19 package org.sleuthkit.autopsy.timeline.actions;
21 import java.awt.Dialog;
22 import java.time.Instant;
23 import java.time.LocalDateTime;
24 import java.time.ZoneId;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.logging.Level;
29 import javafx.application.Platform;
30 import javafx.embed.swing.JFXPanel;
31 import javafx.fxml.FXML;
32 import javafx.scene.Scene;
33 import javafx.scene.control.Alert;
34 import javafx.scene.control.ButtonBase;
35 import javafx.scene.control.ButtonType;
36 import javafx.scene.control.ChoiceBox;
37 import javafx.scene.control.ComboBox;
38 import javafx.scene.control.DialogPane;
39 import javafx.scene.control.TextField;
40 import javafx.scene.image.Image;
41 import javafx.scene.image.ImageView;
42 import javafx.util.StringConverter;
43 import javax.swing.JDialog;
44 import javax.swing.SwingUtilities;
45 import jfxtras.scene.control.LocalDateTimeTextField;
46 import org.apache.commons.lang3.StringUtils;
47 import org.controlsfx.control.action.Action;
48 import org.controlsfx.control.textfield.TextFields;
49 import org.controlsfx.tools.ValueExtractor;
50 import org.controlsfx.validation.ValidationSupport;
51 import org.controlsfx.validation.Validator;
52 import org.openide.util.NbBundle;
75 "AddManualEvent.text=Add Event",
76 "AddManualEvent.longText=Manually add an event to the timeline."})
80 private static final String MANUAL_CREATION =
"Manual Creation";
81 private static final Image ADD_EVENT_IMAGE =
new Image(
"/org/sleuthkit/autopsy/timeline/images/add.png", 16, 16,
true,
true,
true);
88 ValueExtractor.addObservableValueExtractor(LocalDateTimeTextField.class::isInstance,
89 control -> ((LocalDateTimeTextField) control).localDateTimeProperty());
102 this(controller, null);
115 super(Bundle.AddManualEvent_text());
116 setGraphic(
new ImageView(ADD_EVENT_IMAGE));
117 setLongText(Bundle.AddManualEvent_longText());
119 setEventHandler(actionEvent -> SwingUtilities.invokeLater(() -> {
120 JEventCreationDialog dialog = new JEventCreationDialog(controller, epochMillis, SwingUtilities.windowForComponent(controller.getTopComponent()));
121 dialog.setVisible(true);
137 "AddManualEvent.createArtifactFailed=Failed to create artifact for event.",
138 "AddManualEvent.postArtifactFailed=Failed to post artifact to blackboard."})
145 List<BlackboardAttribute> attributes = Arrays.asList(
147 TSK_TL_EVENT_TYPE, source,
150 TSK_DESCRIPTION, source,
153 TSK_DATETIME, source,
162 logger.log(Level.SEVERE,
"Error posting artifact to the blackboard.", ex);
163 new Alert(Alert.AlertType.ERROR, Bundle.AddManualEvent_postArtifactFailed(), ButtonType.OK).showAndWait();
166 logger.log(Level.SEVERE,
"Error creatig new artifact.", ex);
167 new Alert(Alert.AlertType.ERROR, Bundle.AddManualEvent_createArtifactFailed(), ButtonType.OK).showAndWait();
177 private final JFXPanel jfxPanel =
new JFXPanel();
180 super(owner, Bundle.AddManualEvent_text(), Dialog.ModalityType.DOCUMENT_MODAL);
181 setIconImages(owner.getIconImages());
186 Platform.runLater(() -> {
190 ((ButtonBase) customPane.lookupButton(ButtonType.CANCEL)).setOnAction(event -> dispose());
192 ((ButtonBase) customPane.lookupButton(ButtonType.OK)).setOnAction(event -> {
194 if (manualEventInfo != null) {
195 addEvent(controller, manualEventInfo);
200 jfxPanel.setScene(
new Scene(customPane));
202 SwingUtilities.invokeLater(() -> {
205 setLocationRelativeTo(owner);
226 private final ValidationSupport validationSupport =
new ValidationSupport();
230 this.controller = controller;
232 if (epochMillis == null) {
233 timePicker.setLocalDateTime(LocalDateTime.now());
240 @NbBundle.Messages({
"# {0} - datasource name",
"# {1} - datasource id",
241 "AddManualEvent.EventCreationDialogPane.dataSourceStringConverter.template={0} (ID: {1})",
242 "AddManualEvent.EventCreationDialogPane.initialize.dataSourcesError=Error getting datasources in case."})
244 assert descriptionTextField != null :
"fx:id=\"descriptionTextField\" was not injected: check your FXML file 'EventCreationDialog.fxml'.";
246 timeZoneChooser.getItems().setAll(timeZoneList);
248 TextFields.bindAutoCompletion(timeZoneChooser.getEditor(), timeZoneList);
250 dataSourceChooser.setConverter(
new StringConverter<DataSource>() {
252 public String toString(
DataSource dataSource) {
253 return Bundle.AddManualEvent_EventCreationDialogPane_dataSourceStringConverter_template(dataSource.
getName(), dataSource.
getId());
258 throw new UnsupportedOperationException();
263 dataSourceChooser.getSelectionModel().select(0);
265 logger.log(Level.SEVERE,
"Error getting datasources in case.", ex);
266 SwingUtilities.invokeLater(() ->
MessageNotifyUtil.
Message.
error(Bundle.AddManualEvent_EventCreationDialogPane_initialize_dataSourcesError()));
274 "AddManualEvent.validation.description=Description is required.",
275 "AddManualEvent.validation.datetime=Invalid datetime",
276 "AddManualEvent.validation.timezone=Invalid time zone",})
278 validationSupport.registerValidator(descriptionTextField,
false,
279 Validator.createEmptyValidator(Bundle.AddManualEvent_validation_description()));
280 validationSupport.registerValidator(timePicker,
false,
281 Validator.createPredicateValidator(Objects::nonNull, Bundle.AddManualEvent_validation_description()));
282 validationSupport.registerValidator(timeZoneChooser,
false,
283 Validator.createPredicateValidator((String zone) -> timeZoneList.contains(zone.trim()), Bundle.AddManualEvent_validation_timezone()));
285 validationSupport.initInitialDecoration();
288 lookupButton(ButtonType.OK).disableProperty().bind(validationSupport.invalidProperty());
299 String zone = StringUtils.substringAfter(timeZoneChooser.getValue(),
")").trim();
300 long toEpochSecond = timePicker.getLocalDateTime().atZone(ZoneId.of(zone)).toEpochSecond();
301 return new ManualEventInfo(dataSourceChooser.getValue(), descriptionTextField.getText(), toEpochSecond);
316 this.datasource = datasource;
317 this.description = description;
JEventCreationDialog(TimeLineController controller, Long epochMillis, java.awt.Window owner)
TextField descriptionTextField
EventCreationDialogPane(TimeLineController controller, Long epochMillis)
void postArtifact(BlackboardArtifact artifact, String moduleName)
AddManualEvent(TimeLineController controller, Long epochMillis)
final TimeLineController controller
Blackboard getBlackboard()
ManualEventInfo(DataSource datasource, String description, long time)
static List< String > createTimeZoneList()
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
ManualEventInfo getManualEventInfo()
List< DataSource > getDataSources()
static TimeZone getTimeZone()
LocalDateTimeTextField timePicker
SleuthkitCase getSleuthkitCase()
TimelineEventType USER_CREATED
static ZoneId getTimeZoneID()
static String createTimeZoneString(TimeZone timeZone)
SleuthkitCase getSleuthkitCase()
ComboBox< String > timeZoneChooser
EventsModel getEventsModel()
Examiner getCurrentExaminer()
ChoiceBox< DataSource > dataSourceChooser
synchronized static Logger getLogger(String name)
AddManualEvent(TimeLineController controller)
static void construct(Node node, String fxmlFileName)
void addEvent(TimeLineController controller, ManualEventInfo eventInfo)
final DataSource datasource
static void error(String message)