19 package org.sleuthkit.autopsy.timeline;
21 import java.beans.PropertyVetoException;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.logging.Level;
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.TopComponent;
51 import static org.openide.windows.TopComponent.PROP_UNDOCKING_DISABLED;
52 import org.openide.windows.WindowManager;
74 @TopComponent.Description(
75 preferredID =
"TimeLineTopComponent",
77 persistenceType = TopComponent.PERSISTENCE_NEVER)
78 @TopComponent.Registration(mode =
"timeline", openAtStartup =
false)
90 private final ExplorerManager
em = new ExplorerManager();
98 @NbBundle.Messages({
"TimelineTopComponent.selectedEventListener.errorMsg=There was a problem getting the content for the selected event."})
101 public void invalidated(Observable observable) {
111 for (
int i = 0; i < selectedEventIDs.size(); i++) {
114 Children children =
new Children.Array();
115 children.add(childArray);
117 SwingUtilities.invokeLater(() -> {
119 em.setRootContext(
new AbstractNode(children));
122 em.setSelectedNodes(childArray);
123 }
catch (PropertyVetoException ex) {
125 LOGGER.log(Level.SEVERE,
"Selecting the event node was vetoed.", ex);
128 if (childArray.length == 1) {
134 }
catch (IllegalStateException ex) {
136 LOGGER.log(Level.SEVERE,
"There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex);
137 }
catch (TskCoreException ex) {
138 LOGGER.log(Level.SEVERE,
"Failed to lookup Sleuthkit object backing a SingleEvent.", ex);
139 Platform.runLater(() -> {
140 Notifications.create()
142 .text(Bundle.TimelineTopComponent_selectedEventListener_errorMsg())
152 SwingUtilities.invokeLater(() -> {
171 SwingUtilities.invokeLater(() -> {
184 SwingUtilities.invokeLater(() -> {
200 associateLookup(ExplorerUtils.createLookup(
em, getActionMap()));
203 setIcon(WindowManager.getDefault().getMainWindow().getIconImage());
220 Platform.runLater(this::initFXComponents);
235 "TimeLineTopComponent.eventsTab.name=Events",
236 "TimeLineTopComponent.filterTab.name=Filters"})
237 @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
238 void initFXComponents() {
240 final TimeZonePanel timeZonePanel =
new TimeZonePanel();
241 VBox.setVgrow(timeZonePanel, Priority.SOMETIMES);
242 HistoryToolBar historyToolBar =
new HistoryToolBar(
controller);
243 final ZoomSettingsPane zoomSettingsPane =
new ZoomSettingsPane(
controller);
246 final Tab filterTab =
new Tab(Bundle.TimeLineTopComponent_filterTab_name(),
new FilterSetPanel(
controller));
247 filterTab.setClosable(
false);
248 filterTab.setGraphic(
new ImageView(
"org/sleuthkit/autopsy/timeline/images/funnel.png"));
251 final EventsTree eventsTree =
new EventsTree(
controller);
252 final Tab eventsTreeTab =
new Tab(Bundle.TimeLineTopComponent_eventsTab_name(), eventsTree);
253 eventsTreeTab.setClosable(
false);
254 eventsTreeTab.setGraphic(
new ImageView(
"org/sleuthkit/autopsy/timeline/images/timeline_marker.png"));
257 final TabPane leftTabPane =
new TabPane(filterTab, eventsTreeTab);
258 VBox.setVgrow(leftTabPane, Priority.ALWAYS);
262 leftTabPane.getSelectionModel().select(filterTab);
267 final VBox leftVBox =
new VBox(5, timeZonePanel, historyToolBar, zoomSettingsPane, leftTabPane);
268 SplitPane.setResizableWithParent(leftVBox, Boolean.FALSE);
270 final ViewFrame viewFrame =
new ViewFrame(
controller, eventsTree);
271 final SplitPane mainSplitPane =
new SplitPane(leftVBox, viewFrame);
272 mainSplitPane.setDividerPositions(0);
274 final Scene scene =
new Scene(mainSplitPane);
275 scene.addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> {
276 if (new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
277 new Back(controller).handle(null);
278 }
else if (
new KeyCodeCombination(KeyCode.BACK_SPACE).match(keyEvent)) {
280 }
else if (
new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN).match(keyEvent)) {
282 }
else if (
new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCodeCombination.SHIFT_DOWN).match(keyEvent)) {
294 return Collections.emptyList();
305 jFXstatusPanel =
new javafx.embed.swing.JFXPanel();
306 splitYPane =
new javax.swing.JSplitPane();
307 jFXViewPanel =
new javafx.embed.swing.JFXPanel();
308 horizontalSplitPane =
new javax.swing.JSplitPane();
309 leftFillerPanel =
new javax.swing.JPanel();
310 rightfillerPanel =
new javax.swing.JPanel();
312 jFXstatusPanel.setPreferredSize(
new java.awt.Dimension(100, 16));
314 splitYPane.setDividerLocation(420);
315 splitYPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
316 splitYPane.setResizeWeight(0.9);
317 splitYPane.setPreferredSize(
new java.awt.Dimension(1024, 400));
318 splitYPane.setLeftComponent(jFXViewPanel);
320 horizontalSplitPane.setDividerLocation(600);
321 horizontalSplitPane.setResizeWeight(0.5);
322 horizontalSplitPane.setPreferredSize(
new java.awt.Dimension(1200, 300));
323 horizontalSplitPane.setRequestFocusEnabled(
false);
325 javax.swing.GroupLayout leftFillerPanelLayout =
new javax.swing.GroupLayout(leftFillerPanel);
326 leftFillerPanel.setLayout(leftFillerPanelLayout);
327 leftFillerPanelLayout.setHorizontalGroup(
328 leftFillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
329 .addGap(0, 599, Short.MAX_VALUE)
331 leftFillerPanelLayout.setVerticalGroup(
332 leftFillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
333 .addGap(0, 54, Short.MAX_VALUE)
336 horizontalSplitPane.setLeftComponent(leftFillerPanel);
338 javax.swing.GroupLayout rightfillerPanelLayout =
new javax.swing.GroupLayout(rightfillerPanel);
339 rightfillerPanel.setLayout(rightfillerPanelLayout);
340 rightfillerPanelLayout.setHorizontalGroup(
341 rightfillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
342 .addGap(0, 364, Short.MAX_VALUE)
344 rightfillerPanelLayout.setVerticalGroup(
345 rightfillerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
346 .addGap(0, 54, Short.MAX_VALUE)
349 horizontalSplitPane.setRightComponent(rightfillerPanel);
351 splitYPane.setRightComponent(horizontalSplitPane);
353 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
354 this.setLayout(layout);
355 layout.setHorizontalGroup(
356 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
357 .addComponent(splitYPane, javax.swing.GroupLayout.DEFAULT_SIZE, 972, Short.MAX_VALUE)
358 .addComponent(jFXstatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
360 layout.setVerticalGroup(
361 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
362 .addGroup(layout.createSequentialGroup()
363 .addComponent(splitYPane, javax.swing.GroupLayout.DEFAULT_SIZE, 482, Short.MAX_VALUE)
365 .addComponent(jFXstatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE))
380 WindowManager.getDefault().setTopComponentFloating(
this,
true);
381 putClientProperty(PROP_UNDOCKING_DISABLED,
true);
396 "# {0} - start of date range",
397 "# {1} - end of date range",
398 "TimeLineResultView.startDateToEndDate.text={0} to {1}"})
400 Interval selectedTimeRange = controller.getSelectedTimeRange();
401 if (selectedTimeRange == null) {
405 String start = selectedTimeRange.getStart()
407 .toString(zonedFormatter);
408 String end = selectedTimeRange.getEnd()
410 .toString(zonedFormatter);
411 return Bundle.TimeLineResultView_startDateToEndDate_text(start, end);
TimeLineTopComponent(TimeLineController controller)
final InvalidationListener selectedEventsListener
static final KeyStroke BOOKMARK_SHORTCUT
FilteredEventsModel getEventsModel()
static EventNode createEventNode(final Long eventID, FilteredEventsModel eventsModel)
void setNode(Node selectedNode)
synchronized ViewMode getViewMode()
static ReadOnlyObjectProperty< TimeZone > getTimeZone()
DataResultPanel dataResultPanel
String getResultViewerSummaryString()
static final Logger LOGGER
static DataResultPanel createInstanceUninitialized(String title, String pathText, Node givenNode, int totalMatches, DataContent dataContent)
final TimeLineController controller
javafx.embed.swing.JFXPanel jFXstatusPanel
void setNode(Node selectedNode)
final DataContentPanel contentViewerPanel
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()
void setPath(String pathText)
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