19 package org.sleuthkit.autopsy.timeline;
21 import java.beans.PropertyVetoException;
22 import java.util.List;
23 import java.util.logging.Level;
24 import java.util.stream.Collectors;
25 import javafx.application.Platform;
26 import javafx.beans.InvalidationListener;
27 import javafx.beans.Observable;
28 import javafx.scene.Scene;
29 import javafx.scene.control.SplitPane;
30 import javafx.scene.control.Tab;
31 import javafx.scene.control.TabPane;
32 import javafx.scene.image.ImageView;
33 import javafx.scene.input.KeyCode;
34 import javafx.scene.input.KeyCodeCombination;
35 import javafx.scene.input.KeyEvent;
36 import javafx.scene.layout.Priority;
37 import javafx.scene.layout.VBox;
38 import javax.swing.JComponent;
39 import javax.swing.SwingUtilities;
40 import org.controlsfx.control.Notifications;
41 import org.joda.time.Interval;
42 import org.joda.time.format.DateTimeFormatter;
43 import org.openide.explorer.ExplorerManager;
44 import org.openide.explorer.ExplorerUtils;
45 import org.openide.nodes.AbstractNode;
46 import org.openide.nodes.Children;
47 import org.openide.nodes.Node;
48 import org.openide.util.NbBundle;
49 import org.openide.windows.Mode;
50 import org.openide.windows.RetainLocation;
51 import org.openide.windows.TopComponent;
52 import org.openide.windows.WindowManager;
74 @TopComponent.Description(
75 preferredID =
"TimeLineTopComponent",
77 persistenceType = TopComponent.PERSISTENCE_NEVER)
78 @TopComponent.Registration(mode =
"timeline", openAtStartup =
false)
79 @RetainLocation(
"timeline")
91 private final ExplorerManager em = new ExplorerManager();
99 @NbBundle.Messages({
"TimelineTopComponent.selectedEventListener.errorMsg=There was a problem getting the content for the selected event."})
100 private final InvalidationListener selectedEventsListener =
new InvalidationListener() {
102 public void invalidated(Observable observable) {
106 switch (controller.getViewMode()) {
112 for (
int i = 0; i < selectedEventIDs.size(); i++) {
115 Children children =
new Children.Array();
116 children.add(childArray);
118 SwingUtilities.invokeLater(() -> {
120 em.setRootContext(
new AbstractNode(children));
123 em.setSelectedNodes(childArray);
124 }
catch (PropertyVetoException ex) {
126 LOGGER.log(Level.SEVERE,
"Selecting the event node was vetoed.", ex);
129 if (childArray.length == 1) {
130 contentViewerPanel.setNode(childArray[0]);
132 contentViewerPanel.setNode(null);
135 }
catch (IllegalStateException ex) {
137 LOGGER.log(Level.SEVERE,
"There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex);
138 }
catch (TskCoreException ex) {
139 LOGGER.log(Level.SEVERE,
"Failed to lookup Sleuthkit object backing a SingleEvent.", ex);
140 Platform.runLater(() -> {
141 Notifications.create()
142 .owner(jFXViewPanel.getScene().getWindow())
143 .text(Bundle.TimelineTopComponent_selectedEventListener_errorMsg())
153 SwingUtilities.invokeLater(() -> {
154 dataResultPanel.setPath(getResultViewerSummaryString());
155 dataResultPanel.setNode(rootNode);
159 throw new UnsupportedOperationException(
"Unknown view mode: " + controller.getViewMode());
165 switch (controller.getViewMode()) {
172 SwingUtilities.invokeLater(() -> {
173 splitYPane.remove(contentViewerPanel);
174 if ((horizontalSplitPane.getParent() == splitYPane) ==
false) {
175 splitYPane.setBottomComponent(horizontalSplitPane);
176 horizontalSplitPane.setRightComponent(contentViewerPanel);
185 SwingUtilities.invokeLater(() -> {
186 splitYPane.setBottomComponent(contentViewerPanel);
190 throw new UnsupportedOperationException(
"Unknown ViewMode: " + controller.getViewMode());
201 associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
207 this.controller = controller;
214 horizontalSplitPane.setLeftComponent(dataResultPanel);
215 horizontalSplitPane.setRightComponent(contentViewerPanel);
217 dataResultPanel.
open();
219 Platform.runLater(this::initFXComponents);
234 "TimeLineTopComponent.eventsTab.name=Events",
235 "TimeLineTopComponent.filterTab.name=Filters"})
236 @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
237 void initFXComponents() {
239 final TimeZonePanel timeZonePanel =
new TimeZonePanel();
240 VBox.setVgrow(timeZonePanel, Priority.SOMETIMES);
241 HistoryToolBar historyToolBar =
new HistoryToolBar(controller);
242 final ZoomSettingsPane zoomSettingsPane =
new ZoomSettingsPane(controller);
245 final Tab filterTab =
new Tab(Bundle.TimeLineTopComponent_filterTab_name(),
new FilterSetPanel(controller));
246 filterTab.setClosable(
false);
247 filterTab.setGraphic(
new ImageView(
"org/sleuthkit/autopsy/timeline/images/funnel.png"));
250 final EventsTree eventsTree =
new EventsTree(controller);
251 final Tab eventsTreeTab =
new Tab(Bundle.TimeLineTopComponent_eventsTab_name(), eventsTree);
252 eventsTreeTab.setClosable(
false);
253 eventsTreeTab.setGraphic(
new ImageView(
"org/sleuthkit/autopsy/timeline/images/timeline_marker.png"));
254 eventsTreeTab.disableProperty().bind(controller.viewModeProperty().isNotEqualTo(ViewMode.DETAIL));
256 final TabPane leftTabPane =
new TabPane(filterTab, eventsTreeTab);
257 VBox.setVgrow(leftTabPane, Priority.ALWAYS);
258 controller.viewModeProperty().addListener(viewMode -> {
259 if (controller.getViewMode().equals(ViewMode.DETAIL) ==
false) {
261 leftTabPane.getSelectionModel().select(filterTab);
266 final VBox leftVBox =
new VBox(5, timeZonePanel, historyToolBar, zoomSettingsPane, leftTabPane);
267 SplitPane.setResizableWithParent(leftVBox, Boolean.FALSE);
269 final ViewFrame viewFrame =
new ViewFrame(controller, eventsTree);
270 final SplitPane mainSplitPane =
new SplitPane(leftVBox, viewFrame);
271 mainSplitPane.setDividerPositions(0);
273 final Scene scene =
new Scene(mainSplitPane);
274 scene.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
275 if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
276 new Back(controller).handle(null);
277 }
else if (
new KeyCodeCombination(KeyCode.BACK_SPACE).match(keyEvent)) {
278 new Back(controller).handle(null);
279 }
else if (
new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
280 new Forward(controller).handle(null);
281 }
else if (
new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(keyEvent)) {
282 new Forward(controller).handle(null);
287 jFXViewPanel.setScene(scene);
288 jFXstatusPanel.setScene(
new Scene(
new StatusBar(controller)));
298 return modes.stream().filter(mode -> mode.getName().equals(
"timeline") || mode.getName().equals(
"ImageGallery"))
299 .collect(Collectors.toList());
310 jFXstatusPanel =
new javafx.embed.swing.JFXPanel();
311 splitYPane =
new javax.swing.JSplitPane();
312 jFXViewPanel =
new javafx.embed.swing.JFXPanel();
313 horizontalSplitPane =
new javax.swing.JSplitPane();
314 leftFillerPanel =
new javax.swing.JPanel();
315 rightfillerPanel =
new javax.swing.JPanel();
317 jFXstatusPanel.setPreferredSize(
new java.awt.Dimension(100, 16));
319 splitYPane.setDividerLocation(420);
320 splitYPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
321 splitYPane.setResizeWeight(0.9);
322 splitYPane.setPreferredSize(
new java.awt.Dimension(1024, 400));
323 splitYPane.setLeftComponent(jFXViewPanel);
325 horizontalSplitPane.setDividerLocation(600);
326 horizontalSplitPane.setResizeWeight(0.5);
327 horizontalSplitPane.setPreferredSize(
new java.awt.Dimension(1200, 300));
328 horizontalSplitPane.setRequestFocusEnabled(
false);
330 javax.swing.GroupLayout leftFillerPanelLayout =
new javax.swing.GroupLayout(leftFillerPanel);
331 leftFillerPanel.setLayout(leftFillerPanelLayout);
332 leftFillerPanelLayout.setHorizontalGroup(
333 leftFillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
334 .addGap(0, 599, Short.MAX_VALUE)
336 leftFillerPanelLayout.setVerticalGroup(
337 leftFillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
338 .addGap(0, 54, Short.MAX_VALUE)
341 horizontalSplitPane.setLeftComponent(leftFillerPanel);
343 javax.swing.GroupLayout rightfillerPanelLayout =
new javax.swing.GroupLayout(rightfillerPanel);
344 rightfillerPanel.setLayout(rightfillerPanelLayout);
345 rightfillerPanelLayout.setHorizontalGroup(
346 rightfillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
347 .addGap(0, 364, Short.MAX_VALUE)
349 rightfillerPanelLayout.setVerticalGroup(
350 rightfillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
351 .addGap(0, 54, Short.MAX_VALUE)
354 horizontalSplitPane.setRightComponent(rightfillerPanel);
356 splitYPane.setRightComponent(horizontalSplitPane);
358 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
359 this.setLayout(layout);
360 layout.setHorizontalGroup(
361 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
362 .addComponent(splitYPane, javax.swing.GroupLayout.DEFAULT_SIZE, 972, Short.MAX_VALUE)
363 .addComponent(jFXstatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
365 layout.setVerticalGroup(
366 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
367 .addGroup(layout.createSequentialGroup()
368 .addComponent(splitYPane, javax.swing.GroupLayout.DEFAULT_SIZE, 482, Short.MAX_VALUE)
370 .addComponent(jFXstatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE))
385 super.componentOpened();
386 WindowManager.getDefault().setTopComponentFloating(
this,
true);
401 "# {0} - start of date range",
402 "# {1} - end of date range",
403 "TimeLineResultView.startDateToEndDate.text={0} to {1}"})
405 Interval selectedTimeRange = controller.getSelectedTimeRange();
406 if (selectedTimeRange == null) {
410 String start = selectedTimeRange.getStart()
412 .toString(zonedFormatter);
413 String end = selectedTimeRange.getEnd()
415 .toString(zonedFormatter);
416 return Bundle.TimeLineResultView_startDateToEndDate_text(start, end);
TimeLineTopComponent(TimeLineController controller)
static final KeyStroke BOOKMARK_SHORTCUT
static EventNode createEventNode(final Long eventID, FilteredEventsModel eventsModel)
static ReadOnlyObjectProperty< TimeZone > getTimeZone()
String getResultViewerSummaryString()
javafx.embed.swing.JFXPanel jFXstatusPanel
javax.swing.JSplitPane splitYPane
List< Mode > availableModes(List< Mode > modes)
static DataContentPanel createInstance()
javafx.embed.swing.JFXPanel jFXViewPanel
synchronized ObservableList< Long > getSelectedEventIDs()
static DateTimeZone getJodaTimeZone()
static DataResultPanel createInstanceUninitialized(String title, String pathText, Node rootNode, int totalMatches, DataContent customContentView)
javax.swing.JSplitPane horizontalSplitPane
synchronized ReadOnlyObjectProperty< ViewMode > viewModeProperty()
ExplorerManager getExplorerManager()
synchronized static Logger getLogger(String name)
static DateTimeFormatter getZonedFormatter()
javax.swing.JPanel rightfillerPanel
javax.swing.JPanel leftFillerPanel