mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 19:14:55 +00:00
Merge branch 'TL-list-view' of https://github.com/sleuthkit/autopsy into TL-list-view
This commit is contained in:
commit
c46a91c1c5
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-15 Basis Technology Corp.
|
* Copyright 2013-16 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,10 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.timeline;
|
package org.sleuthkit.autopsy.timeline;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
import javafx.embed.swing.JFXPanel;
|
import javafx.embed.swing.JFXPanel;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.SplitPane;
|
import javafx.scene.control.SplitPane;
|
||||||
@ -34,6 +38,7 @@ import javafx.scene.input.KeyEvent;
|
|||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import org.controlsfx.control.Notifications;
|
||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
||||||
import org.openide.explorer.ExplorerUtils;
|
import org.openide.explorer.ExplorerUtils;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -46,6 +51,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.timeline.actions.Back;
|
import org.sleuthkit.autopsy.timeline.actions.Back;
|
||||||
import org.sleuthkit.autopsy.timeline.actions.Forward;
|
import org.sleuthkit.autopsy.timeline.actions.Forward;
|
||||||
|
import org.sleuthkit.autopsy.timeline.explorernodes.EventNode;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.HistoryToolBar;
|
import org.sleuthkit.autopsy.timeline.ui.HistoryToolBar;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.StatusBar;
|
import org.sleuthkit.autopsy.timeline.ui.StatusBar;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.TimeLineResultView;
|
import org.sleuthkit.autopsy.timeline.ui.TimeLineResultView;
|
||||||
@ -54,9 +60,10 @@ import org.sleuthkit.autopsy.timeline.ui.VisualizationPanel;
|
|||||||
import org.sleuthkit.autopsy.timeline.ui.detailview.tree.EventsTree;
|
import org.sleuthkit.autopsy.timeline.ui.detailview.tree.EventsTree;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.filtering.FilterSetPanel;
|
import org.sleuthkit.autopsy.timeline.ui.filtering.FilterSetPanel;
|
||||||
import org.sleuthkit.autopsy.timeline.zooming.ZoomSettingsPane;
|
import org.sleuthkit.autopsy.timeline.zooming.ZoomSettingsPane;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TopComponent for the timeline feature.
|
* TopComponent for the Timeline feature.
|
||||||
*/
|
*/
|
||||||
@TopComponent.Description(
|
@TopComponent.Description(
|
||||||
preferredID = "TimeLineTopComponent",
|
preferredID = "TimeLineTopComponent",
|
||||||
@ -67,7 +74,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(TimeLineTopComponent.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(TimeLineTopComponent.class.getName());
|
||||||
|
|
||||||
private final DataContentPanel dataContentPanel;
|
private final DataContentPanel contentViewerPanel;
|
||||||
|
|
||||||
private final TimeLineResultView tlResultView;
|
private final TimeLineResultView tlResultView;
|
||||||
|
|
||||||
@ -75,6 +82,36 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
|
|
||||||
private final TimeLineController controller;
|
private final TimeLineController controller;
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"TimelineTopComponent.selectedEventListener.errorMsg=There was a problem getting the content for the selected event."})
|
||||||
|
/**
|
||||||
|
* Listener that drives the ContentViewer when in List ViewMode.
|
||||||
|
*/
|
||||||
|
private final InvalidationListener selectedEventListener = new InvalidationListener() {
|
||||||
|
@Override
|
||||||
|
public void invalidated(Observable observable) {
|
||||||
|
if (controller.getSelectedEventIDs().size() == 1) {
|
||||||
|
try {
|
||||||
|
EventNode eventNode = EventNode.createEventNode(Iterables.getOnlyElement(controller.getSelectedEventIDs()), controller.getEventsModel());
|
||||||
|
SwingUtilities.invokeLater(() -> contentViewerPanel.setNode(eventNode));
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
//Since the case is closed, the user probably doesn't care about this, just log it as a precaution.
|
||||||
|
LOGGER.log(Level.SEVERE, "There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex); // NON-NLS
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to lookup Sleuthkit object backing a SingleEvent.", ex); // NON-NLS
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Notifications.create()
|
||||||
|
.owner(jFXVizPanel.getScene().getWindow())
|
||||||
|
.text(Bundle.TimelineTopComponent_selectedEventListener_errorMsg())
|
||||||
|
.showError();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SwingUtilities.invokeLater(() -> contentViewerPanel.setNode(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public TimeLineTopComponent(TimeLineController controller) {
|
public TimeLineTopComponent(TimeLineController controller) {
|
||||||
initComponents();
|
initComponents();
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
@ -84,9 +121,9 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
setToolTipText(NbBundle.getMessage(TimeLineTopComponent.class, "HINT_TimeLineTopComponent"));
|
setToolTipText(NbBundle.getMessage(TimeLineTopComponent.class, "HINT_TimeLineTopComponent"));
|
||||||
setIcon(WindowManager.getDefault().getMainWindow().getIconImage()); //use the same icon as main application
|
setIcon(WindowManager.getDefault().getMainWindow().getIconImage()); //use the same icon as main application
|
||||||
|
|
||||||
dataContentPanel = DataContentPanel.createInstance();
|
contentViewerPanel = DataContentPanel.createInstance();
|
||||||
this.contentViewerContainerPanel.add(dataContentPanel, BorderLayout.CENTER);
|
this.contentViewerContainerPanel.add(contentViewerPanel, BorderLayout.CENTER);
|
||||||
tlResultView = new TimeLineResultView(controller, dataContentPanel);
|
tlResultView = new TimeLineResultView(controller, contentViewerPanel);
|
||||||
final DataResultPanel dataResultPanel = tlResultView.getDataResultPanel();
|
final DataResultPanel dataResultPanel = tlResultView.getDataResultPanel();
|
||||||
this.resultContainerPanel.add(dataResultPanel, BorderLayout.CENTER);
|
this.resultContainerPanel.add(dataResultPanel, BorderLayout.CENTER);
|
||||||
dataResultPanel.open();
|
dataResultPanel.open();
|
||||||
@ -108,6 +145,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
lowerSplitXPane.add(contentViewerContainerPanel);
|
lowerSplitXPane.add(contentViewerContainerPanel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
controller.getSelectedEventIDs().removeListener(selectedEventListener);
|
||||||
break;
|
break;
|
||||||
case LIST:
|
case LIST:
|
||||||
/*
|
/*
|
||||||
@ -119,6 +157,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
splitYPane.add(contentViewerContainerPanel);
|
splitYPane.add(contentViewerContainerPanel);
|
||||||
dataResultPanel.setNode(null);
|
dataResultPanel.setNode(null);
|
||||||
});
|
});
|
||||||
|
controller.getSelectedEventIDs().addListener(selectedEventListener);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException("Unknown ViewMode: " + controller.getViewMode());
|
throw new UnsupportedOperationException("Unknown ViewMode: " + controller.getViewMode());
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014 Basis Technology Corp.
|
* Copyright 2014-16 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -31,21 +31,25 @@ import org.openide.nodes.Children;
|
|||||||
import org.openide.nodes.PropertySupport;
|
import org.openide.nodes.PropertySupport;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
|
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
|
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * Explorer Node for {@link SingleEvent}s.
|
* * Explorer Node for SingleEvents.
|
||||||
*/
|
*/
|
||||||
class EventNode extends DisplayableItemNode {
|
public class EventNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(EventNode.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(EventNode.class.getName());
|
||||||
|
|
||||||
@ -155,10 +159,38 @@ class EventNode extends DisplayableItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(String t) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
final public void setValue(String t) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||||
String oldValue = getValue();
|
String oldValue = getValue();
|
||||||
value = t;
|
value = t;
|
||||||
firePropertyChange("time", oldValue, t); // NON-NLS
|
firePropertyChange("time", oldValue, t); // NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method to create an EventNode from the event ID and the events
|
||||||
|
* model.
|
||||||
|
*
|
||||||
|
* @param eventID The ID of the event this node is for.
|
||||||
|
* @param eventsModel The model that provides access to the events DB.
|
||||||
|
*
|
||||||
|
* @return An EventNode with the file (and artifact) backing this event in
|
||||||
|
* its lookup.
|
||||||
|
*/
|
||||||
|
public static EventNode createEventNode(final Long eventID, FilteredEventsModel eventsModel) throws TskCoreException, IllegalStateException {
|
||||||
|
/*
|
||||||
|
* Look up the event by id and creata an EventNode with the appropriate
|
||||||
|
* data in the lookup.
|
||||||
|
*/
|
||||||
|
final SingleEvent eventById = eventsModel.getEventById(eventID);
|
||||||
|
|
||||||
|
SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||||
|
AbstractFile file = sleuthkitCase.getAbstractFileById(eventById.getFileID());
|
||||||
|
|
||||||
|
if (eventById.getArtifactID().isPresent()) {
|
||||||
|
BlackboardArtifact blackboardArtifact = sleuthkitCase.getBlackboardArtifact(eventById.getArtifactID().get());
|
||||||
|
return new EventNode(eventById, file, blackboardArtifact);
|
||||||
|
} else {
|
||||||
|
return new EventNode(eventById, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,15 +27,10 @@ import org.openide.nodes.Children;
|
|||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,29 +127,19 @@ public class EventRootNode extends DisplayableItemNode {
|
|||||||
*/
|
*/
|
||||||
return new TooManyNode(eventIDs.size());
|
return new TooManyNode(eventIDs.size());
|
||||||
} else {
|
} else {
|
||||||
/*
|
|
||||||
* look up the event by id and creata an EventNode with the
|
|
||||||
* appropriate data in the lookup.
|
|
||||||
*/
|
|
||||||
final SingleEvent eventById = filteredEvents.getEventById(eventID);
|
|
||||||
try {
|
try {
|
||||||
SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
return EventNode.createEventNode(eventID, filteredEvents);
|
||||||
AbstractFile file = sleuthkitCase.getAbstractFileById(eventById.getFileID());
|
} catch (IllegalStateException ex) {
|
||||||
if (file != null) {
|
//Since the case is closed, the user probably doesn't care about this, just log it as a precaution.
|
||||||
if (eventById.getArtifactID().isPresent()) {
|
LOGGER.log(Level.SEVERE, "There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex); // NON-NLS
|
||||||
BlackboardArtifact blackboardArtifact = sleuthkitCase.getBlackboardArtifact(eventById.getArtifactID().get());
|
return null;
|
||||||
return new EventNode(eventById, file, blackboardArtifact);
|
} catch (TskCoreException ex) {
|
||||||
} else {
|
/*
|
||||||
return new EventNode(eventById, file);
|
* Just log it: There might be lots of these errors, and we
|
||||||
}
|
* don't want to flood the user with notifications. It will
|
||||||
} else {
|
* be obvious the UI is broken anyways
|
||||||
//This should never happen in normal operations
|
*/
|
||||||
LOGGER.log(Level.WARNING, "Failed to lookup sleuthkit object backing TimeLineEvent."); // NON-NLS
|
LOGGER.log(Level.SEVERE, "Failed to lookup Sleuthkit object backing a SingleEvent.", ex); // NON-NLS
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (IllegalStateException | TskCoreException ex) {
|
|
||||||
//if some how the case was closed or ther is another unspecified exception, just bail out with a warning.
|
|
||||||
LOGGER.log(Level.WARNING, "Failed to lookup sleuthkit object backing TimeLineEvent.", ex); // NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,13 +62,9 @@ public class TimeLineResultView {
|
|||||||
dataResultPanel = DataResultPanel.createInstanceUninitialized("", "", Node.EMPTY, 0, dataContent);
|
dataResultPanel = DataResultPanel.createInstanceUninitialized("", "", Node.EMPTY, 0, dataContent);
|
||||||
|
|
||||||
//set up listeners on relevant properties
|
//set up listeners on relevant properties
|
||||||
TimeLineController.getTimeZone().addListener((Observable observable) -> {
|
TimeLineController.getTimeZone().addListener(timeZone -> dataResultPanel.setPath(getSummaryString()));
|
||||||
dataResultPanel.setPath(getSummaryString());
|
|
||||||
});
|
|
||||||
|
|
||||||
controller.getSelectedEventIDs().addListener((Observable o) -> {
|
controller.getSelectedEventIDs().addListener((Observable selectedIDs) -> refresh());
|
||||||
refresh();
|
|
||||||
});
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import java.util.Collection;
|
|||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TableCell;
|
import javafx.scene.control.TableCell;
|
||||||
@ -128,6 +129,15 @@ class ListChart extends BorderPane {
|
|||||||
table.getItems().setAll(eventIDs);
|
table.getItems().setAll(eventIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the List of IDs of events that are selected in this list.
|
||||||
|
*
|
||||||
|
* @return The List of IDs of events that are selected in this list.
|
||||||
|
*/
|
||||||
|
ObservableList<Long> getSelectedEventIDs() {
|
||||||
|
return table.getSelectionModel().getSelectedItems();
|
||||||
|
}
|
||||||
|
|
||||||
private class ImageCell extends EventTableCell {
|
private class ImageCell extends EventTableCell {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.timeline.ui.listvew;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.Observable;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import org.joda.time.Interval;
|
import org.joda.time.Interval;
|
||||||
@ -58,6 +59,11 @@ public class ListViewPane extends AbstractTimeLineView {
|
|||||||
//initialize chart;
|
//initialize chart;
|
||||||
setCenter(listChart);
|
setCenter(listChart);
|
||||||
setSettingsNodes(new ListViewPane.ListViewSettingsPane().getChildrenUnmodifiable());
|
setSettingsNodes(new ListViewPane.ListViewSettingsPane().getChildrenUnmodifiable());
|
||||||
|
|
||||||
|
//keep controller's list of selected event IDs in sync with this list's
|
||||||
|
listChart.getSelectedEventIDs().addListener((Observable selectedIDs) -> {
|
||||||
|
controller.selectEventIDs(listChart.getSelectedEventIDs());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user