Resolve merge conflict for com.sun.javafx.Utils

This commit is contained in:
Richard Cordovano 2015-10-22 10:09:35 -04:00
commit ee396f3271
30 changed files with 413 additions and 521 deletions

View File

@ -24,10 +24,7 @@ TimelinePanel.jButton7.text=3d
TimelinePanel.jButton2.text=1m TimelinePanel.jButton2.text=1m
TimelinePanel.jButton3.text=3m TimelinePanel.jButton3.text=3m
TimelinePanel.jButton4.text=2w TimelinePanel.jButton4.text=2w
TimeLineTopComponent.eventsTab.name=Events
TimeLineTopComponent.filterTab.name=Filters
OpenTimelineAction.title=Timeline OpenTimelineAction.title=Timeline
OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources. OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources.
TimeLineTopComponent.timeZonePanel.text=Display Times In\:
ProgressWindow.progressHeader.text=\ ProgressWindow.progressHeader.text=\

View File

@ -316,9 +316,11 @@ public class TimeLineController {
LOGGER.log(Level.INFO, "Beginning generation of timeline"); // NON-NLS LOGGER.log(Level.INFO, "Beginning generation of timeline"); // NON-NLS
try { try {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
synchronized (TimeLineController.this) {
if (isWindowOpen()) { if (isWindowOpen()) {
mainFrame.close(); mainFrame.close();
} }
}
}); });
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
final long lastObjId = sleuthkitCase.getLastObjectId(); final long lastObjId = sleuthkitCase.getLastObjectId();
@ -362,9 +364,11 @@ public class TimeLineController {
void rebuildTagsTable() { void rebuildTagsTable() {
LOGGER.log(Level.INFO, "starting to rebuild tags table"); // NON-NLS LOGGER.log(Level.INFO, "starting to rebuild tags table"); // NON-NLS
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
synchronized (TimeLineController.this) {
if (isWindowOpen()) { if (isWindowOpen()) {
mainFrame.close(); mainFrame.close();
} }
}
}); });
synchronized (eventsRepository) { synchronized (eventsRepository) {
eventsRepository.rebuildTags(() -> { eventsRepository.rebuildTags(() -> {
@ -388,16 +392,19 @@ public class TimeLineController {
IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener); IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener);
IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener); IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener);
Case.removePropertyChangeListener(caseListener); Case.removePropertyChangeListener(caseListener);
SwingUtilities.invokeLater(() -> {
synchronized (TimeLineController.this) {
mainFrame.close(); mainFrame.close();
mainFrame.setVisible(false);
mainFrame = null; mainFrame = null;
} }
});
}
} }
/** /**
* show the timeline window and prompt for rebuilding database if necessary. * show the timeline window and prompt for rebuilding database if necessary.
*/ */
synchronized void openTimeLine() { void openTimeLine() {
// listen for case changes (specifically images being added, and case changes). // listen for case changes (specifically images being added, and case changes).
if (Case.isCaseOpen() && !listeningToAutopsy) { if (Case.isCaseOpen() && !listeningToAutopsy) {
IngestManager.getInstance().addIngestModuleEventListener(ingestModuleListener); IngestManager.getInstance().addIngestModuleEventListener(ingestModuleListener);
@ -539,20 +546,20 @@ public class TimeLineController {
/** /**
* private method to build gui if necessary and make it visible. * private method to build gui if necessary and make it visible.
*/ */
synchronized private void showWindow() { private void showWindow() {
SwingUtilities.invokeLater(() -> {
synchronized (TimeLineController.this) {
if (mainFrame == null) { if (mainFrame == null) {
LOGGER.log(Level.WARNING, "Tried to show timeline with invalid window. Rebuilding GUI."); // NON-NLS LOGGER.log(Level.WARNING, "Tried to show timeline with invalid window. Rebuilding GUI."); // NON-NLS
mainFrame = (TimeLineTopComponent) WindowManager.getDefault().findTopComponent( mainFrame = (TimeLineTopComponent) WindowManager.getDefault().findTopComponent(
NbBundle.getMessage(TimeLineController.class, "CTL_TimeLineTopComponentAction")); NbBundle.getMessage(TimeLineController.class, "CTL_TimeLineTopComponentAction"));
if (mainFrame == null) { if (mainFrame == null) {
mainFrame = new TimeLineTopComponent(); mainFrame = new TimeLineTopComponent(this);
} }
mainFrame.setController(this);
} }
SwingUtilities.invokeLater(() -> {
mainFrame.open(); mainFrame.open();
mainFrame.setVisible(true);
mainFrame.toFront(); mainFrame.toFront();
}
}); });
} }

View File

@ -23,7 +23,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.event.ActionEvent; import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.SplitPane; import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
@ -34,7 +34,6 @@ import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent; 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 org.netbeans.api.settings.ConvertAsProperties;
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;
@ -51,135 +50,103 @@ import org.sleuthkit.autopsy.timeline.ui.StatusBar;
import org.sleuthkit.autopsy.timeline.ui.TimeLineResultView; import org.sleuthkit.autopsy.timeline.ui.TimeLineResultView;
import org.sleuthkit.autopsy.timeline.ui.TimeZonePanel; import org.sleuthkit.autopsy.timeline.ui.TimeZonePanel;
import org.sleuthkit.autopsy.timeline.ui.VisualizationPanel; import org.sleuthkit.autopsy.timeline.ui.VisualizationPanel;
import org.sleuthkit.autopsy.timeline.ui.detailview.tree.NavPanel; 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;
/** /**
* TopComponent for the timeline feature. * TopComponent for the timeline feature.
*/ */
@ConvertAsProperties(
dtd = "-//org.sleuthkit.autopsy.timeline//TimeLine//EN",
autostore = false)
@TopComponent.Description( @TopComponent.Description(
preferredID = "TimeLineTopComponent", preferredID = "TimeLineTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", //iconBase="SET/PATH/TO/ICON/HERE",
persistenceType = TopComponent.PERSISTENCE_NEVER) persistenceType = TopComponent.PERSISTENCE_NEVER)
@TopComponent.Registration(mode = "timeline", openAtStartup = false) @TopComponent.Registration(mode = "timeline", openAtStartup = false)
public final class TimeLineTopComponent extends TopComponent implements ExplorerManager.Provider, TimeLineUI { public final class TimeLineTopComponent extends TopComponent implements ExplorerManager.Provider {
private static final Logger LOGGER = Logger.getLogger(TimeLineTopComponent.class.getName()); private static final Logger LOGGER = Logger.getLogger(TimeLineTopComponent.class.getName());
private DataContentPanel dataContentPanel; private final DataContentPanel dataContentPanel;
private TimeLineResultView tlrv; private final TimeLineResultView tlrv;
private final ExplorerManager em = new ExplorerManager(); private final ExplorerManager em = new ExplorerManager();
private TimeLineController controller; private final TimeLineController controller;
////jfx componenets that make up the interface public TimeLineTopComponent(TimeLineController controller) {
private final FilterSetPanel filtersPanel = new FilterSetPanel();
private final Tab eventsTab = new Tab(
NbBundle.getMessage(TimeLineTopComponent.class, "TimeLineTopComponent.eventsTab.name"));
private final Tab filterTab = new Tab(
NbBundle.getMessage(TimeLineTopComponent.class, "TimeLineTopComponent.filterTab.name"));
private final VBox leftVBox = new VBox(5);
private final NavPanel navPanel = new NavPanel();
private final StatusBar statusBar = new StatusBar();
private final TabPane tabPane = new TabPane();
private final ZoomSettingsPane zoomSettingsPane = new ZoomSettingsPane();
private final VisualizationPanel visualizationPanel = new VisualizationPanel(navPanel);
private final SplitPane splitPane = new SplitPane();
private final TimeZonePanel timeZonePanel = new TimeZonePanel();
public TimeLineTopComponent() {
initComponents(); initComponents();
this.controller = controller;
associateLookup(ExplorerUtils.createLookup(em, getActionMap())); associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
setName(NbBundle.getMessage(TimeLineTopComponent.class, "CTL_TimeLineTopComponent")); setName(NbBundle.getMessage(TimeLineTopComponent.class, "CTL_TimeLineTopComponent"));
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
timeZonePanel.setText(NbBundle.getMessage(this.getClass(), "TimeLineTopComponent.timeZonePanel.text"));
customizeComponents();
}
synchronized private void customizeComponents() {
dataContentPanel = DataContentPanel.createInstance(); dataContentPanel = DataContentPanel.createInstance();
this.contentViewerContainerPanel.add(dataContentPanel, BorderLayout.CENTER); this.contentViewerContainerPanel.add(dataContentPanel, BorderLayout.CENTER);
tlrv = new TimeLineResultView(dataContentPanel); tlrv = new TimeLineResultView(controller, dataContentPanel);
DataResultPanel dataResultPanel = tlrv.getDataResultPanel(); DataResultPanel dataResultPanel = tlrv.getDataResultPanel();
this.resultContainerPanel.add(dataResultPanel, BorderLayout.CENTER); this.resultContainerPanel.add(dataResultPanel, BorderLayout.CENTER);
dataResultPanel.open(); dataResultPanel.open();
customizeFXComponents();
}
@NbBundle.Messages({"TimeLineTopComponent.eventsTab.name=Events",
"TimeLineTopComponent.filterTab.name=Filters"})
void customizeFXComponents() {
Platform.runLater(() -> { Platform.runLater(() -> {
//assemble ui componenets together
jFXstatusPanel.setScene(new Scene(statusBar));
jFXVizPanel.setScene(new Scene(splitPane));
splitPane.setDividerPositions(0);
//create and wire up jfx componenets that make up the interface
final Tab filterTab = new Tab(Bundle.TimeLineTopComponent_filterTab_name(), new FilterSetPanel(controller));
filterTab.setClosable(false); filterTab.setClosable(false);
filterTab.setContent(filtersPanel);
filterTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/funnel.png")); // NON-NLS filterTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/funnel.png")); // NON-NLS
eventsTab.setClosable(false); final EventsTree eventsTree = new EventsTree(controller);
eventsTab.setContent(navPanel); final VisualizationPanel visualizationPanel = new VisualizationPanel(controller, eventsTree);
eventsTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/timeline_marker.png")); // NON-NLS final Tab eventsTreeTab = new Tab(Bundle.TimeLineTopComponent_eventsTab_name(), eventsTree);
eventsTreeTab.setClosable(false);
eventsTreeTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/timeline_marker.png")); // NON-NLS
eventsTreeTab.disableProperty().bind(controller.viewModeProperty().isEqualTo(VisualizationMode.COUNTS));
tabPane.getTabs().addAll(filterTab, eventsTab); final TabPane leftTabPane = new TabPane(filterTab, eventsTreeTab);
VBox.setVgrow(tabPane, Priority.ALWAYS); VBox.setVgrow(leftTabPane, Priority.ALWAYS);
VBox.setVgrow(timeZonePanel, Priority.SOMETIMES);
leftVBox.getChildren().addAll(timeZonePanel, zoomSettingsPane, tabPane);
SplitPane.setResizableWithParent(leftVBox, Boolean.FALSE);
splitPane.getItems().addAll(leftVBox, visualizationPanel);
});
}
@Override
public synchronized void setController(TimeLineController controller) {
this.controller = controller;
tlrv.setController(controller);
Platform.runLater(() -> {
jFXVizPanel.getScene().addEventFilter(KeyEvent.KEY_PRESSED,
(KeyEvent event) -> {
if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(event)) {
new Back(controller).handle(new ActionEvent());
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE).match(event)) {
new Back(controller).handle(new ActionEvent());
} else if (new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(event)) {
new Forward(controller).handle(new ActionEvent());
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(event)) {
new Forward(controller).handle(new ActionEvent());
}
});
controller.viewModeProperty().addListener((Observable observable) -> { controller.viewModeProperty().addListener((Observable observable) -> {
if (controller.viewModeProperty().get().equals(VisualizationMode.COUNTS)) { if (controller.viewModeProperty().get().equals(VisualizationMode.COUNTS)) {
tabPane.getSelectionModel().select(filterTab); //if view mode is counts, make sure events tabd is not active
leftTabPane.getSelectionModel().select(filterTab);
} }
}); });
eventsTab.disableProperty().bind(controller.viewModeProperty().isEqualTo(VisualizationMode.COUNTS));
visualizationPanel.setController(controller); final TimeZonePanel timeZonePanel = new TimeZonePanel();
navPanel.setController(controller); VBox.setVgrow(timeZonePanel, Priority.SOMETIMES);
filtersPanel.setController(controller);
zoomSettingsPane.setController(controller); final ZoomSettingsPane zoomSettingsPane = new ZoomSettingsPane(controller);
statusBar.setController(controller);
final VBox leftVBox = new VBox(5, timeZonePanel, zoomSettingsPane, leftTabPane);
SplitPane.setResizableWithParent(leftVBox, Boolean.FALSE);
final SplitPane mainSplitPane = new SplitPane(leftVBox, visualizationPanel);
mainSplitPane.setDividerPositions(0);
final Scene scene = new Scene(mainSplitPane);
scene.addEventFilter(KeyEvent.KEY_PRESSED,
(KeyEvent event) -> {
if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(event)) {
new Back(controller).handle(null);
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE).match(event)) {
new Back(controller).handle(null);
} else if (new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(event)) {
new Forward(controller).handle(null);
} else if (new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(event)) {
new Forward(controller).handle(null);
}
});
//add ui componenets to JFXPanels
jFXVizPanel.setScene(scene);
jFXstatusPanel.setScene(new Scene(new StatusBar(controller)));
}); });
} }
@ -196,9 +163,9 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
jFXstatusPanel = new javafx.embed.swing.JFXPanel(); jFXstatusPanel = new JFXPanel();
splitYPane = new javax.swing.JSplitPane(); splitYPane = new javax.swing.JSplitPane();
jFXVizPanel = new javafx.embed.swing.JFXPanel(); jFXVizPanel = new JFXPanel();
lowerSplitXPane = new javax.swing.JSplitPane(); lowerSplitXPane = new javax.swing.JSplitPane();
resultContainerPanel = new javax.swing.JPanel(); resultContainerPanel = new javax.swing.JPanel();
contentViewerContainerPanel = new javax.swing.JPanel(); contentViewerContainerPanel = new javax.swing.JPanel();

View File

@ -1,27 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.timeline;
/**
*
*/
public interface TimeLineUI {
void setController(TimeLineController controller);
}

View File

@ -1,36 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.timeline;
/**
* Interface to be implemented by views of the data.
*
* Most implementations should install the relevant listeners in their
* {@link #setController} and {@link #setModel} methods
*/
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
public interface TimeLineView extends TimeLineUI {
@Override
void setController(TimeLineController controller);
void setModel(final FilteredEventsModel filteredEvents);
}

View File

@ -1,4 +1,4 @@
Back.actions.name.text=Back Back.actions.name.text=Back
DefaultFilters.action.name.text=apply default filters DefaultFilters.action.name.text=apply default filters
Forward.action.name.text=Forward Forward.action.name.text=Forward
ZoomOut.action.name.text=apply default filters

View File

@ -53,7 +53,8 @@ public class SaveSnapshotAsReport extends Action {
private static final Logger LOGGER = Logger.getLogger(SaveSnapshotAsReport.class.getName()); private static final Logger LOGGER = Logger.getLogger(SaveSnapshotAsReport.class.getName());
@NbBundle.Messages({"SaveSnapshot.action.name.text=save snapshot", "SaveSnapshot.fileChoose.title.text=Save snapshot to"}) @NbBundle.Messages({"SaveSnapshot.action.name.text=save snapshot",
"SaveSnapshot.fileChoose.title.text=Save snapshot to"})
public SaveSnapshotAsReport(TimeLineController controller, WritableImage snapshot) { public SaveSnapshotAsReport(TimeLineController controller, WritableImage snapshot) {
super(Bundle.SaveSnapshot_action_name_text()); super(Bundle.SaveSnapshot_action_name_text());
setEventHandler(new Consumer<ActionEvent>() { setEventHandler(new Consumer<ActionEvent>() {

View File

@ -0,0 +1,44 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.timeline.actions;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.controlsfx.control.action.Action;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController;
/**
*
*/
public class ZoomIn extends Action {
private static final Image MAGNIFIER_IN = new Image("/org/sleuthkit/autopsy/timeline/images/magnifier-zoom-in-green.png"); //NOI18N
@NbBundle.Messages({"ZoomIn.longText=Zoom in to view half as much time.",
"ZoomIn.action.text=Zoom in"})
public ZoomIn(TimeLineController controller) {
super(Bundle.ZoomIn_action_text());
setLongText(Bundle.ZoomIn_longText());
setGraphic(new ImageView(MAGNIFIER_IN));
setEventHandler(actionEvent -> {
controller.pushZoomInTime();
});
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2014 Basis Technology Corp. * Copyright 2015 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");
@ -19,7 +19,8 @@
package org.sleuthkit.autopsy.timeline.actions; package org.sleuthkit.autopsy.timeline.actions;
import javafx.beans.binding.BooleanBinding; import javafx.beans.binding.BooleanBinding;
import javafx.event.ActionEvent; import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
@ -30,15 +31,22 @@ import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
*/ */
public class ZoomOut extends Action { public class ZoomOut extends Action {
private final TimeLineController controller; private static final Image MAGNIFIER_OUT = new Image("/org/sleuthkit/autopsy/timeline/images/magnifier-zoom-out-red.png"); //NOI18N
private final FilteredEventsModel eventsModel; @NbBundle.Messages({"ZoomOut.longText=Zoom out to view 50% more time.",
"ZoomOut.action.text=Zoom out"})
public ZoomOut(TimeLineController controller) {
super(Bundle.ZoomOut_action_text());
setLongText(Bundle.ZoomOut_longText());
setGraphic(new ImageView(MAGNIFIER_OUT));
setEventHandler(actionEvent -> {
controller.pushZoomOutTime();
});
public ZoomOut(final TimeLineController controller) { //disable action when the current time range already encompases the entire case.
super(NbBundle.getMessage(ZoomOut.class, "ZoomOut.action.name.text"));
this.controller = controller;
eventsModel = controller.getEventsModel();
disabledProperty().bind(new BooleanBinding() { disabledProperty().bind(new BooleanBinding() {
private final FilteredEventsModel eventsModel = controller.getEventsModel();
{ {
bind(eventsModel.zoomParametersProperty()); bind(eventsModel.zoomParametersProperty());
} }
@ -48,8 +56,5 @@ public class ZoomOut extends Action {
return eventsModel.zoomParametersProperty().getValue().getTimeRange().contains(eventsModel.getSpanningInterval()); return eventsModel.zoomParametersProperty().getValue().getTimeRange().contains(eventsModel.getSpanningInterval());
} }
}); });
setEventHandler((ActionEvent t) -> {
controller.zoomOutToActivity();
});
} }
} }

View File

@ -0,0 +1,61 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014-15 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.timeline.actions;
import javafx.beans.binding.BooleanBinding;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.controlsfx.control.action.Action;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
/**
*
*/
public class ZoomToEvents extends Action {
private static final Image MAGNIFIER_OUT = new Image("/org/sleuthkit/autopsy/timeline/images/magnifier-zoom-out-red.png", 16, 16, true, true); //NOI18N
@NbBundle.Messages({"ZoomToEvents.action.text=Zoom to events",
"ZoomToEvents.longText=Zoom out to show the nearest events."})
public ZoomToEvents(final TimeLineController controller) {
super(Bundle.ZoomToEvents_action_text());
setLongText(Bundle.ZoomToEvents_longText());
setGraphic(new ImageView(MAGNIFIER_OUT));
setEventHandler(actionEvent -> {
controller.zoomOutToActivity();
});
//disable action when the current time range already encompases the entire case.
disabledProperty().bind(new BooleanBinding() {
private final FilteredEventsModel eventsModel = controller.getEventsModel();
{
bind(eventsModel.zoomParametersProperty());
}
@Override
protected boolean computeValue() {
//TODO: do a db query to see if using this action will actually result in viewable events
return eventsModel.zoomParametersProperty().getValue().getTimeRange().contains(eventsModel.getSpanningInterval());
}
});
}
}

View File

@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent.DeletedContentTagInfo; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent.DeletedContentTagInfo;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.RootEventType; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.RootEventType;
import org.sleuthkit.autopsy.timeline.db.EventsRepository; import org.sleuthkit.autopsy.timeline.db.EventsRepository;

View File

@ -51,13 +51,11 @@ import javafx.scene.text.Font;
import javafx.scene.text.FontWeight; import javafx.scene.text.FontWeight;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment; import javafx.scene.text.TextAlignment;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
@ -75,7 +73,7 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
* {@link XYChart} doing the rendering. Is this a good idea? -jm TODO: pull up * {@link XYChart} doing the rendering. Is this a good idea? -jm TODO: pull up
* common history context menu items out of derived classes? -jm * common history context menu items out of derived classes? -jm
*/ */
public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y> & TimeLineChart<X>> extends BorderPane implements TimeLineView { public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y> & TimeLineChart<X>> extends BorderPane {
@NbBundle.Messages("AbstractVisualization.Drag_Tooltip.text=Drag the mouse to select a time interval to zoom into.") @NbBundle.Messages("AbstractVisualization.Drag_Tooltip.text=Drag the mouse to select a time interval to zoom into.")
private static final Tooltip DRAG_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Drag_Tooltip_text()); private static final Tooltip DRAG_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Drag_Tooltip_text());
@ -102,11 +100,15 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
*/ */
private Task<Boolean> updateTask; private Task<Boolean> updateTask;
protected TimeLineController controller; final protected TimeLineController controller;
protected FilteredEventsModel filteredEvents; final protected FilteredEventsModel filteredEvents;
protected ReadOnlyListWrapper<N> selectedNodes = new ReadOnlyListWrapper<>(FXCollections.observableArrayList()); final protected ReadOnlyListWrapper<N> selectedNodes = new ReadOnlyListWrapper<>(FXCollections.observableArrayList());
private InvalidationListener invalidationListener = (Observable observable) -> {
update();
};
public ReadOnlyListProperty<N> getSelectedNodes() { public ReadOnlyListProperty<N> getSelectedNodes() {
return selectedNodes.getReadOnlyProperty(); return selectedNodes.getReadOnlyProperty();
@ -186,7 +188,7 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
* Primarily this invokes the background {@link Task} returned by * Primarily this invokes the background {@link Task} returned by
* {@link #getUpdateTask()} which derived classes must implement. * {@link #getUpdateTask()} which derived classes must implement.
*/ */
synchronized public void update() { final synchronized public void update() {
if (updateTask != null) { if (updateTask != null) {
updateTask.cancel(true); updateTask.cancel(true);
updateTask = null; updateTask = null;
@ -212,7 +214,7 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
controller.monitorTask(updateTask); controller.monitorTask(updateTask);
} }
synchronized public void dispose() { final synchronized public void dispose() {
if (updateTask != null) { if (updateTask != null) {
updateTask.cancel(true); updateTask.cancel(true);
} }
@ -220,7 +222,12 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
invalidationListener = null; invalidationListener = null;
} }
protected AbstractVisualizationPane(Pane partPane, Pane contextPane, Region spacer) { protected AbstractVisualizationPane(TimeLineController controller, Pane partPane, Pane contextPane, Region spacer) {
this.controller = controller;
this.filteredEvents = controller.getEventsModel();
this.filteredEvents.registerForEvents(this);
this.filteredEvents.zoomParametersProperty().addListener(invalidationListener);
this.leafPane = partPane; this.leafPane = partPane;
this.branchPane = contextPane; this.branchPane = contextPane;
this.spacer = spacer; this.spacer = spacer;
@ -235,17 +242,8 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
}); });
} }
}); });
}
@Override TimeLineController.getTimeZone().addListener(invalidationListener);
synchronized public void setController(TimeLineController controller) {
this.controller = controller;
chart.setController(controller);
setModel(controller.getEventsModel());
TimeLineController.getTimeZone().addListener((Observable observable) -> {
update();
});
//show tooltip text in status bar //show tooltip text in status bar
hoverProperty().addListener((observable, oldActivated, newActivated) -> { hoverProperty().addListener((observable, oldActivated, newActivated) -> {
@ -255,20 +253,6 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
controller.setStatus(""); controller.setStatus("");
} }
}); });
}
@Override
synchronized public void setModel(@Nonnull FilteredEventsModel filteredEvents) {
if (this.filteredEvents != null && this.filteredEvents != filteredEvents) {
this.filteredEvents.unRegisterForEvents(this);
this.filteredEvents.zoomParametersProperty().removeListener(invalidationListener);
}
if (this.filteredEvents != filteredEvents) {
filteredEvents.registerForEvents(this);
filteredEvents.zoomParametersProperty().addListener(invalidationListener);
}
this.filteredEvents = filteredEvents;
update(); update();
} }
@ -278,10 +262,6 @@ public abstract class AbstractVisualizationPane<X, Y, N, C extends XYChart<X, Y>
update(); update();
} }
protected InvalidationListener invalidationListener = (Observable observable) -> {
update();
};
/** /**
* iterate through the list of tick-marks building a two level structure of * iterate through the list of tick-marks building a two level structure of
* replacement tick marl labels. (Visually) upper level has most * replacement tick marl labels. (Visually) upper level has most

View File

@ -28,13 +28,12 @@ import javafx.scene.layout.Region;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineUI;
/** /**
* simple status bar that only shows one possible message determined by * simple status bar that only shows one possible message determined by
* {@link TimeLineController#newEventsFlag} * {@link TimeLineController#newEventsFlag}
*/ */
public class StatusBar extends ToolBar implements TimeLineUI { public class StatusBar extends ToolBar {
private TimeLineController controller; private TimeLineController controller;
@ -56,7 +55,8 @@ public class StatusBar extends ToolBar implements TimeLineUI {
@FXML @FXML
private Label messageLabel; private Label messageLabel;
public StatusBar() { public StatusBar(TimeLineController controller) {
this.controller = controller;
FXMLConstructor.construct(this, "StatusBar.fxml"); // NON-NLS FXMLConstructor.construct(this, "StatusBar.fxml"); // NON-NLS
} }
@ -73,11 +73,7 @@ public class StatusBar extends ToolBar implements TimeLineUI {
taskLabel.setText(NbBundle.getMessage(this.getClass(), "StatusBar.taskLabel.text")); taskLabel.setText(NbBundle.getMessage(this.getClass(), "StatusBar.taskLabel.text"));
taskLabel.setVisible(false); taskLabel.setVisible(false);
HBox.setHgrow(spacer, Priority.ALWAYS); HBox.setHgrow(spacer, Priority.ALWAYS);
}
@Override
public void setController(TimeLineController controller) {
this.controller = controller;
refreshLabel.visibleProperty().bind(this.controller.getNewEventsFlag()); refreshLabel.visibleProperty().bind(this.controller.getNewEventsFlag());
refreshLabel.managedProperty().bind(this.controller.getNewEventsFlag()); refreshLabel.managedProperty().bind(this.controller.getNewEventsFlag());
taskLabel.textProperty().bind(this.controller.getTaskTitle()); taskLabel.textProperty().bind(this.controller.getTaskTitle());

View File

@ -29,7 +29,6 @@ import javafx.scene.input.MouseEvent;
import org.controlsfx.control.action.ActionGroup; import org.controlsfx.control.action.ActionGroup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
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;
@ -38,8 +37,9 @@ import org.sleuthkit.autopsy.timeline.actions.Forward;
* *
* @param <X> the type of values along the horizontal axis * @param <X> the type of values along the horizontal axis
*/ */
public interface TimeLineChart<X> extends TimeLineView { public interface TimeLineChart<X> {
// void setController(TimeLineController controller);
IntervalSelector<? extends X> getIntervalSelector(); IntervalSelector<? extends X> getIntervalSelector();
void setIntervalSelector(IntervalSelector<? extends X> newIntervalSelector); void setIntervalSelector(IntervalSelector<? extends X> newIntervalSelector);
@ -139,6 +139,17 @@ public interface TimeLineChart<X> extends TimeLineView {
} }
} }
/**
* enum to represent whether the drag is a left/right-edge modification or a
* horizontal slide triggered by dragging the center
*/
enum DragPosition {
LEFT,
CENTER,
RIGHT
}
@NbBundle.Messages({"TimeLineChart.zoomHistoryActionGroup.name=Zoom History"}) @NbBundle.Messages({"TimeLineChart.zoomHistoryActionGroup.name=Zoom History"})
static ActionGroup newZoomHistoyActionGroup(TimeLineController controller) { static ActionGroup newZoomHistoyActionGroup(TimeLineController controller) {
return new ActionGroup(Bundle.TimeLineChart_zoomHistoryActionGroup_name(), return new ActionGroup(Bundle.TimeLineChart_zoomHistoryActionGroup_name(),

View File

@ -25,12 +25,11 @@ import javax.swing.SwingUtilities;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.explorernodes.EventRootNode;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel; import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.explorernodes.EventRootNode;
/** /**
* Since it was too hard to derive from {@link DataResultPanel}, this class * Since it was too hard to derive from {@link DataResultPanel}, this class
@ -39,16 +38,16 @@ import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
* {@link DataResultPanel}. That is, this class acts as a sort of bridge/adapter * {@link DataResultPanel}. That is, this class acts as a sort of bridge/adapter
* between a FilteredEventsModel instance and a DataResultPanel instance. * between a FilteredEventsModel instance and a DataResultPanel instance.
*/ */
public class TimeLineResultView implements TimeLineView { public class TimeLineResultView {
/** /**
* the {@link DataResultPanel} that is the real view proxied by this class * the {@link DataResultPanel} that is the real view proxied by this class
*/ */
private final DataResultPanel dataResultPanel; private final DataResultPanel dataResultPanel;
private TimeLineController controller; private final TimeLineController controller;
private FilteredEventsModel filteredEvents; private final FilteredEventsModel filteredEvents;
private Set<Long> selectedEventIDs = new HashSet<>(); private Set<Long> selectedEventIDs = new HashSet<>();
@ -56,19 +55,11 @@ public class TimeLineResultView implements TimeLineView {
return dataResultPanel; return dataResultPanel;
} }
public TimeLineResultView(DataContent dataContent) { public TimeLineResultView(TimeLineController controller, DataContent dataContent) {
dataResultPanel = DataResultPanel.createInstanceUninitialized("", "", Node.EMPTY, 0, dataContent);
}
/**
* Set the Controller for this class. Also sets the model provided by the
* controller as the model for this view.
*
* @param controller
*/
@Override
public void setController(TimeLineController controller) {
this.controller = controller; this.controller = controller;
this.filteredEvents = controller.getEventsModel();
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((Observable observable) -> {
@ -78,18 +69,7 @@ public class TimeLineResultView implements TimeLineView {
controller.getSelectedEventIDs().addListener((Observable o) -> { controller.getSelectedEventIDs().addListener((Observable o) -> {
refresh(); refresh();
}); });
refresh();
setModel(controller.getEventsModel());
}
/**
* Set the Model for this View
*
* @param filteredEvents
*/
@Override
synchronized public void setModel(final FilteredEventsModel filteredEvents) {
this.filteredEvents = filteredEvents;
} }
/** /**

View File

@ -23,7 +23,10 @@ import java.util.Date;
import java.util.TimeZone; import java.util.TimeZone;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.*; import javafx.scene.control.RadioButton;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
@ -50,8 +53,9 @@ public class TimeZonePanel extends TitledPane {
} }
@FXML @FXML
@NbBundle.Messages({"TimeZonePanel.title=Display Times In:"})
public void initialize() { public void initialize() {
setText(Bundle.TimeZonePanel_title());
// localRadio.setText("Local Time Zone: " + getTimeZoneString(TimeZone.getDefault())); // localRadio.setText("Local Time Zone: " + getTimeZoneString(TimeZone.getDefault()));
localRadio.setText(NbBundle.getMessage(this.getClass(), "TimeZonePanel.localRadio.text")); localRadio.setText(NbBundle.getMessage(this.getClass(), "TimeZonePanel.localRadio.text"));
otherRadio.setText(NbBundle.getMessage(this.getClass(), "TimeZonePanel.otherRadio.text")); otherRadio.setText(NbBundle.getMessage(this.getClass(), "TimeZonePanel.otherRadio.text"));

View File

@ -9,7 +9,7 @@
<?import jfxtras.scene.control.*?> <?import jfxtras.scene.control.*?>
<?import org.controlsfx.control.*?> <?import org.controlsfx.control.*?>
<fx:root prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.BorderPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <fx:root prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.BorderPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<top> <top>
<ToolBar fx:id="toolBar" prefWidth="200.0" BorderPane.alignment="CENTER"> <ToolBar fx:id="toolBar" prefWidth="200.0" BorderPane.alignment="CENTER">
<items> <items>
@ -115,7 +115,7 @@
</Separator> </Separator>
<HBox> <HBox>
<children> <children>
<Button fx:id="zoomOutButton" mnemonicParsing="false"> <Button fx:id="zoomOutButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false">
<graphic> <graphic>
<ImageView pickOnBounds="true" preserveRatio="true"> <ImageView pickOnBounds="true" preserveRatio="true">
<image> <image>
@ -127,7 +127,7 @@
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" /> <Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</HBox.margin> </HBox.margin>
</Button> </Button>
<Button fx:id="zoomInButton" mnemonicParsing="false"> <Button fx:id="zoomInButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false">
<graphic> <graphic>
<ImageView pickOnBounds="true" preserveRatio="true"> <ImageView pickOnBounds="true" preserveRatio="true">
<image> <image>
@ -143,7 +143,7 @@
</HBox> </HBox>
<MenuButton fx:id="zoomMenuButton" mnemonicParsing="false"> <MenuButton fx:id="zoomMenuButton" mnemonicParsing="false">
<graphic> <graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> <ImageView pickOnBounds="true" preserveRatio="true">
<image> <image>
<Image url="@../images/magnifier-left.png" /> <Image url="@../images/magnifier-left.png" />
</image> </image>

View File

@ -63,6 +63,7 @@ import jfxtras.scene.control.LocalDateTimeTextField;
import org.controlsfx.control.NotificationPane; import org.controlsfx.control.NotificationPane;
import org.controlsfx.control.RangeSlider; import org.controlsfx.control.RangeSlider;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.Interval; import org.joda.time.Interval;
@ -71,11 +72,12 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.VisualizationMode; import org.sleuthkit.autopsy.timeline.VisualizationMode;
import org.sleuthkit.autopsy.timeline.actions.ResetFilters; import org.sleuthkit.autopsy.timeline.actions.ResetFilters;
import org.sleuthkit.autopsy.timeline.actions.SaveSnapshotAsReport; import org.sleuthkit.autopsy.timeline.actions.SaveSnapshotAsReport;
import org.sleuthkit.autopsy.timeline.actions.ZoomIn;
import org.sleuthkit.autopsy.timeline.actions.ZoomOut; import org.sleuthkit.autopsy.timeline.actions.ZoomOut;
import org.sleuthkit.autopsy.timeline.actions.ZoomToEvents;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.events.TagsUpdatedEvent; import org.sleuthkit.autopsy.timeline.events.TagsUpdatedEvent;
import org.sleuthkit.autopsy.timeline.filters.TagsFilter; import org.sleuthkit.autopsy.timeline.filters.TagsFilter;
@ -83,7 +85,7 @@ import static org.sleuthkit.autopsy.timeline.ui.Bundle.VisualizationPanel_refres
import static org.sleuthkit.autopsy.timeline.ui.Bundle.VisualizationPanel_tagsAddedOrDeleted; import static org.sleuthkit.autopsy.timeline.ui.Bundle.VisualizationPanel_tagsAddedOrDeleted;
import org.sleuthkit.autopsy.timeline.ui.countsview.CountsViewPane; import org.sleuthkit.autopsy.timeline.ui.countsview.CountsViewPane;
import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane; import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane;
import org.sleuthkit.autopsy.timeline.ui.detailview.tree.NavPanel; import org.sleuthkit.autopsy.timeline.ui.detailview.tree.EventsTree;
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
/** /**
@ -94,7 +96,7 @@ import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
* *
* TODO: refactor common code out of histogram and CountsView? -jm * TODO: refactor common code out of histogram and CountsView? -jm
*/ */
public class VisualizationPanel extends BorderPane implements TimeLineView { final public class VisualizationPanel extends BorderPane {
private static final Image INFORMATION = new Image("org/sleuthkit/autopsy/timeline/images/information.png", 16, 16, true, true); // NON-NLS private static final Image INFORMATION = new Image("org/sleuthkit/autopsy/timeline/images/information.png", 16, 16, true, true); // NON-NLS
private static final Image REFRESH = new Image("org/sleuthkit/autopsy/timeline/images/arrow-circle-double-135.png"); // NON-NLS private static final Image REFRESH = new Image("org/sleuthkit/autopsy/timeline/images/arrow-circle-double-135.png"); // NON-NLS
@ -104,7 +106,7 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
@GuardedBy("this") @GuardedBy("this")
private LoggedTask<Void> histogramTask; private LoggedTask<Void> histogramTask;
private final NavPanel navPanel; private final EventsTree eventsTree;
private AbstractVisualizationPane<?, ?, ?, ?> visualization; private AbstractVisualizationPane<?, ?, ?, ?> visualization;
@ -204,14 +206,15 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
static private final Lighting lighting = new Lighting(); static private final Lighting lighting = new Lighting();
public VisualizationPanel(NavPanel navPanel) { public VisualizationPanel(TimeLineController controller, EventsTree eventsTree) {
this.navPanel = navPanel; this.controller = controller;
this.eventsTree = eventsTree;
FXMLConstructor.construct(this, "VisualizationPanel.fxml"); // NON-NLS FXMLConstructor.construct(this, "VisualizationPanel.fxml"); // NON-NLS
} }
@FXML // This method is called by the FXMLLoader when initialization is complete @FXML // This method is called by the FXMLLoader when initialization is complete
@NbBundle.Messages("VisualizationPanel.refresh=refresh") @NbBundle.Messages("VisualizationPanel.refresh=refresh")
protected void initialize() { void initialize() {
assert endPicker != null : "fx:id=\"endPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS assert endPicker != null : "fx:id=\"endPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS
assert histogramBox != null : "fx:id=\"histogramBox\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS assert histogramBox != null : "fx:id=\"histogramBox\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS
assert startPicker != null : "fx:id=\"startPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS assert startPicker != null : "fx:id=\"startPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'."; // NON-NLS
@ -286,13 +289,6 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
} }
zoomMenuButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomMenuButton.text")); // NON-NLS zoomMenuButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomMenuButton.text")); // NON-NLS
zoomOutButton.setOnAction(e -> {
controller.pushZoomOutTime();
});
zoomInButton.setOnAction(e -> {
controller.pushZoomInTime();
});
snapShotButton.setOnAction(event -> snapShotButton.setOnAction(event ->
this.snapshot(snapShotResult -> { this.snapshot(snapShotResult -> {
new SaveSnapshotAsReport(controller, snapShotResult.getImage()).handle(event); new SaveSnapshotAsReport(controller, snapShotResult.getImage()).handle(event);
@ -301,12 +297,22 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
); );
snapShotButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapShotButton.text")); // NON-NLS snapShotButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapShotButton.text")); // NON-NLS
if (this.filteredEvents != null && this.filteredEvents != controller.getEventsModel()) {
this.filteredEvents.unRegisterForEvents(this);
this.filteredEvents.timeRangeProperty().removeListener(timeRangeInvalidationListener);
this.filteredEvents.zoomParametersProperty().removeListener(zoomListener);
}
if (this.filteredEvents != controller.getEventsModel()) {
controller.getEventsModel().registerForEvents(this);
controller.getEventsModel().timeRangeProperty().addListener(timeRangeInvalidationListener);
controller.getEventsModel().zoomParametersProperty().addListener(zoomListener);
} }
@Override this.filteredEvents = controller.getEventsModel();
public synchronized void setController(TimeLineController controller) { refreshTimeUI(controller.getEventsModel().timeRangeProperty().get());
this.controller = controller; ActionUtils.configureButton(new ZoomOut(controller), zoomOutButton);
setModel(controller.getEventsModel()); ActionUtils.configureButton(new ZoomIn(controller), zoomInButton);
setViewMode(controller.viewModeProperty().get()); setViewMode(controller.viewModeProperty().get());
controller.getNeedsHistogramRebuild().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> { controller.getNeedsHistogramRebuild().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
if (newValue) { if (newValue) {
@ -321,33 +327,14 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
refreshHistorgram(); refreshHistorgram();
} }
@Override
public void setModel(FilteredEventsModel filteredEvents) {
if (this.filteredEvents != null && this.filteredEvents != filteredEvents) {
this.filteredEvents.unRegisterForEvents(this);
this.filteredEvents.timeRangeProperty().removeListener(timeRangeInvalidationListener);
this.filteredEvents.zoomParametersProperty().removeListener(zoomListener);
}
if (this.filteredEvents != filteredEvents) {
filteredEvents.registerForEvents(this);
filteredEvents.timeRangeProperty().addListener(timeRangeInvalidationListener);
filteredEvents.zoomParametersProperty().addListener(zoomListener);
}
this.filteredEvents = filteredEvents;
refreshTimeUI(filteredEvents.timeRangeProperty().get());
}
private void setViewMode(VisualizationMode visualizationMode) { private void setViewMode(VisualizationMode visualizationMode) {
switch (visualizationMode) { switch (visualizationMode) {
case COUNTS: case COUNTS:
setVisualization(new CountsViewPane(partPane, contextPane, spacer)); setVisualization(new CountsViewPane(controller, partPane, contextPane, spacer));
countsToggle.setSelected(true); countsToggle.setSelected(true);
break; break;
case DETAIL: case DETAIL:
setVisualization(new DetailViewPane(partPane, contextPane, spacer)); setVisualization(new DetailViewPane(controller, partPane, contextPane, spacer));
detailsToggle.setSelected(true); detailsToggle.setSelected(true);
break; break;
} }
@ -362,24 +349,25 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
} }
visualization = newViz; visualization = newViz;
visualization.update();
toolBar.getItems().addAll(newViz.getSettingsNodes()); toolBar.getItems().addAll(newViz.getSettingsNodes());
visualization.setController(controller);
notificationPane.setContent(visualization); notificationPane.setContent(visualization);
if (visualization instanceof DetailViewPane) { if (visualization instanceof DetailViewPane) {
navPanel.setDetailViewPane((DetailViewPane) visualization); eventsTree.setDetailViewPane((DetailViewPane) visualization);
} }
visualization.hasEvents.addListener((observable, oldValue, newValue) -> { visualization.hasEvents.addListener((observable, oldValue, newValue) -> {
if (newValue == false) { if (newValue == false) {
notificationPane.setContent(new StackPane(visualization, new Region() { notificationPane.setContent(
new StackPane(visualization,
new Region() {
{ {
setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY)));
setOpacity(.3); setOpacity(.3);
} }
}, new NoEventsDialog(() -> { },
notificationPane.setContent(visualization); new NoEventsDialog(() -> notificationPane.setContent(visualization))));
})));
} else { } else {
notificationPane.setContent(visualization); notificationPane.setContent(visualization);
} }
@ -544,7 +532,6 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
private NoEventsDialog(Runnable closeCallback) { private NoEventsDialog(Runnable closeCallback) {
this.closeCallback = closeCallback; this.closeCallback = closeCallback;
FXMLConstructor.construct(this, "NoEventsDialog.fxml"); // NON-NLS FXMLConstructor.construct(this, "NoEventsDialog.fxml"); // NON-NLS
} }
@FXML @FXML
@ -554,15 +541,9 @@ public class VisualizationPanel extends BorderPane implements TimeLineView {
assert zoomButton != null : "fx:id=\"zoomButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'."; // NON-NLS assert zoomButton != null : "fx:id=\"zoomButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'."; // NON-NLS
noEventsDialogLabel.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.noEventsDialogLabel.text")); // NON-NLS noEventsDialogLabel.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.noEventsDialogLabel.text")); // NON-NLS
zoomButton.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.zoomButton.text")); // NON-NLS ActionUtils.configureButton(new ZoomToEvents(controller), zoomButton);
Action zoomOutAction = new ZoomOut(controller); dismissButton.setOnAction(actionEvent -> closeCallback.run());
zoomButton.setOnAction(zoomOutAction);
zoomButton.disableProperty().bind(zoomOutAction.disabledProperty());
dismissButton.setOnAction(e -> {
closeCallback.run();
});
Action defaultFiltersAction = new ResetFilters(controller); Action defaultFiltersAction = new ResetFilters(controller);
resetFiltersButton.setOnAction(defaultFiltersAction); resetFiltersButton.setOnAction(defaultFiltersAction);
resetFiltersButton.disableProperty().bind(defaultFiltersAction.disabledProperty()); resetFiltersButton.disableProperty().bind(defaultFiltersAction.disabledProperty());

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013 Basis Technology Corp. * Copyright 2013-15 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");

View File

@ -66,7 +66,6 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.VisualizationMode; import org.sleuthkit.autopsy.timeline.VisualizationMode;
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;
@ -279,9 +278,9 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
}; };
} }
public CountsViewPane(Pane partPane, Pane contextPane, Region spacer) { public CountsViewPane(TimeLineController controller, Pane partPane, Pane contextPane, Region spacer) {
super(partPane, contextPane, spacer); super(controller, partPane, contextPane, spacer);
chart = new EventCountsChart(dateAxis, countAxis); chart = new EventCountsChart(controller, dateAxis, countAxis);
setChartClickHandler(); setChartClickHandler();
chart.setData(dataSets); chart.setData(dataSets);
setCenter(chart); setCenter(chart);

View File

@ -19,7 +19,6 @@
package org.sleuthkit.autopsy.timeline.ui.countsview; package org.sleuthkit.autopsy.timeline.ui.countsview;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis; import javafx.scene.chart.NumberAxis;
@ -32,7 +31,6 @@ import org.joda.time.DateTime;
import org.joda.time.Interval; import org.joda.time.Interval;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.ui.IntervalSelector; import org.sleuthkit.autopsy.timeline.ui.IntervalSelector;
import org.sleuthkit.autopsy.timeline.ui.TimeLineChart; import org.sleuthkit.autopsy.timeline.ui.TimeLineChart;
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
@ -45,11 +43,12 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
private ContextMenu chartContextMenu; private ContextMenu chartContextMenu;
@Override
public ContextMenu getChartContextMenu() { public ContextMenu getChartContextMenu() {
return chartContextMenu; return chartContextMenu;
} }
private TimeLineController controller; private final TimeLineController controller;
private IntervalSelector<? extends String> intervalSelector; private IntervalSelector<? extends String> intervalSelector;
@ -60,8 +59,9 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
*/ */
private RangeDivisionInfo rangeInfo; private RangeDivisionInfo rangeInfo;
EventCountsChart(CategoryAxis dateAxis, NumberAxis countAxis) { EventCountsChart(TimeLineController controller, CategoryAxis dateAxis, NumberAxis countAxis) {
super(dateAxis, countAxis); super(dateAxis, countAxis);
this.controller = controller;
//configure constant properties on axes and chart //configure constant properties on axes and chart
dateAxis.setAnimated(true); dateAxis.setAnimated(true);
dateAxis.setLabel(null); dateAxis.setLabel(null);
@ -87,6 +87,7 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
setOnMouseDragged(chartDragHandler); setOnMouseDragged(chartDragHandler);
setOnMouseClicked(new MouseClickedHandler<>(this)); setOnMouseClicked(new MouseClickedHandler<>(this));
} }
@Override @Override
@ -95,6 +96,7 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
intervalSelector = null; intervalSelector = null;
} }
@Override
public ContextMenu getChartContextMenu(MouseEvent clickEvent) throws MissingResourceException { public ContextMenu getChartContextMenu(MouseEvent clickEvent) throws MissingResourceException {
if (chartContextMenu != null) { if (chartContextMenu != null) {
chartContextMenu.hide(); chartContextMenu.hide();
@ -112,12 +114,6 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
return controller; return controller;
} }
@Override
public synchronized void setController(TimeLineController controller) {
this.controller = controller;
setModel(this.controller.getEventsModel());
}
@Override @Override
public IntervalSelector<? extends String> getIntervalSelector() { public IntervalSelector<? extends String> getIntervalSelector() {
return intervalSelector; return intervalSelector;
@ -129,14 +125,6 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
getChartChildren().add(getIntervalSelector()); getChartChildren().add(getIntervalSelector());
} }
@Override
public void setModel(FilteredEventsModel filteredEvents) {
filteredEvents.zoomParametersProperty().addListener(o -> {
clearIntervalSelector();
controller.selectEventIDs(Collections.emptyList());
});
}
@Override @Override
public CountsIntervalSelector newIntervalSelector() { public CountsIntervalSelector newIntervalSelector() {
return new CountsIntervalSelector(this); return new CountsIntervalSelector(this);
@ -179,7 +167,7 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
* Interval Selector for the counts chart, adjusts interval based on * Interval Selector for the counts chart, adjusts interval based on
* rangeInfo to include final period * rangeInfo to include final period
*/ */
static private class CountsIntervalSelector extends IntervalSelector<String> { final static private class CountsIntervalSelector extends IntervalSelector<String> {
private final EventCountsChart countsChart; private final EventCountsChart countsChart;

View File

@ -113,9 +113,10 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventClu
return chart.getEventBundles(); return chart.getEventBundles();
} }
public DetailViewPane(Pane partPane, Pane contextPane, Region spacer) {
super(partPane, contextPane, spacer); public DetailViewPane(TimeLineController controller, Pane partPane, Pane contextPane, Region spacer) {
chart = new EventDetailsChart(dateAxis, verticalAxis, selectedNodes); super(controller, partPane, contextPane, spacer);
chart = new EventDetailsChart(controller, dateAxis, verticalAxis, selectedNodes);
setChartClickHandler(); setChartClickHandler();
chart.setData(dataSets); chart.setData(dataSets);
setCenter(chart); setCenter(chart);
@ -211,11 +212,6 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventClu
} }
@Override
public synchronized void setModel(FilteredEventsModel filteredEvents) {
super.setModel(filteredEvents);
}
private void incrementScrollValue(int factor) { private void incrementScrollValue(int factor) {
vertScrollBar.valueProperty().set(Math.max(0, Math.min(100, vertScrollBar.getValue() + factor * (chart.getHeight() / chart.maxVScrollProperty().get())))); vertScrollBar.valueProperty().set(Math.max(0, Math.min(100, vertScrollBar.getValue() + factor * (chart.getHeight() / chart.maxVScrollProperty().get()))));
} }

View File

@ -102,16 +102,19 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
private static final int PROJECTED_LINE_Y_OFFSET = 5; private static final int PROJECTED_LINE_Y_OFFSET = 5;
private static final int PROJECTED_LINE_STROKE_WIDTH = 5; private static final int PROJECTED_LINE_STROKE_WIDTH = 5;
private static final int MINIMUM_EVENT_NODE_GAP = 4; private static final int MINIMUM_EVENT_NODE_GAP = 4;
private final TimeLineController controller;
private final FilteredEventsModel filteredEvents;
private ContextMenu chartContextMenu; private ContextMenu chartContextMenu;
public ContextMenu getChartContextMenu() { public ContextMenu getChartContextMenu() {
return chartContextMenu; return chartContextMenu;
} }
private TimeLineController controller;
private FilteredEventsModel filteredEvents;
/** /**
* a user positionable vertical line to help compare events * a user positionable vertical line to help compare events
*/ */
@ -187,10 +190,21 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
*/ */
final SimpleDoubleProperty truncateWidth = new SimpleDoubleProperty(200.0); final SimpleDoubleProperty truncateWidth = new SimpleDoubleProperty(200.0);
EventDetailsChart(DateAxis dateAxis, final Axis<EventCluster> verticalAxis, ObservableList<EventBundleNodeBase<?, ?, ?>> selectedNodes) { EventDetailsChart(TimeLineController controller, DateAxis dateAxis, final Axis<EventCluster> verticalAxis, ObservableList<EventBundleNodeBase<?, ?, ?>> selectedNodes) {
super(dateAxis, verticalAxis); super(dateAxis, verticalAxis);
this.controller = controller;
this.filteredEvents = this.controller.getEventsModel();
filteredEvents.zoomParametersProperty().addListener(o -> {
clearGuideLine();
clearIntervalSelector();
selectedNodes.clear();
projectionMap.clear();
controller.selectEventIDs(Collections.emptyList());
});
Tooltip.install(this, AbstractVisualizationPane.getDragTooltip()); Tooltip.install(this, AbstractVisualizationPane.getDragTooltip());
dateAxis.setAutoRanging(false); dateAxis.setAutoRanging(false);
verticalAxis.setVisible(false);//TODO: why doesn't this hide the vertical axis, instead we have to turn off all parts individually? -jm verticalAxis.setVisible(false);//TODO: why doesn't this hide the vertical axis, instead we have to turn off all parts individually? -jm
@ -210,6 +224,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
truncateAll.addListener(layoutInvalidationListener); truncateAll.addListener(layoutInvalidationListener);
truncateWidth.addListener(layoutInvalidationListener); truncateWidth.addListener(layoutInvalidationListener);
descrVisibility.addListener(layoutInvalidationListener); descrVisibility.addListener(layoutInvalidationListener);
getController().getQuickHideFilters().addListener(layoutInvalidationListener);
//this is needed to allow non circular binding of the guideline and timerangeRect heights to the height of the chart //this is needed to allow non circular binding of the guideline and timerangeRect heights to the height of the chart
//TODO: seems like a hack, can we remove? -jm //TODO: seems like a hack, can we remove? -jm
@ -260,30 +275,6 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
return bandByType; return bandByType;
} }
@Override
public synchronized void setController(TimeLineController controller) {
this.controller = controller;
setModel(this.controller.getEventsModel());
getController().getQuickHideFilters().addListener(layoutInvalidationListener);
}
@Override
public void setModel(FilteredEventsModel filteredEvents) {
if (this.filteredEvents != filteredEvents) {
filteredEvents.zoomParametersProperty().addListener(o -> {
clearGuideLine();
clearIntervalSelector();
selectedNodes.clear();
projectionMap.clear();
controller.selectEventIDs(Collections.emptyList());
});
}
this.filteredEvents = filteredEvents;
}
@Override @Override
public IntervalSelector<DateTime> newIntervalSelector() { public IntervalSelector<DateTime> newIntervalSelector() {
return new DetailIntervalSelector(this); return new DetailIntervalSelector(this);

View File

@ -1 +0,0 @@
NavPanel.eventsTreeLabel.text=Sort By\:

View File

@ -1 +1 @@
NavPanel.eventsTreeLabel.text=\u4E0B\u8A18\u306B\u5F93\u3044\u4E26\u3079\u66FF\u3048\uFF1A EventsTree.Label.text=\u4e0b\u8a18\u306b\u5f93\u3044\u4e26\u3079\u66ff\u3048\uff1a

View File

@ -46,9 +46,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.datamodel.EventBundle; import org.sleuthkit.autopsy.timeline.datamodel.EventBundle;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter; import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter; import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane; import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane;
@ -59,11 +57,9 @@ import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane;
* out. Right clicking on a item in the tree shows a context menu to show/hide * out. Right clicking on a item in the tree shows a context menu to show/hide
* it. * it.
*/ */
public class NavPanel extends BorderPane implements TimeLineView { final public class EventsTree extends BorderPane {
private TimeLineController controller; private final TimeLineController controller;
private FilteredEventsModel filteredEvents;
private DetailViewPane detailViewPane; private DetailViewPane detailViewPane;
@ -76,8 +72,10 @@ public class NavPanel extends BorderPane implements TimeLineView {
@FXML @FXML
private ComboBox<Comparator<TreeItem<EventBundle<?>>>> sortByBox; private ComboBox<Comparator<TreeItem<EventBundle<?>>>> sortByBox;
public NavPanel() { public EventsTree(TimeLineController controller) {
FXMLConstructor.construct(this, "NavPanel.fxml"); // NON-NLS this.controller = controller;
FXMLConstructor.construct(this, "EventsTree.fxml"); // NON-NLS
} }
public void setDetailViewPane(DetailViewPane detailViewPane) { public void setDetailViewPane(DetailViewPane detailViewPane) {
@ -112,19 +110,8 @@ public class NavPanel extends BorderPane implements TimeLineView {
} }
@Override
public void setController(TimeLineController controller) {
this.controller = controller;
setModel(controller.getEventsModel());
}
@Override
public void setModel(FilteredEventsModel filteredEvents) {
this.filteredEvents = filteredEvents;
}
@FXML @FXML
@NbBundle.Messages("EventsTree.Label.text=Sort By:")
void initialize() { void initialize() {
assert sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'NavPanel.fxml'."; // NON-NLS assert sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'NavPanel.fxml'."; // NON-NLS
@ -137,7 +124,7 @@ public class NavPanel extends BorderPane implements TimeLineView {
eventsTree.setCellFactory((TreeView<EventBundle<?>> p) -> new EventBundleTreeCell()); eventsTree.setCellFactory((TreeView<EventBundle<?>> p) -> new EventBundleTreeCell());
eventsTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); eventsTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
eventsTreeLabel.setText(NbBundle.getMessage(this.getClass(), "NavPanel.eventsTreeLabel.text")); eventsTreeLabel.setText(Bundle.EventsTree_Label_text());
} }
/** /**
@ -232,6 +219,5 @@ public class NavPanel extends BorderPane implements TimeLineView {
setContextMenu(null); setContextMenu(null);
} }
} }
} }
} }

View File

@ -44,7 +44,6 @@ import org.controlsfx.control.action.ActionUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.VisualizationMode; import org.sleuthkit.autopsy.timeline.VisualizationMode;
import org.sleuthkit.autopsy.timeline.actions.ResetFilters; import org.sleuthkit.autopsy.timeline.actions.ResetFilters;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
@ -64,7 +63,7 @@ import static org.sleuthkit.autopsy.timeline.ui.filtering.Bundle.Timeline_ui_fil
* This also implements {@link TimeLineView} since it dynamically updates its * This also implements {@link TimeLineView} since it dynamically updates its
* filters based on the contents of a {@link FilteredEventsModel} * filters based on the contents of a {@link FilteredEventsModel}
*/ */
final public class FilterSetPanel extends BorderPane implements TimeLineView { final public class FilterSetPanel extends BorderPane {
private static final Image TICK = new Image("org/sleuthkit/autopsy/timeline/images/tick.png"); private static final Image TICK = new Image("org/sleuthkit/autopsy/timeline/images/tick.png");
@ -171,20 +170,25 @@ final public class FilterSetPanel extends BorderPane implements TimeLineView {
legendColumn.setCellValueFactory(param -> param.getValue().valueProperty()); legendColumn.setCellValueFactory(param -> param.getValue().valueProperty());
legendColumn.setCellFactory(col -> new LegendCell(this.controller)); legendColumn.setCellFactory(col -> new LegendCell(this.controller));
}
public FilterSetPanel() {
FXMLConstructor.construct(this, "FilterSetPanel.fxml"); // NON-NLS
expansionMap.put(new TypeFilter(RootEventType.getInstance()).getDisplayName(), true); expansionMap.put(new TypeFilter(RootEventType.getInstance()).getDisplayName(), true);
}
@Override
public void setController(TimeLineController timeLineController) {
this.controller = timeLineController;
Action defaultFiltersAction = new ResetFilters(controller); Action defaultFiltersAction = new ResetFilters(controller);
defaultButton.setOnAction(defaultFiltersAction); defaultButton.setOnAction(defaultFiltersAction);
defaultButton.disableProperty().bind(defaultFiltersAction.disabledProperty()); defaultButton.disableProperty().bind(defaultFiltersAction.disabledProperty());
this.setModel(timeLineController.getEventsModel());
this.filteredEvents.eventTypeZoomProperty().addListener((Observable observable) -> {
applyFilters();
});
this.filteredEvents.descriptionLODProperty().addListener((Observable observable1) -> {
applyFilters();
});
this.filteredEvents.timeRangeProperty().addListener((Observable observable2) -> {
applyFilters();
});
this.filteredEvents.filterProperty().addListener((Observable o) -> {
refresh();
});
refresh();
hiddenDescriptionsListView.setItems(controller.getQuickHideFilters()); hiddenDescriptionsListView.setItems(controller.getQuickHideFilters());
hiddenDescriptionsListView.setCellFactory((ListView<DescriptionFilter> param) -> { hiddenDescriptionsListView.setCellFactory((ListView<DescriptionFilter> param) -> {
@ -237,25 +241,13 @@ final public class FilterSetPanel extends BorderPane implements TimeLineView {
} }
}); });
} }
@Override public FilterSetPanel(TimeLineController controller) {
this.controller = controller;
public void setModel(FilteredEventsModel filteredEvents) { this.filteredEvents = controller.getEventsModel();
this.filteredEvents = filteredEvents; FXMLConstructor.construct(this, "FilterSetPanel.fxml"); // NON-NLS
this.filteredEvents.eventTypeZoomProperty().addListener((Observable observable) -> {
applyFilters();
});
this.filteredEvents.descriptionLODProperty().addListener((Observable observable) -> {
applyFilters();
});
this.filteredEvents.timeRangeProperty().addListener((Observable observable) -> {
applyFilters();
});
this.filteredEvents.filterProperty().addListener((Observable o) -> {
refresh();
});
refresh();
} }

View File

@ -29,7 +29,6 @@ import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle; import javafx.scene.shape.Rectangle;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter; import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
import org.sleuthkit.autopsy.timeline.filters.TextFilter; import org.sleuthkit.autopsy.timeline.filters.TextFilter;
@ -40,18 +39,19 @@ import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
* A TreeTableCell that shows an icon and color corresponding to the represented * A TreeTableCell that shows an icon and color corresponding to the represented
* filter * filter
*/ */
class LegendCell extends TreeTableCell<AbstractFilter, AbstractFilter> implements TimeLineView { final class LegendCell extends TreeTableCell<AbstractFilter, AbstractFilter> {
private static final Color CLEAR = Color.rgb(0, 0, 0, 0); private static final Color CLEAR = Color.rgb(0, 0, 0, 0);
private TimeLineController controller; private final TimeLineController controller;
private FilteredEventsModel filteredEvents; private final FilteredEventsModel filteredEvents;
//We need a controller so we can listen to changes in EventTypeZoom to show/hide legends //We need a controller so we can listen to changes in EventTypeZoom to show/hide legends
public LegendCell(TimeLineController controller) { LegendCell(TimeLineController controller) {
setEditable(false); setEditable(false);
setController(controller); this.controller = controller;
this.filteredEvents = this.controller.getEventsModel();
} }
@Override @Override
@ -119,15 +119,4 @@ class LegendCell extends TreeTableCell<AbstractFilter, AbstractFilter> implement
}); });
} }
} }
@Override
synchronized public final void setController(TimeLineController controller) {
this.controller = controller;
setModel(this.controller.getEventsModel());
}
@Override
public void setModel(FilteredEventsModel filteredEvents) {
this.filteredEvents = filteredEvents;
}
} }

View File

@ -18,19 +18,20 @@
*/ */
package org.sleuthkit.autopsy.timeline.zooming; package org.sleuthkit.autopsy.timeline.zooming;
import java.net.URL;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ResourceBundle;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.*; import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Tooltip;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.FXMLConstructor;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.TimeLineView;
import org.sleuthkit.autopsy.timeline.VisualizationMode; import org.sleuthkit.autopsy.timeline.VisualizationMode;
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;
@ -44,13 +45,7 @@ import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
* has sliders to provide context/control over three axes of zooming (timescale, * has sliders to provide context/control over three axes of zooming (timescale,
* event hierarchy, and description detail). * event hierarchy, and description detail).
*/ */
public class ZoomSettingsPane extends TitledPane implements TimeLineView { public class ZoomSettingsPane extends TitledPane {
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML @FXML
private Button backButton; private Button backButton;
@ -105,35 +100,6 @@ public class ZoomSettingsPane extends TitledPane implements TimeLineView {
timeUnitLabel.setText(NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.timeUnitLabel.text")); timeUnitLabel.setText(NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.timeUnitLabel.text"));
zoomLabel.setText(NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.zoomLabel.text")); zoomLabel.setText(NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.zoomLabel.text"));
historyLabel.setText(NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.historyLabel.text")); historyLabel.setText(NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.historyLabel.text"));
}
public ZoomSettingsPane() {
FXMLConstructor.construct(this, "ZoomSettingsPane.fxml"); // NON-NLS
}
@Override
synchronized public void setController(TimeLineController controller) {
this.controller = controller;
setModel(controller.getEventsModel());
descrLODSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(VisualizationMode.COUNTS));
Back back = new Back(controller);
backButton.disableProperty().bind(back.disabledProperty());
backButton.setOnAction(back);
backButton.setTooltip(new Tooltip(
NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.backButton.toolTip.text",
back.getAccelerator().getName())));
Forward forward = new Forward(controller);
forwardButton.disableProperty().bind(forward.disabledProperty());
forwardButton.setOnAction(forward);
forwardButton.setTooltip(new Tooltip(
NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.forwardButton.toolTip.text",
forward.getAccelerator().getName())));
}
@Override
public void setModel(FilteredEventsModel filteredEvents) {
this.filteredEvents = filteredEvents;
initializeSlider(timeUnitSlider, initializeSlider(timeUnitSlider,
() -> { () -> {
@ -151,18 +117,14 @@ public class ZoomSettingsPane extends TitledPane implements TimeLineView {
timeUnitSlider.setValue(TimeUnits.fromChronoUnit(chronoUnit).ordinal() - 1); timeUnitSlider.setValue(TimeUnits.fromChronoUnit(chronoUnit).ordinal() - 1);
}); });
initializeSlider(descrLODSlider, () -> {
initializeSlider(descrLODSlider,
() -> {
DescriptionLoD newLOD = DescriptionLoD.values()[Math.round(descrLODSlider.valueProperty().floatValue())]; DescriptionLoD newLOD = DescriptionLoD.values()[Math.round(descrLODSlider.valueProperty().floatValue())];
if (controller.pushDescrLOD(newLOD) == false) { if (controller.pushDescrLOD(newLOD) == false) {
descrLODSlider.setValue(new DescrLODConverter().fromString(filteredEvents.getDescriptionLOD().toString())); descrLODSlider.setValue(new DescrLODConverter().fromString(controller.getEventsModel().getDescriptionLOD().toString()));
} }
}, this.filteredEvents.descriptionLODProperty(), }, this.filteredEvents.descriptionLODProperty(), () -> {
() -> {
descrLODSlider.setValue(this.filteredEvents.descriptionLODProperty().get().ordinal()); descrLODSlider.setValue(this.filteredEvents.descriptionLODProperty().get().ordinal());
}); });
initializeSlider(typeZoomSlider, initializeSlider(typeZoomSlider,
() -> { () -> {
EventTypeZoomLevel newZoomLevel = EventTypeZoomLevel.values()[Math.round(typeZoomSlider.valueProperty().floatValue())]; EventTypeZoomLevel newZoomLevel = EventTypeZoomLevel.values()[Math.round(typeZoomSlider.valueProperty().floatValue())];
@ -172,6 +134,26 @@ public class ZoomSettingsPane extends TitledPane implements TimeLineView {
() -> { () -> {
typeZoomSlider.setValue(this.filteredEvents.eventTypeZoomProperty().get().ordinal()); typeZoomSlider.setValue(this.filteredEvents.eventTypeZoomProperty().get().ordinal());
}); });
descrLODSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(VisualizationMode.COUNTS));
Back back = new Back(controller);
backButton.disableProperty().bind(back.disabledProperty());
backButton.setOnAction(back);
backButton.setTooltip(new Tooltip(
NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.backButton.toolTip.text",
back.getAccelerator().getName())));
Forward forward = new Forward(controller);
forwardButton.disableProperty().bind(forward.disabledProperty());
forwardButton.setOnAction(forward);
forwardButton.setTooltip(new Tooltip(
NbBundle.getMessage(this.getClass(), "ZoomSettingsPane.forwardButton.toolTip.text",
forward.getAccelerator().getName())));
}
public ZoomSettingsPane(TimeLineController controller) {
this.controller = controller;
this.filteredEvents = controller.getEventsModel();
FXMLConstructor.construct(this, "ZoomSettingsPane.fxml"); // NON-NLS
} }
/** /**