diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties-MERGED index 07655ceb1b..aac5f8beef 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties-MERGED @@ -32,12 +32,15 @@ SaveSnapShotAsReport.ErrorWritingReport=Error writing report to disk at {0}. SaveSnapShotAsReport.FailedToAddReport=Failed to add snaphot to case as a report. SaveSnapShotAsReport.reportName.header=Enter a report name for the Timeline Snapshot Report. # {0} - generated default report name -SaveSnapShotAsReport.reportName.prompt=leave empty for default report name: {0}. +SaveSnapShotAsReport.reportName.prompt=Leave empty for default report name:\n{0}. # {0} - report file path SaveSnapShotAsReport.ReportSavedAt=Report saved at [{0}] SaveSnapShotAsReport.Success=Success +SaveSnapShotAsReport_OK_Button=OK +SaveSnapShotAsReport_Open_Button=Open Report SaveSnapShotAsReport_Path_Failure_Report=Failed to create report. Supplied report name has invalid characters: {0} SaveSnapShotAsReport_Report_Failed=Report failed +SaveSnapShotAsReport_success_message=Snapshot report successfully created at location: \n\n {0} Timeline.ModuleName=Timeline ViewArtifactInTimelineAction.displayName=View Result in Timeline... ViewFileInTimelineAction.viewFile.displayName=View File in Timeline... diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java index c0ca0e72a5..c55c78256d 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -37,6 +37,7 @@ import javafx.scene.control.TextInputDialog; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import org.apache.commons.lang3.StringUtils; import org.controlsfx.control.HyperlinkLabel; import org.controlsfx.control.action.Action; @@ -50,6 +51,8 @@ import org.sleuthkit.autopsy.timeline.PromptDialogManager; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.snapshot.SnapShotReportWriter; import org.sleuthkit.datamodel.TskCoreException; +import javafx.application.Platform; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * Action that saves a snapshot of the given node as an autopsy report. @@ -82,11 +85,14 @@ public class SaveSnapshotAsReport extends Action { "# {0} - report path", "SaveSnapShotAsReport.ErrorWritingReport=Error writing report to disk at {0}.", "# {0} - generated default report name", - "SaveSnapShotAsReport.reportName.prompt=leave empty for default report name: {0}.", + "SaveSnapShotAsReport.reportName.prompt=Leave empty for default report name:\n{0}.", "SaveSnapShotAsReport.reportName.header=Enter a report name for the Timeline Snapshot Report.", "SaveSnapShotAsReport.duplicateReportNameError.text=A report with that name already exists.", "SaveSnapShotAsReport_Report_Failed=Report failed", - "SaveSnapShotAsReport_Path_Failure_Report=Failed to create report. Supplied report name has invalid characters: {0}" + "SaveSnapShotAsReport_Path_Failure_Report=Failed to create report. Supplied report name has invalid characters: {0}", + "SaveSnapShotAsReport_success_message=Snapshot report successfully created at location: \n\n {0}", + "SaveSnapShotAsReport_Open_Button=Open Report", + "SaveSnapShotAsReport_OK_Button=OK" }) public SaveSnapshotAsReport(TimeLineController controller, Supplier nodeSupplier) { super(Bundle.SaveSnapShotAsReport_action_name_text()); @@ -100,71 +106,71 @@ public class SaveSnapshotAsReport extends Action { Date generationDate = new Date(); final String defaultReportName = FileUtil.escapeFileName(currentCase.getDisplayName() + " " + new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss").format(generationDate)); //NON_NLS BufferedImage snapshot = SwingFXUtils.fromFXImage(nodeSupplier.get().snapshot(null, null), null); - - //prompt user to pick report name - TextInputDialog textInputDialog = new TextInputDialog(); - PromptDialogManager.setDialogIcons(textInputDialog); - textInputDialog.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title()); - textInputDialog.getEditor().setPromptText(Bundle.SaveSnapShotAsReport_reportName_prompt(defaultReportName)); - textInputDialog.setHeaderText(Bundle.SaveSnapShotAsReport_reportName_header()); - - //keep prompt even if text field has focus, until user starts typing. - textInputDialog.getEditor().setStyle("-fx-prompt-text-fill: derive(-fx-control-inner-background, -30%);");//NON_NLS - - //show dialog and handle result - textInputDialog.showAndWait().ifPresent(enteredReportName -> { - //reportName defaults to case name + timestamp if left blank - String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName); - Path reportFolderPath; - try{ - reportFolderPath = Paths.get(currentCase.getReportDirectory(), reportName, "Timeline Snapshot"); - } catch(InvalidPathException ex) { - //notify user of report location - final Alert alert = new Alert(Alert.AlertType.ERROR, null, OK); - alert.setTitle(Bundle.SaveSnapShotAsReport_Report_Failed()); - alert.setHeaderText(Bundle.SaveSnapShotAsReport_Path_Failure_Report(reportName)); - alert.show(); - return; - } - Path reportMainFilePath; - - try { - //generate and write report - reportMainFilePath = new SnapShotReportWriter(currentCase, - reportFolderPath, - reportName, - controller.getEventsModel().getZoomState(), - generationDate, snapshot).writeReport(); - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, "Error writing report to disk at " + reportFolderPath, ex); //NON_NLS - new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_ErrorWritingReport(reportFolderPath)).show(); - return; - } - - try { - //add main file as report to case - Case.getCurrentCaseThrows().addReport(reportMainFilePath.toString(), Bundle.Timeline_ModuleName(), reportName); - } catch (TskCoreException | NoCurrentCaseException ex) { - LOGGER.log(Level.WARNING, "Failed to add " + reportMainFilePath.toString() + " to case as a report", ex); //NON_NLS - new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_FailedToAddReport()).show(); - return; - } - - //notify user of report location - final Alert alert = new Alert(Alert.AlertType.INFORMATION, null, OPEN, OK); - alert.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title()); - alert.setHeaderText(Bundle.SaveSnapShotAsReport_Success()); - - //make action to open report, and hyperlinklable to invoke action - final OpenReportAction openReportAction = new OpenReportAction(reportMainFilePath); - HyperlinkLabel hyperlinkLabel = new HyperlinkLabel(Bundle.SaveSnapShotAsReport_ReportSavedAt(reportMainFilePath.toString())); - hyperlinkLabel.setOnAction(openReportAction); - alert.getDialogPane().setContent(hyperlinkLabel); - - alert.showAndWait().filter(OPEN::equals).ifPresent(buttonType -> openReportAction.handle(null)); + + SwingUtilities.invokeLater(() ->{ + String message = String.format("%s\n\n%s", Bundle.SaveSnapShotAsReport_reportName_header(), Bundle.SaveSnapShotAsReport_reportName_prompt(defaultReportName)); + + String reportName = JOptionPane.showInputDialog(SwingUtilities.windowForComponent(controller.getTopComponent()), message, + Bundle.SaveSnapShotAsReport_action_dialogs_title(), JOptionPane.QUESTION_MESSAGE); + + reportName = StringUtils.defaultIfBlank(reportName, defaultReportName); + + createReport(controller, reportName, generationDate, snapshot); }); }); } + + + private void createReport(TimeLineController controller, String reportName, Date generationDate, BufferedImage snapshot) { + Path reportFolderPath; + try { + reportFolderPath = Paths.get(currentCase.getReportDirectory(), reportName, "Timeline Snapshot"); + } catch (InvalidPathException ex) { + //notify user of report location + final Alert alert = new Alert(Alert.AlertType.ERROR, null, OK); + alert.setTitle(Bundle.SaveSnapShotAsReport_Report_Failed()); + alert.setHeaderText(Bundle.SaveSnapShotAsReport_Path_Failure_Report(reportName)); + alert.show(); + return; + } + Path reportMainFilePath; + + try { + //generate and write report + reportMainFilePath = new SnapShotReportWriter(currentCase, + reportFolderPath, + reportName, + controller.getEventsModel().getZoomState(), + generationDate, snapshot).writeReport(); + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, "Error writing report to disk at " + reportFolderPath, ex); //NON_NLS + MessageNotifyUtil.Message.error( Bundle.SaveSnapShotAsReport_ErrorWritingReport(reportFolderPath)); + return; + } + + try { + //add main file as report to case + Case.getCurrentCaseThrows().addReport(reportMainFilePath.toString(), Bundle.Timeline_ModuleName(), reportName); + } catch (TskCoreException | NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Failed to add " + reportMainFilePath.toString() + " to case as a report", ex); //NON_NLS + MessageNotifyUtil.Message.error(Bundle.SaveSnapShotAsReport_FailedToAddReport()); + return; + } + + Object[] options = { Bundle.SaveSnapShotAsReport_Open_Button(), + Bundle.SaveSnapShotAsReport_OK_Button()}; + + int result = JOptionPane.showOptionDialog(SwingUtilities.windowForComponent(controller.getTopComponent()), + Bundle.SaveSnapShotAsReport_success_message(reportMainFilePath), + Bundle.SaveSnapShotAsReport_action_dialogs_title(), + JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, + options, options[0]); + + if(result == 0) { + final OpenReportAction openReportAction = new OpenReportAction(reportMainFilePath); + openReportAction.handle(null); + } + } /** * Action that opens the given Path in the system default application.