diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index 2982f383dd..4d81571db0 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,10 @@ package org.sleuthkit.autopsy.timeline; import java.awt.Component; import java.io.IOException; import java.util.logging.Level; +import javafx.application.Platform; import javax.swing.ImageIcon; import javax.swing.JButton; +import javax.swing.JMenuItem; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -30,7 +32,6 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; @@ -38,6 +39,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.TskCoreException; /** * An Action that opens the Timeline window. Has methods to open the window in @@ -48,15 +50,15 @@ import org.sleuthkit.datamodel.BlackboardArtifact; @ActionReferences(value = { @ActionReference(path = "Menu/Tools", position = 102), @ActionReference(path = "Toolbars/Case", position = 102)}) -public final class OpenTimelineAction extends CallableSystemAction implements Presenter.Toolbar { +public final class OpenTimelineAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - private static final Logger LOGGER = Logger.getLogger(OpenTimelineAction.class.getName()); - - private static final boolean FX_INITED = Installer.isJavaFxInited(); + private static final Logger logger = Logger.getLogger(OpenTimelineAction.class.getName()); + private static final int FILE_LIMIT = 6_000_000; private static TimeLineController timeLineController = null; + private final JMenuItem menuItem; private final JButton toolbarButton = new JButton(getName(), new ImageIcon(getClass().getResource("images/btn_icon_timeline_colorized_26.png"))); //NON-NLS @@ -70,6 +72,7 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr public OpenTimelineAction() { toolbarButton.addActionListener(actionEvent -> performAction()); + menuItem = super.getMenuPresenter(); this.setEnabled(false); } @@ -78,15 +81,25 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr /** * We used to also check if Case.getCurrentCase().hasData() was true. We * disabled that check because if it is executed while a data source is - * being added, it blocks the edt + * being added, it blocks the edt. We still do that in ImageGallery. */ - return Case.isCaseOpen() && FX_INITED; + return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited(); } @Override @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void performAction() { - showTimeline(); + if (tooManyFiles()) { + Platform.runLater(PromptDialogManager::showTooManyFiles); + synchronized (OpenTimelineAction.this) { + if (timeLineController != null) { + timeLineController.shutDownTimeLine(); + } + } + setEnabled(false); + } else { + showTimeline(); + } } @NbBundle.Messages({ @@ -97,7 +110,7 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr Case currentCase = Case.getCurrentCase(); if (currentCase.hasData() == false) { MessageNotifyUtil.Message.info(Bundle.OpenTimeLineAction_msgdlg_text()); - LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS + logger.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS return; } try { @@ -112,7 +125,7 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr } catch (IOException iOException) { MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage()); - LOGGER.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException); + logger.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException); } } catch (IllegalStateException e) { //there is no case... Do nothing. @@ -169,12 +182,13 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr /** * Set this action to be enabled/disabled * - * @param value whether to enable this action or not + * @param enable whether to enable this action or not */ @Override - public void setEnabled(boolean value) { - super.setEnabled(value); - toolbarButton.setEnabled(value); + public void setEnabled(boolean enable) { + super.setEnabled(enable); + menuItem.setEnabled(enable); + toolbarButton.setEnabled(enable); } /** @@ -184,9 +198,23 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr */ @Override public Component getToolbarPresenter() { - ImageIcon icon = new ImageIcon(getClass().getResource("images/btn_icon_timeline_colorized_26.png")); //NON-NLS - toolbarButton.setIcon(icon); - toolbarButton.setText(this.getName()); return toolbarButton; } + + @Override + public JMenuItem getMenuPresenter() { + return menuItem; + } + + private boolean tooManyFiles() { + try { + return FILE_LIMIT < Case.getCurrentCase().getSleuthkitCase().countFilesWhere("1 = 1"); + } catch (IllegalStateException ex) { + logger.log(Level.SEVERE, "Can not open timeline with no case open.", ex); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error counting files in the DB.", ex); + } + //if there is any doubt (no case, tskcore error, etc) just disable . + return false; + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java b/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java index 67b952bc13..a216c9366a 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/PromptDialogManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-16 Basis Technology Corp. + * Copyright 2015-17 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,7 +45,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; */ public final class PromptDialogManager { - private static final Logger LOGGER = Logger.getLogger(PromptDialogManager.class.getName()); + private final static Logger logger = Logger.getLogger(PromptDialogManager.class.getName()); @NbBundle.Messages("PrompDialogManager.buttonType.showTimeline=Continue") private static final ButtonType CONTINUE = new ButtonType(Bundle.PrompDialogManager_buttonType_showTimeline(), ButtonBar.ButtonData.OK_DONE); @@ -66,7 +66,7 @@ public final class PromptDialogManager { try { tempImg = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NON-NLS } catch (IOException ex) { - LOGGER.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NON-NLS + logger.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NON-NLS } AUTOPSY_ICON = tempImg; } @@ -138,7 +138,7 @@ public final class PromptDialogManager { } /** - * Set the title bar icon for the given dialog to be the autopsy logo icon. + * Set the title bar icon for the given Dialog to be the Autopsy logo icon. * * @param dialog The dialog to set the title bar icon for. */ @@ -177,7 +177,8 @@ public final class PromptDialogManager { * @return True if the user a confirms rebuilding the database. */ @NbBundle.Messages({ - "PromptDialogManager.rebuildPrompt.headerText=The Timeline DB is incomplete and/or out of date. Some events may be missing or inaccurate and some features may be unavailable.", + "PromptDialogManager.rebuildPrompt.headerText=The Timeline DB is incomplete and/or out of date." + + " Some events may be missing or inaccurate and some features may be unavailable.", "PromptDialogManager.rebuildPrompt.details=Details"}) @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean confirmRebuild(List rebuildReasons) { @@ -206,4 +207,20 @@ public final class PromptDialogManager { //show dialog and map all results except "update" to false. return currentDialog.showAndWait().map(UPDATE::equals).orElse(false); } + + @NbBundle.Messages({ + "PromptDialogManager.showTooManyFiles.contentText=" + + "There are too many files in the DB to ensure reasonable performance." + + " Timeline will be disabled. ", + "PromptDialogManager.showTooManyFiles.headerText="}) + static void showTooManyFiles() { + Alert dialog = new Alert(Alert.AlertType.INFORMATION, + Bundle.PromptDialogManager_showTooManyFiles_contentText(), ButtonType.OK); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.setTitle(Bundle.Timeline_dialogs_title()); + setDialogIcons(dialog); + dialog.setHeaderText(Bundle.PromptDialogManager_showTooManyFiles_headerText()); + dialog.showAndWait(); + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index 71ff3681a5..1707e57d0f 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -1,93 +1,130 @@ /* -* Autopsy Forensic Browser -* -* Copyright 2011-17 Basis Technology Corp. -* Contact: carrier sleuthkit org -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Autopsy Forensic Browser + * + * Copyright 2015-17 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.sleuthkit.autopsy.imagegallery.actions; import java.awt.Component; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.net.URL; +import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Dialog; +import javafx.scene.image.Image; +import javafx.stage.Modality; +import javafx.stage.Stage; import javax.swing.ImageIcon; import javax.swing.JButton; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; +import org.sleuthkit.datamodel.TskCoreException; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.imagegallery.OpenAction") @ActionReferences(value = { @ActionReference(path = "Menu/Tools", position = 101), - @ActionReference(path = "Toolbars/Case", position = 101) -}) + @ActionReference(path = "Toolbars/Case", position = 101)}) @ActionRegistration(displayName = "#CTL_OpenAction", lazy = false) @Messages({"CTL_OpenAction=View Images/Videos", - "OpenAction.stale.confDlg.msg=The image / video database may be out of date. " + - "Do you want to update and listen for further ingest results?\n" + - "Choosing 'yes' will update the database and enable listening to future ingests.", + "OpenAction.stale.confDlg.msg=The image / video database may be out of date. " + + "Do you want to update and listen for further ingest results?\n" + + "Choosing 'yes' will update the database and enable listening to future ingests.", "OpenAction.stale.confDlg.title=Image Gallery"}) -public final class OpenAction extends CallableSystemAction implements Presenter.Toolbar { - - private static final Logger LOGGER = Logger.getLogger(OpenAction.class.getName()); +public final class OpenAction extends CallableSystemAction { + + private static final Logger logger = Logger.getLogger(OpenAction.class.getName()); private static final String VIEW_IMAGES_VIDEOS = Bundle.CTL_OpenAction(); - - private final JButton toolbarButton = new JButton(); + + /** + * Image to use as title bar icon in dialogs + */ + private static final Image AUTOPSY_ICON; + + static { + Image tempImg = null; + try { + tempImg = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NON-NLS + } catch (IOException ex) { + logger.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NON-NLS + } + AUTOPSY_ICON = tempImg; + } + + private static final long FILE_LIMIT = 6_000_000; + private final PropertyChangeListener pcl; - + private final JMenuItem menuItem; + private final JButton toolbarButton = new JButton(this.getName(), + new ImageIcon(getClass().getResource("btn_icon_image_gallery_26.png"))); + public OpenAction() { super(); toolbarButton.addActionListener(actionEvent -> performAction()); + menuItem = super.getMenuPresenter(); pcl = (PropertyChangeEvent evt) -> { if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { - setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null); + setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null); } }; Case.addPropertyChangeListener(pcl); this.setEnabled(false); } - + @Override public boolean isEnabled() { - return Case.isCaseOpen() && Installer.isJavaFxInited() && Case.getCurrentCase().hasData(); + return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited() && Case.getCurrentCase().hasData(); } - - /** Returns the toolbar component of this action + + /** + * Returns the toolbar component of this action * - * @return component the toolbar button */ + * @return component the toolbar button + */ @Override public Component getToolbarPresenter() { - ImageIcon icon = new ImageIcon(getClass().getResource("btn_icon_image_gallery_26.png")); //NON-NLS - toolbarButton.setIcon(icon); - toolbarButton.setText(this.getName()); + return toolbarButton; } - + + @Override + public JMenuItem getMenuPresenter() { + return menuItem; + } + /** * Set this action to be enabled/disabled * @@ -96,28 +133,37 @@ public final class OpenAction extends CallableSystemAction implements Presenter. @Override public void setEnabled(boolean value) { super.setEnabled(value); + menuItem.setEnabled(value); toolbarButton.setEnabled(value); } - + @Override @SuppressWarnings("fallthrough") + @NbBundle.Messages({ + "OpenAction.dialogTitle=Image Gallery" + }) public void performAction() { - + //check case if (!Case.isCaseOpen()) { return; } final Case currentCase = Case.getCurrentCase(); - + + if (tooManyFiles()) { + Platform.runLater(OpenAction::showTooManyFiles); + setEnabled(false); + return; + } if (ImageGalleryModule.isDrawableDBStale(currentCase)) { //drawable db is stale, ask what to do int answer = JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), Bundle.OpenAction_stale_confDlg_msg(), Bundle.OpenAction_stale_confDlg_title(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); - + switch (answer) { case JOptionPane.YES_OPTION: ImageGalleryController.getDefault().setListeningEnabled(true); - //fall through + //fall through case JOptionPane.NO_OPTION: ImageGalleryTopComponent.openTopComponent(); break; @@ -129,17 +175,54 @@ public final class OpenAction extends CallableSystemAction implements Presenter. ImageGalleryTopComponent.openTopComponent(); } } - + + private boolean tooManyFiles() { + try { + return FILE_LIMIT < Case.getCurrentCase().getSleuthkitCase().countFilesWhere("1 = 1"); + } catch (IllegalStateException ex) { + logger.log(Level.SEVERE, "Can not open image gallery with no case open.", ex); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error counting files in the DB.", ex); + } + //if there is any doubt (no case, tskcore error, etc) just disable . + return false; + } + + /** + * Set the title bar icon for the given Dialog to be the Autopsy logo icon. + * + * @param dialog The dialog to set the title bar icon for. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) + private static void setDialogIcons(Dialog dialog) { + ((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().setAll(AUTOPSY_ICON); + } + + @NbBundle.Messages({ + "ImageGallery.showTooManyFiles.contentText=" + + "There are too many files in the DB to ensure reasonable performance." + + " Image Gallery will be disabled. ", + "ImageGallery.showTooManyFiles.headerText="}) + private static void showTooManyFiles() { + Alert dialog = new Alert(Alert.AlertType.INFORMATION, + Bundle.ImageGallery_showTooManyFiles_contentText(), ButtonType.OK); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.setTitle(Bundle.OpenAction_dialogTitle()); + setDialogIcons(dialog); + dialog.setHeaderText(Bundle.ImageGallery_showTooManyFiles_headerText()); + dialog.showAndWait(); + } + @Override public String getName() { return VIEW_IMAGES_VIDEOS; } - + @Override public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } - + @Override public boolean asynchronous() { return false; // run on edt