19package org.sleuthkit.autopsy.timeline.actions;
21import java.awt.Dialog;
22import java.time.Instant;
23import java.time.LocalDateTime;
24import java.time.ZoneId;
25import java.util.Arrays;
27import java.util.Objects;
28import java.util.logging.Level;
29import javafx.application.Platform;
30import javafx.embed.swing.JFXPanel;
31import javafx.fxml.FXML;
32import javafx.scene.Scene;
33import javafx.scene.control.Alert;
34import javafx.scene.control.ButtonBase;
35import javafx.scene.control.ButtonType;
36import javafx.scene.control.ChoiceBox;
37import javafx.scene.control.ComboBox;
38import javafx.scene.control.DialogPane;
39import javafx.scene.control.TextField;
40import javafx.scene.image.Image;
41import javafx.scene.image.ImageView;
42import javafx.util.StringConverter;
43import javax.swing.JDialog;
44import javax.swing.SwingUtilities;
45import jfxtras.scene.control.LocalDateTimeTextField;
46import org.apache.commons.lang3.StringUtils;
47import org.controlsfx.control.action.Action;
48import org.controlsfx.control.textfield.TextFields;
49import org.controlsfx.tools.ValueExtractor;
50import org.controlsfx.validation.ValidationSupport;
51import org.controlsfx.validation.Validator;
52import org.openide.util.NbBundle;
53import org.sleuthkit.autopsy.coreutils.Logger;
54import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
55import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
56import org.sleuthkit.autopsy.timeline.FXMLConstructor;
57import org.sleuthkit.autopsy.timeline.TimeLineController;
58import org.sleuthkit.datamodel.Blackboard;
59import org.sleuthkit.datamodel.BlackboardArtifact;
60import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_TL_EVENT;
61import org.sleuthkit.datamodel.BlackboardAttribute;
62import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
63import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION;
64import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TL_EVENT_TYPE;
65import org.sleuthkit.datamodel.DataSource;
66import org.sleuthkit.datamodel.SleuthkitCase;
67import org.sleuthkit.datamodel.TskCoreException;
68import org.sleuthkit.datamodel.TimelineEventType;
75 "AddManualEvent.text=Add Event",
76 "AddManualEvent.longText=Manually add an event to the timeline."})
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());
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."})
144 String source =
MANUAL_CREATION +
": " + sleuthkitCase.getCurrentExaminer().getLoginName();
145 List<BlackboardAttribute> attributes = Arrays.asList(
146 new BlackboardAttribute(
147 TSK_TL_EVENT_TYPE, source,
148 TimelineEventType.USER_CREATED.getTypeID()),
149 new BlackboardAttribute(
150 TSK_DESCRIPTION, source,
152 new BlackboardAttribute(
153 TSK_DATETIME, source,
157 BlackboardArtifact artifact = eventInfo.
datasource.newDataArtifact(
new BlackboardArtifact.Type(TSK_TL_EVENT), attributes,
null);
160 sleuthkitCase.getBlackboard().postArtifact(artifact, source,
null);
161 }
catch (Blackboard.BlackboardException ex) {
162 logger.log(Level.SEVERE,
"Error posting artifact to the blackboard.", ex);
163 new Alert(Alert.AlertType.ERROR, Bundle.AddManualEvent_postArtifactFailed(), ButtonType.OK).showAndWait();
165 }
catch (TskCoreException ex) {
166 logger.log(Level.SEVERE,
"Error creatig new artifact.", ex);
167 new Alert(Alert.AlertType.ERROR, Bundle.AddManualEvent_createArtifactFailed(), ButtonType.OK).showAndWait();
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);
229 @SuppressWarnings(
"this-escape")
233 if (epochMillis ==
null) {
234 timePicker.setLocalDateTime(LocalDateTime.now());
241 @NbBundle.Messages({
"# {0} - datasource name",
"# {1} - datasource id",
242 "AddManualEvent.EventCreationDialogPane.dataSourceStringConverter.template={0} (ID: {1})",
243 "AddManualEvent.EventCreationDialogPane.initialize.dataSourcesError=Error getting datasources in case."})
245 assert
descriptionTextField != null :
"fx:id=\"descriptionTextField\" was not injected: check your FXML file 'EventCreationDialog.fxml'.";
253 public String toString(DataSource dataSource) {
254 return Bundle.AddManualEvent_EventCreationDialogPane_dataSourceStringConverter_template(dataSource.getName(), dataSource.getId());
258 public DataSource fromString(String
string) {
259 throw new UnsupportedOperationException();
265 }
catch (TskCoreException ex) {
266 logger.log(Level.SEVERE,
"Error getting datasources in case.", ex);
267 SwingUtilities.invokeLater(() ->
MessageNotifyUtil.
Message.
error(Bundle.AddManualEvent_EventCreationDialogPane_initialize_dataSourcesError()));
275 "AddManualEvent.validation.description=Description is required.",
276 "AddManualEvent.validation.datetime=Invalid datetime",
277 "AddManualEvent.validation.timezone=Invalid time zone",})
280 Validator.createEmptyValidator(Bundle.AddManualEvent_validation_description()));
282 Validator.createPredicateValidator(Objects::nonNull, Bundle.AddManualEvent_validation_description()));
284 Validator.createPredicateValidator((String zone) ->
timeZoneList.contains(zone.trim()), Bundle.AddManualEvent_validation_timezone()));
289 lookupButton(ButtonType.OK).disableProperty().bind(
validationSupport.invalidProperty());
300 String zone = StringUtils.substringAfter(
timeZoneChooser.getValue(),
")").trim();
301 long toEpochSecond =
timePicker.getLocalDateTime().atZone(ZoneId.of(zone)).toEpochSecond();
synchronized static Logger getLogger(String name)
static void error(String message)
static List< String > createTimeZoneList()
static String createTimeZoneString(TimeZone timeZone)
SleuthkitCase getSleuthkitCase()
static void construct(Node node, String fxmlFileName)
static TimeZone getTimeZone()
EventsModel getEventsModel()
static ZoneId getTimeZoneID()
final ValidationSupport validationSupport
EventCreationDialogPane(TimeLineController controller, Long epochMillis)
ChoiceBox< DataSource > dataSourceChooser
final List< String > timeZoneList
ManualEventInfo getManualEventInfo()
ComboBox< String > timeZoneChooser
final TimeLineController controller
TextField descriptionTextField
LocalDateTimeTextField timePicker
JEventCreationDialog(TimeLineController controller, Long epochMillis, java.awt.Window owner)
final DataSource datasource
ManualEventInfo(DataSource datasource, String description, long time)
AddManualEvent(TimeLineController controller, Long epochMillis)
static final Logger logger
static final String MANUAL_CREATION
static final Image ADD_EVENT_IMAGE
AddManualEvent(TimeLineController controller)
void addEvent(TimeLineController controller, ManualEventInfo eventInfo)