add right click menu option to add event with datetime prepopulated;

other small cleanup and refactoring
This commit is contained in:
millmanorama 2019-03-05 16:30:52 +01:00
parent 397f9694ee
commit aecc229345
10 changed files with 36 additions and 18 deletions

View File

@ -23,6 +23,7 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.Collection; import java.util.Collection;
@ -32,6 +33,7 @@ import java.util.Optional;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.Observable; import javafx.beans.Observable;
@ -116,7 +118,8 @@ public class TimeLineController {
private static final ReadOnlyObjectWrapper<TimeZone> timeZone = new ReadOnlyObjectWrapper<>(TimeZone.getDefault()); private static final ReadOnlyObjectWrapper<TimeZone> timeZone = new ReadOnlyObjectWrapper<>(TimeZone.getDefault());
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder().setNameFormat("Timeline Controller BG thread").build()));
private final ReadOnlyListWrapper<Task<?>> tasks = new ReadOnlyListWrapper<>(FXCollections.observableArrayList()); private final ReadOnlyListWrapper<Task<?>> tasks = new ReadOnlyListWrapper<>(FXCollections.observableArrayList());
private final ReadOnlyDoubleWrapper taskProgress = new ReadOnlyDoubleWrapper(-1); private final ReadOnlyDoubleWrapper taskProgress = new ReadOnlyDoubleWrapper(-1);
private final ReadOnlyStringWrapper taskMessage = new ReadOnlyStringWrapper(); private final ReadOnlyStringWrapper taskMessage = new ReadOnlyStringWrapper();
@ -134,13 +137,17 @@ public class TimeLineController {
} }
public static DateTimeZone getJodaTimeZone() { public static DateTimeZone getJodaTimeZone() {
return DateTimeZone.forTimeZone(getTimeZone().get()); return DateTimeZone.forTimeZone(timeZoneProperty().get());
} }
public static ReadOnlyObjectProperty<TimeZone> getTimeZone() { public static ReadOnlyObjectProperty<TimeZone> timeZoneProperty() {
return timeZone.getReadOnlyProperty(); return timeZone.getReadOnlyProperty();
} }
public static TimeZone getTimeZone() {
return timeZone.get();
}
/** /**
* Status is a string that will be displayed in the status bar as a kind of * Status is a string that will be displayed in the status bar as a kind of
* user hint/information when it is not empty * user hint/information when it is not empty

View File

@ -281,7 +281,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
Platform.runLater(this::initFXComponents); Platform.runLater(this::initFXComponents);
//set up listeners //set up listeners
TimeLineController.getTimeZone().addListener(timeZone -> dataResultPanel.setPath(getResultViewerSummaryString())); TimeLineController.timeZoneProperty().addListener(timeZone -> dataResultPanel.setPath(getResultViewerSummaryString()));
controller.getSelectedEventIDs().addListener(selectedEventsListener); controller.getSelectedEventIDs().addListener(selectedEventsListener);
//Listen to ViewMode and adjust GUI componenets as needed. //Listen to ViewMode and adjust GUI componenets as needed.

View File

@ -18,8 +18,10 @@
*/ */
package org.sleuthkit.autopsy.timeline.actions; package org.sleuthkit.autopsy.timeline.actions;
import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -88,6 +90,10 @@ public class AddManualEvent extends Action {
"CreateManualEvent.text=Add Event", "CreateManualEvent.text=Add Event",
"CreateManualEvent.longText=Manually add an event to the timeline."}) "CreateManualEvent.longText=Manually add an event to the timeline."})
public AddManualEvent(TimeLineController controller) { public AddManualEvent(TimeLineController controller) {
this(controller, System.currentTimeMillis());
}
public AddManualEvent(TimeLineController controller, long epochMillis) {
super(Bundle.CreateManualEvent_text()); super(Bundle.CreateManualEvent_text());
this.controller = controller; this.controller = controller;
setGraphic(new ImageView(ADD_EVENT_IMAGE)); setGraphic(new ImageView(ADD_EVENT_IMAGE));
@ -95,7 +101,7 @@ public class AddManualEvent extends Action {
setEventHandler(actionEvent -> { setEventHandler(actionEvent -> {
//shoe the dialog and if it completed normally add the event. //shoe the dialog and if it completed normally add the event.
new EventCreationDialog(controller).showAndWait().ifPresent(this::addEvent); new EventCreationDialog(controller, epochMillis).showAndWait().ifPresent(this::addEvent);
}); });
} }
@ -147,8 +153,8 @@ public class AddManualEvent extends Action {
*/ */
private final EventCreationDialogPane eventCreationDialogPane; private final EventCreationDialogPane eventCreationDialogPane;
EventCreationDialog(TimeLineController controller) { EventCreationDialog(TimeLineController controller, long epochMillis) {
this.eventCreationDialogPane = new EventCreationDialogPane(controller); this.eventCreationDialogPane = new EventCreationDialogPane(controller, epochMillis);
setTitle("Add Event"); setTitle("Add Event");
setDialogPane(eventCreationDialogPane); setDialogPane(eventCreationDialogPane);
@ -187,9 +193,10 @@ public class AddManualEvent extends Action {
private final ValidationSupport validationSupport = new ValidationSupport(); private final ValidationSupport validationSupport = new ValidationSupport();
private final TimeLineController controller; private final TimeLineController controller;
EventCreationDialogPane(TimeLineController controller) { EventCreationDialogPane(TimeLineController controller, long epochMillis) {
this.controller = controller; this.controller = controller;
FXMLConstructor.construct(this, "EventCreationDialog.fxml"); FXMLConstructor.construct(this, "EventCreationDialog.fxml");
timePicker.setLocalDateTime( LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis) , TimeLineController.getTimeZoneID()));
} }
@FXML @FXML
@ -198,11 +205,9 @@ public class AddManualEvent extends Action {
assert descriptionTextField != null : "fx:id=\"descriptionTextField\" was not injected: check your FXML file 'EventCreationDialog.fxml'."; assert descriptionTextField != null : "fx:id=\"descriptionTextField\" was not injected: check your FXML file 'EventCreationDialog.fxml'.";
timeZoneChooser.getItems().setAll(timeZoneList); timeZoneChooser.getItems().setAll(timeZoneList);
timeZoneChooser.getSelectionModel().select(TimeZoneUtils.createTimeZoneString(TimeZone.getDefault())); timeZoneChooser.getSelectionModel().select(TimeZoneUtils.createTimeZoneString(TimeLineController.getTimeZone()));
TextFields.bindAutoCompletion(timeZoneChooser.getEditor(), timeZoneList); TextFields.bindAutoCompletion(timeZoneChooser.getEditor(), timeZoneList);
timePicker.setLocalDateTime(LocalDateTime.now());
try { try {
dataSourceChooser.getItems().setAll(controller.getAutopsyCase().getSleuthkitCase().getDataSources()); dataSourceChooser.getItems().setAll(controller.getAutopsyCase().getSleuthkitCase().getDataSources());
dataSourceChooser.getSelectionModel().select(0); dataSourceChooser.getSelectionModel().select(0);

View File

@ -184,7 +184,7 @@ public class EventNode extends DisplayableItemNode {
super(name, String.class, displayName, shortDescription); super(name, String.class, displayName, shortDescription);
setValue("suppressCustomEditor", Boolean.TRUE); // remove the "..." (editing) button NON-NLS setValue("suppressCustomEditor", Boolean.TRUE); // remove the "..." (editing) button NON-NLS
this.value = value; this.value = value;
TimeLineController.getTimeZone().addListener(timeZone -> { TimeLineController.timeZoneProperty().addListener(timeZone -> {
try { try {
setValue(getDateTimeString()); setValue(getDateTimeString());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {

View File

@ -87,7 +87,7 @@ public abstract class AbstractTimeLineView extends BorderPane {
this.filteredEvents = controller.getEventsModel(); this.filteredEvents = controller.getEventsModel();
this.filteredEvents.registerForEvents(this); this.filteredEvents.registerForEvents(this);
this.filteredEvents.zoomStateProperty().addListener(updateListener); this.filteredEvents.zoomStateProperty().addListener(updateListener);
TimeLineController.getTimeZone().addListener(updateListener); TimeLineController.timeZoneProperty().addListener(updateListener);
} }
/** /**
@ -225,7 +225,7 @@ public abstract class AbstractTimeLineView extends BorderPane {
} }
//remvoe and gc updateListener //remvoe and gc updateListener
this.filteredEvents.zoomStateProperty().removeListener(updateListener); this.filteredEvents.zoomStateProperty().removeListener(updateListener);
TimeLineController.getTimeZone().removeListener(updateListener); TimeLineController.timeZoneProperty().removeListener(updateListener);
updateListener = null; updateListener = null;
filteredEvents.unRegisterForEvents(this); filteredEvents.unRegisterForEvents(this);
controller.unRegisterForEvents(this); controller.unRegisterForEvents(this);

View File

@ -293,8 +293,8 @@ public abstract class IntervalSelector<X> extends BorderPane {
return getValueForDisplay(getBoundsInParent().getMinX()); return getValueForDisplay(getBoundsInParent().getMinX());
} }
private X getValueForDisplay(final double display) { private X getValueForDisplay(final double displayX) {
return chart.getXAxis().getValueForDisplay(chart.getXAxis().parentToLocal(display, 0).getX()); return chart.getXAxis().getValueForDisplay(chart.getXAxis().parentToLocal(displayX, 0).getX());
} }
/** /**

View File

@ -68,6 +68,7 @@ public interface TimeLineChart<X> extends ContextMenuProvider, IntervalSelectorP
@Override @Override
public TimeLineController getController(); public TimeLineController getController();
/** /**
* Drag handler class used by TimeLineCharts to create IntervalSelectors * Drag handler class used by TimeLineCharts to create IntervalSelectors
* *

View File

@ -424,7 +424,7 @@ final public class ViewFrame extends BorderPane {
filteredEvents.registerForEvents(this); filteredEvents.registerForEvents(this);
//listen for changes in the time range / zoom params //listen for changes in the time range / zoom params
TimeLineController.getTimeZone().addListener(timeZoneProp -> refreshTimeUI()); TimeLineController.timeZoneProperty().addListener(timeZoneProp -> refreshTimeUI());
filteredEvents.timeRangeProperty().addListener(timeRangeProp -> refreshTimeUI()); filteredEvents.timeRangeProperty().addListener(timeRangeProp -> refreshTimeUI());
filteredEvents.zoomStateProperty().addListener(zoomListener); filteredEvents.zoomStateProperty().addListener(zoomListener);
refreshTimeUI(); //populate the view refreshTimeUI(); //populate the view

View File

@ -395,7 +395,7 @@ final public class DetailViewPane extends AbstractTimelineChart<DateTime, EventS
ZoomState newZoom = eventsModel.getZoomState(); ZoomState newZoom = eventsModel.getZoomState();
//if the ZoomState haven't actually changed, just bail //if the ZoomState haven't actually changed, just bail
if (Objects.equals(currentZoom, newZoom)) { if (needsRefresh() == false && Objects.equals(currentZoom, newZoom)) {
return true; return true;
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.sleuthkit.autopsy.timeline.ui.detailview; package org.sleuthkit.autopsy.timeline.ui.detailview;
import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -45,6 +46,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.timeline.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.actions.AddManualEvent;
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.ui.detailview.datamodel.DetailViewEvent; import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailViewEvent;
@ -276,9 +278,12 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
contextMenu.hide(); contextMenu.hide();
} }
long selectedTimeMillis = getXAxis().getValueForDisplay(getXAxis().parentToLocal(mouseEvent.getX(), 0).getX()).getMillis();
//make and assign a new context menu based on the given mouseEvent //make and assign a new context menu based on the given mouseEvent
setContextMenu(ActionUtils.createContextMenu(Arrays.asList( setContextMenu(ActionUtils.createContextMenu(Arrays.asList(
new PlaceMarkerAction(this, mouseEvent), new PlaceMarkerAction(this, mouseEvent),
new AddManualEvent(controller, selectedTimeMillis),
ActionUtils.ACTION_SEPARATOR, ActionUtils.ACTION_SEPARATOR,
TimeLineChart.newZoomHistoyActionGroup(getController()) TimeLineChart.newZoomHistoyActionGroup(getController())
))); )));