19 package org.sleuthkit.autopsy.timeline.actions;
 
   21 import java.awt.Desktop;
 
   22 import java.awt.image.BufferedImage;
 
   23 import java.io.IOException;
 
   24 import java.nio.file.Files;
 
   25 import java.nio.file.Path;
 
   26 import java.nio.file.Paths;
 
   27 import java.text.SimpleDateFormat;
 
   28 import java.util.Date;
 
   29 import java.util.function.Supplier;
 
   30 import java.util.logging.Level;
 
   31 import javafx.embed.swing.SwingFXUtils;
 
   32 import javafx.scene.Node;
 
   33 import javafx.scene.control.Alert;
 
   34 import javafx.scene.control.ButtonBar;
 
   35 import javafx.scene.control.ButtonType;
 
   36 import javafx.scene.control.Control;
 
   37 import javafx.scene.control.TextInputDialog;
 
   38 import javafx.scene.image.Image;
 
   39 import javafx.scene.image.ImageView;
 
   40 import javax.swing.JOptionPane;
 
   41 import org.apache.commons.lang3.StringUtils;
 
   42 import org.controlsfx.control.HyperlinkLabel;
 
   43 import org.controlsfx.control.action.Action;
 
   44 import org.controlsfx.validation.ValidationResult;
 
   45 import org.controlsfx.validation.ValidationSupport;
 
   46 import org.controlsfx.validation.Validator;
 
   47 import org.openide.util.NbBundle;
 
   63     private static final Image 
SNAP_SHOT = 
new Image(
"org/sleuthkit/autopsy/timeline/images/image.png", 16, 16, 
true, 
true); 
 
   64     private static final ButtonType 
OPEN = 
new ButtonType(Bundle.OpenReportAction_DisplayName(), ButtonBar.ButtonData.NO);
 
   65     private static final ButtonType 
OK = 
new ButtonType(ButtonType.OK.getText(), ButtonBar.ButtonData.CANCEL_CLOSE);
 
   77         "Timeline.ModuleName=Timeline",
 
   78         "SaveSnapShotAsReport.action.dialogs.title=Timeline",
 
   79         "SaveSnapShotAsReport.action.name.text=Snapshot Report",
 
   80         "SaveSnapShotAsReport.action.longText=Save a screen capture of the current view of the timeline as a report.",
 
   81         "# {0} - report file path",
 
   82         "SaveSnapShotAsReport.ReportSavedAt=Report saved at [{0}]",
 
   83         "SaveSnapShotAsReport.Success=Success",
 
   84         "SaveSnapShotAsReport.FailedToAddReport=Failed to add snaphot to case as a report.",
 
   85         "# {0} - report path",
 
   86         "SaveSnapShotAsReport.ErrorWritingReport=Error writing report to disk at {0}.",
 
   87         "# {0} - generated default report name",
 
   88         "SaveSnapShotAsReport.reportName.prompt=leave empty for default report name: {0}.",
 
   89         "SaveSnapShotAsReport.reportName.header=Enter a report name for the Timeline Snapshot Report.",
 
   90         "SaveSnapShotAsReport.duplicateReportNameError.text=A report with that name already exists." 
   93         super(Bundle.SaveSnapShotAsReport_action_name_text());
 
   94         setLongText(Bundle.SaveSnapShotAsReport_action_longText());
 
   95         setGraphic(
new ImageView(SNAP_SHOT));
 
  100         setEventHandler(actionEvent -> {
 
  102             Date generationDate = 
new Date();
 
  104             BufferedImage snapshot = SwingFXUtils.fromFXImage(nodeSupplier.get().snapshot(null, null), null);
 
  107             TextInputDialog textInputDialog = 
new TextInputDialog();
 
  109             textInputDialog.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title());
 
  110             textInputDialog.getEditor().setPromptText(Bundle.SaveSnapShotAsReport_reportName_prompt(defaultReportName));
 
  111             textInputDialog.setHeaderText(Bundle.SaveSnapShotAsReport_reportName_header());
 
  114             textInputDialog.getEditor().setStyle(
"-fx-prompt-text-fill: derive(-fx-control-inner-background, -30%);");
 
  121             ValidationSupport validationSupport = 
new ValidationSupport();
 
  122             validationSupport.registerValidator(textInputDialog.getEditor(), 
false, 
new Validator<String>() {
 
  124                 public ValidationResult apply(Control textField, String enteredReportName) {
 
  125                     String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
 
  126                     boolean exists = Files.exists(Paths.get(currentCase.
getReportDirectory(), reportName));
 
  127                     return ValidationResult.fromErrorIf(textField, Bundle.SaveSnapShotAsReport_duplicateReportNameError_text(), exists);
 
  130             textInputDialog.getDialogPane().lookupButton(ButtonType.OK).disableProperty().bind(validationSupport.invalidProperty());
 
  133             textInputDialog.showAndWait().ifPresent(enteredReportName -> {
 
  135                 String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
 
  136                 Path reportFolderPath = Paths.get(currentCase.
getReportDirectory(), reportName, 
"Timeline Snapshot"); 
 
  137                 Path reportMainFilePath;
 
  145                             generationDate, snapshot).writeReport();
 
  146                 } 
catch (IOException ex) {
 
  147                     LOGGER.log(Level.SEVERE, 
"Error writing report to disk at " + reportFolderPath, ex); 
 
  148                     new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_ErrorWritingReport(reportFolderPath)).show();
 
  155                 } 
catch (TskCoreException ex) {
 
  156                     LOGGER.log(Level.WARNING, 
"Failed to add " + reportMainFilePath.toString() + 
" to case as a report", ex); 
 
  157                     new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_FailedToAddReport()).show();
 
  162                 final Alert alert = 
new Alert(Alert.AlertType.INFORMATION, null, OPEN, OK);
 
  163                 alert.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title());
 
  164                 alert.setHeaderText(Bundle.SaveSnapShotAsReport_Success());
 
  168                 HyperlinkLabel hyperlinkLabel = 
new HyperlinkLabel(Bundle.SaveSnapShotAsReport_ReportSavedAt(reportMainFilePath.toString()));
 
  169                 hyperlinkLabel.setOnAction(openReportAction);
 
  170                 alert.getDialogPane().setContent(hyperlinkLabel);
 
  172                 alert.showAndWait().filter(OPEN::equals).ifPresent(buttonType -> openReportAction.handle(null));
 
  181         "OpenReportAction.DisplayName=Open Report",
 
  182         "OpenReportAction.NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.",
 
  183         "OpenReportAction.MessageBoxTitle=Open Report Failure",
 
  184         "OpenReportAction.NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.",
 
  185         "OpenReportAction.MissingReportFileMessage=The report file no longer exists.",
 
  186         "OpenReportAction.ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied."})
 
  190             super(Bundle.OpenReportAction_DisplayName());
 
  191             setEventHandler(actionEvent -> {
 
  193                     Desktop.getDesktop().open(reportHTMLFIle.toFile());
 
  194                 } 
catch (IOException ex) {
 
  195                     JOptionPane.showMessageDialog(null,
 
  196                             Bundle.OpenReportAction_NoAssociatedEditorMessage(),
 
  197                             Bundle.OpenReportAction_MessageBoxTitle(),
 
  198                             JOptionPane.ERROR_MESSAGE);
 
  199                 } 
catch (UnsupportedOperationException ex) {
 
  200                     JOptionPane.showMessageDialog(null,
 
  201                             Bundle.OpenReportAction_NoOpenInEditorSupportMessage(),
 
  202                             Bundle.OpenReportAction_MessageBoxTitle(),
 
  203                             JOptionPane.ERROR_MESSAGE);
 
  204                 } 
catch (IllegalArgumentException ex) {
 
  205                     JOptionPane.showMessageDialog(null,
 
  206                             Bundle.OpenReportAction_MissingReportFileMessage(),
 
  207                             Bundle.OpenReportAction_MessageBoxTitle(),
 
  208                             JOptionPane.ERROR_MESSAGE);
 
  209                 } 
catch (SecurityException ex) {
 
  210                     JOptionPane.showMessageDialog(null,
 
  211                             Bundle.OpenReportAction_ReportFileOpenPermissionDeniedMessage(),
 
  212                             Bundle.OpenReportAction_MessageBoxTitle(),
 
  213                             JOptionPane.ERROR_MESSAGE);
 
static final Logger LOGGER
FilteredEventsModel getEventsModel()
static final Image SNAP_SHOT
static final ButtonType OPEN
String getReportDirectory()
void addReport(String localPath, String srcModuleName, String reportName)
SaveSnapshotAsReport(TimeLineController controller, Supplier< Node > nodeSupplier)
final TimeLineController controller
synchronized ZoomParams getZoomParamaters()
static String escapeFileName(String fileName)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
static void setDialogIcons(Dialog<?> dialog)
static final ButtonType OK