diff --git a/.gitattributes b/.gitattributes index 6cd046f17b..cd5271c982 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ *.java text diff=java *.txt text -*.sh text +*.sh eol=lf *.mf text *.xml text *.form text diff --git a/Core/manifest.mf b/Core/manifest.mf index 53b737fbd1..dbfb89dc59 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 28 +OpenIDE-Module-Implementation-Version: 29 OpenIDE-Module-Requires: org.openide.windows.WindowManager AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index a246e0cc80..06e7638be5 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -122,5 +122,5 @@ nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar -spec.version.base=10.16 +spec.version.base=10.17 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 1e32239fc4..8fe442a721 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -251,7 +251,7 @@ 3 - 1.2 + 1.3 diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java index 9768547546..4d04e5dbbf 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java @@ -62,15 +62,16 @@ import org.sleuthkit.autopsy.ingest.IngestModuleError; import org.sleuthkit.autopsy.ingest.IngestProfiles; import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; -import org.sleuthkit.autopsy.report.infrastructure.ReportProgressLogger; +import org.sleuthkit.autopsy.progress.LoggingProgressIndicator; import org.sleuthkit.autopsy.report.infrastructure.ReportGenerator; +import org.sleuthkit.autopsy.report.infrastructure.ReportProgressIndicator; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; /** - * Allows Autopsy to be invoked with a command line arguments. Causes Autopsy to - * create a case, add a specified data source, run ingest on that data source, - * list all data source in a case, generate reports. + * Allows Autopsy to be invoked with command line arguments. Arguments exist to + * cause Autopsy to create a case, add a specified data source, run ingest on + * that data source, list all data sources in the case, and generate reports. */ public class CommandLineIngestManager { @@ -285,7 +286,8 @@ public class CommandLineIngestManager { } // generate reports - ReportGenerator generator = new ReportGenerator(CommandLineIngestSettingsPanel.getReportingConfigName(), new ReportProgressLogger()); //NON-NLS + ReportProgressIndicator progressIndicator = new ReportProgressIndicator(new LoggingProgressIndicator()); + ReportGenerator generator = new ReportGenerator(CommandLineIngestSettingsPanel.getReportingConfigName(), progressIndicator); generator.generateReports(); } catch (CaseActionException ex) { String caseDirPath = command.getInputs().get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); @@ -332,9 +334,10 @@ public class CommandLineIngestManager { * Creates a new case using arguments passed in from command line * CREATE_CASE command. * - * @param baseCaseName Case name + * @param baseCaseName Case name * @param rootOutputDirectory Full path to directory in which case - * output folder will be created + * output folder will be created + * * @throws CaseActionException */ private void openCase(String baseCaseName, String rootOutputDirectory) throws CaseActionException { @@ -363,6 +366,7 @@ public class CommandLineIngestManager { * Opens existing case. * * @param caseFolderPath full path to case directory + * * @throws CaseActionException */ private void openCase(String caseFolderPath) throws CaseActionException { @@ -415,11 +419,16 @@ public class CommandLineIngestManager { * @param dataSource The data source. * * @throws - * AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException if - * there was a DSP processing error + * AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorExceptioif + * there + * was + * a + * DSP + * processing + * error * - * @throws InterruptedException if the thread running the job processing - * task is interrupted while blocked, i.e., if auto ingest is shutting down. + * @throws ead running the job processing task is interrupted while + * blocked, i.e., if auto ingest is shutting down. */ private void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource) throws InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { @@ -520,14 +529,15 @@ public class CommandLineIngestManager { * profile (profile = ingest context + ingest filter) for ingest. * Otherwise use baseline configuration. * - * @param dataSource The data source to analyze. + * @param dataSource The data source to analyze. * @param ingestProfileName Name of ingest profile to use (optional) * * @throws AnalysisStartupException if there is an error analyzing the - * data source. - * @throws InterruptedException if the thread running the job processing - * task is interrupted while blocked, i.e., if auto ingest is shutting - * down. + * data source. + * @throws InterruptedException if the thread running the job + * processing task is interrupted while + * blocked, i.e., if auto ingest is + * shutting down. */ private void analyze(AutoIngestDataSource dataSource, String ingestProfileName) throws AnalysisStartupException, InterruptedException { @@ -628,6 +638,7 @@ public class CommandLineIngestManager { * ingest profiles. * * @param ingestProfileName Ingest profile name + * * @return IngestProfile object, or NULL if the profile doesn't exist */ private IngestProfiles.IngestProfile getSelectedProfile(String ingestProfileName) { @@ -649,6 +660,7 @@ public class CommandLineIngestManager { * filters (custom and standard). * * @param filterName Name of the file filter + * * @return FilesSet object, or NULL if the filter doesn't exist */ private FilesSet getSelectedFilter(String filterName) { @@ -711,6 +723,7 @@ public class CommandLineIngestManager { * Returns full path to directory where command outputs should be saved. * * @param caseForJob Case object + * * @return Full path to directory where command outputs should be saved */ private String getOutputDirPath(Case caseForJob) { diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form index 1c1bc033f5..e1375f2d5a 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form @@ -16,28 +16,14 @@ - - - - + - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java index 0cad213cd4..4ebcd9298e 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java @@ -64,8 +64,6 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro private final Outline outline; private final ExplorerManager accountsTableEM = new ExplorerManager(); - - final RelationshipBrowser relationshipBrowser; /* * This lookup proxies the selection lookup of both he accounts table and @@ -73,12 +71,9 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro */ private final ProxyLookup proxyLookup; - public AccountsBrowser() { + public AccountsBrowser(RelationshipBrowser relationshipBrowser) { initComponents(); - jSplitPane1.setResizeWeight(0.5); - jSplitPane1.setDividerLocation(0.75); - outline = outlineView.getOutline(); outlineView.setPropertyColumns( "device", Bundle.AccountNode_device(), @@ -90,9 +85,6 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName()); outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded - - relationshipBrowser = new RelationshipBrowser(); - jSplitPane1.setRightComponent(relationshipBrowser); accountsTableEM.addPropertyChangeListener(evt -> { if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) { @@ -174,20 +166,14 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro // //GEN-BEGIN:initComponents private void initComponents() { - jSplitPane1 = new javax.swing.JSplitPane(); outlineView = new org.openide.explorer.view.OutlineView(); setLayout(new java.awt.BorderLayout()); - - jSplitPane1.setDividerLocation(500); - jSplitPane1.setLeftComponent(outlineView); - - add(jSplitPane1, java.awt.BorderLayout.CENTER); + add(outlineView, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JSplitPane jSplitPane1; private org.openide.explorer.view.OutlineView outlineView; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index 1b2dd9ae37..747f0c82f7 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -49,3 +49,5 @@ VisualizationPanel.forwardButton.text= VisualizationPanel.zoomPercentLabel.text=100% VisualizationPanel.zoomLabel.text=Zoom: VisualizationPanel.snapshotButton.toolTipText=Generate Snapshot report. +CVTTopComponent.filtersPane.TabConstraints.tabTitle=Filters +CVTTopComponent.filterTabPanel.TabConstraints.tabTitle=Filters diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index 2ad2305d38..65c130bd6e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -92,6 +92,8 @@ VisualizationPanel.forwardButton.text= VisualizationPanel.zoomPercentLabel.text=100% VisualizationPanel.zoomLabel.text=Zoom: VisualizationPanel.snapshotButton.toolTipText=Generate Snapshot report. +CVTTopComponent.filtersPane.TabConstraints.tabTitle=Filters +CVTTopComponent.filterTabPanel.TabConstraints.tabTitle=Filters VisualizationPanel_action_dialogs_title=Communications VisualizationPanel_action_name_text=Snapshot Report VisualizationPanel_module_name=Communications diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form index a7bc5379c3..c11d0c335c 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form @@ -14,24 +14,52 @@ - + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - @@ -45,13 +73,16 @@ - + + + + @@ -66,6 +97,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java index 2a5dd8c0d1..a11fde5622 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java @@ -19,14 +19,16 @@ package org.sleuthkit.autopsy.communications; import com.google.common.eventbus.Subscribe; +import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; import javax.swing.ImageIcon; +import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import org.openide.util.Lookup; @@ -35,7 +37,10 @@ import org.openide.windows.Mode; import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.communications.relationships.RelationshipBrowser; +import org.sleuthkit.autopsy.communications.relationships.SelectionInfo; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.datamodel.CommunicationsFilter; /** * Top component which displays the Communications Visualization Tool. @@ -48,10 +53,17 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; public final class CVTTopComponent extends TopComponent { private static final long serialVersionUID = 1L; + private boolean filtersVisible = true; + private final RelationshipBrowser relationshipBrowser = new RelationshipBrowser(); + private CommunicationsFilter currentFilter; @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public CVTTopComponent() { initComponents(); + + splitPane.setRightComponent(relationshipBrowser); + splitPane.setDividerLocation(0.25); + setName(Bundle.CVTTopComponent_name()); /* @@ -68,6 +80,8 @@ public final class CVTTopComponent extends TopComponent { Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup(); proxyLookup.setNewLookups(lookup); } + + relationshipBrowser.setSelectionInfo(new SelectionInfo(new HashSet<>(), new HashSet<>(), currentFilter)); }); @@ -80,14 +94,19 @@ public final class CVTTopComponent extends TopComponent { CVTEvents.getCVTEventBus().register(accountsBrowser); CVTEvents.getCVTEventBus().register(filtersPane); - mainSplitPane.setResizeWeight(0.5); - mainSplitPane.setDividerLocation(0.25); + filterTabbedPane.setIconAt(0, new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-left.png"))); + filterTabbedPane.setTitleAt(0, ""); } @Subscribe void pinAccount(CVTEvents.PinAccountsEvent pinEvent) { browseVisualizeTabPane.setSelectedIndex(1); } + + @Subscribe + void handle(final CVTEvents.FilterChangeEvent filterChangeEvent) { + currentFilter = filterChangeEvent.getNewFilter(); + } /** * This method is called from within the constructor to initialize the form. @@ -96,38 +115,68 @@ public final class CVTTopComponent extends TopComponent { */ // //GEN-BEGIN:initComponents private void initComponents() { - GridBagConstraints gridBagConstraints; - mainSplitPane = new JSplitPane(); + filterTabbedPane = new JTabbedPane(); + filterTabPanel = new JPanel(); filtersPane = new FiltersPanel(); + splitPane = new JSplitPane(); browseVisualizeTabPane = new JTabbedPane(); - accountsBrowser = new AccountsBrowser(); - vizPanel = new VisualizationPanel(); + accountsBrowser = new AccountsBrowser(relationshipBrowser); + vizPanel = new VisualizationPanel(relationshipBrowser); - setLayout(new GridBagLayout()); + setLayout(new BorderLayout()); - mainSplitPane.setLeftComponent(filtersPane); + filterTabbedPane.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + filterTabbedPaneMouseClicked(evt); + } + }); + + filterTabPanel.setLayout(new BorderLayout()); + filterTabPanel.add(filtersPane, BorderLayout.CENTER); + + filterTabbedPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.filterTabPanel.TabConstraints.tabTitle"), filterTabPanel); // NOI18N + + add(filterTabbedPane, BorderLayout.WEST); + + splitPane.setDividerLocation(1); + splitPane.setResizeWeight(0.25); browseVisualizeTabPane.setFont(new Font("Tahoma", 0, 18)); // NOI18N browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.vizPanel.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), vizPanel); // NOI18N - mainSplitPane.setRightComponent(browseVisualizeTabPane); + splitPane.setLeftComponent(browseVisualizeTabPane); browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N - gridBagConstraints = new GridBagConstraints(); - gridBagConstraints.fill = GridBagConstraints.BOTH; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.weighty = 1.0; - add(mainSplitPane, gridBagConstraints); + add(splitPane, BorderLayout.CENTER); }// //GEN-END:initComponents + private void filterTabbedPaneMouseClicked(MouseEvent evt) {//GEN-FIRST:event_filterTabPaneMouseClicked + int index = filterTabbedPane.indexAtLocation(evt.getX(), evt.getY()); + if(index != -1) { + if(filtersVisible) { + filterTabbedPane.setIconAt(0, new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-right.png"))); + filterTabPanel.removeAll(); + filterTabPanel.revalidate(); + filtersVisible = false; + } else { + filterTabbedPane.setIconAt(0, new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-left.png"))); + filterTabPanel.add(filtersPane, BorderLayout.CENTER); + filterTabPanel.revalidate(); + filtersVisible = true; + } + } + }//GEN-LAST:event_filterTabPaneMouseClicked + // Variables declaration - do not modify//GEN-BEGIN:variables private AccountsBrowser accountsBrowser; private JTabbedPane browseVisualizeTabPane; + private JTabbedPane filterTabbedPane; + private JPanel filterTabPanel; private FiltersPanel filtersPane; - private JSplitPane mainSplitPane; + private JSplitPane splitPane; private VisualizationPanel vizPanel; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form index 33fe6d5228..c1b520127e 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form @@ -18,6 +18,7 @@ + @@ -37,7 +38,7 @@ - + @@ -128,7 +129,7 @@ - + @@ -222,7 +223,7 @@ - + @@ -325,7 +326,7 @@ - + @@ -422,7 +423,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index a9c6f58e4e..61485832b0 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -477,6 +477,7 @@ final public class FiltersPanel extends JPanel { setLayout(new java.awt.GridBagLayout()); + scrollPane.setAutoscrolls(true); scrollPane.setBorder(null); mainPanel.setLayout(new java.awt.GridBagLayout()); @@ -541,7 +542,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; - gridBagConstraints.insets = new java.awt.Insets(15, 0, 15, 0); + gridBagConstraints.insets = new java.awt.Insets(15, 0, 15, 25); mainPanel.add(limitPane, gridBagConstraints); startDatePicker.setEnabled(false); @@ -608,7 +609,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 25); mainPanel.add(dateRangePane, gridBagConstraints); devicesPane.setLayout(new java.awt.GridBagLayout()); @@ -686,7 +687,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.ipady = 100; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 25); mainPanel.add(devicesPane, gridBagConstraints); accountTypesPane.setLayout(new java.awt.GridBagLayout()); @@ -760,7 +761,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 25); mainPanel.add(accountTypesPane, gridBagConstraints); topPane.setLayout(new java.awt.GridBagLayout()); @@ -810,6 +811,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END; gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 25); mainPanel.add(topPane, gridBagConstraints); scrollPane.setViewportView(mainPanel); diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form index e85901a1ba..18d2d90b0d 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form @@ -11,348 +11,282 @@ - + - - - - - + - + - + - - + + - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 8a5404bb1a..263bb200e6 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -43,6 +43,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Desktop; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; @@ -61,7 +62,6 @@ import java.nio.file.Paths; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; @@ -86,7 +86,6 @@ import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; -import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JToolBar; @@ -96,7 +95,6 @@ import javax.swing.SwingWorker; import org.apache.commons.lang3.StringUtils; import org.controlsfx.control.Notifications; import org.jdesktop.layout.GroupLayout; -import org.jdesktop.layout.LayoutStyle; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; @@ -112,6 +110,7 @@ import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.uicomponents.WrapLayout; /** * A panel that goes in the Visualize tab of the Communications Visualization * Tool. Hosts an JGraphX mxGraphComponent that implements the communications @@ -160,7 +159,8 @@ final public class VisualizationPanel extends JPanel { private final StateManager stateManager; @NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.") - public VisualizationPanel() { + public VisualizationPanel(RelationshipBrowser relationshipBrowser) { + this.relationshipBrowser = relationshipBrowser; initComponents(); //initialize invisible JFXPanel that is used to show JFXNotifications over this window. notificationsJFXPanel.setScene(new Scene(new Pane())); @@ -220,9 +220,6 @@ final public class VisualizationPanel extends JPanel { final GraphMouseListener graphMouseListener = new GraphMouseListener(); graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener); graphComponent.getGraphControl().addMouseListener(graphMouseListener); - - relationshipBrowser = new RelationshipBrowser(); - splitPane.setRightComponent(relationshipBrowser); //feed selection to explorermanager graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener()); @@ -247,6 +244,8 @@ final public class VisualizationPanel extends JPanel { stateManager = new StateManager(pinnedAccountModel); setStateButtonsEnabled(); + + toolbar.setLayout(new WrapLayout(FlowLayout.LEFT)); } @Subscribe @@ -373,32 +372,28 @@ final public class VisualizationPanel extends JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - splitPane = new JSplitPane(); borderLayoutPanel = new JPanel(); placeHolderPanel = new JPanel(); jTextArea1 = new JTextArea(); - toolbar = new JPanel(); - fastOrganicLayoutButton = new JButton(); - zoomOutButton = new JButton(); - zoomInButton = new JButton(); - zoomActualButton = new JButton(); - fitZoomButton = new JButton(); - zoomLabel = new JLabel(); - zoomPercentLabel = new JLabel(); - clearVizButton = new JButton(); - jSeparator2 = new JToolBar.Separator(); + notificationsJFXPanel = new JFXPanel(); + toolbar = new JToolBar(); backButton = new JButton(); forwardButton = new JButton(); - snapshotButton = new JButton(); jSeparator3 = new JToolBar.Separator(); - jSeparator4 = new JToolBar.Separator(); - notificationsJFXPanel = new JFXPanel(); + clearVizButton = new JButton(); + fastOrganicLayoutButton = new JButton(); + jSeparator2 = new JToolBar.Separator(); + zoomLabel = new JLabel(); + zoomPercentLabel = new JLabel(); + zoomOutButton = new JButton(); + fitZoomButton = new JButton(); + zoomActualButton = new JButton(); + zoomInButton = new JButton(); + jSeparator1 = new JToolBar.Separator(); + snapshotButton = new JButton(); setLayout(new BorderLayout()); - splitPane.setDividerLocation(800); - splitPane.setResizeWeight(0.5); - borderLayoutPanel.setLayout(new BorderLayout()); jTextArea1.setBackground(new Color(240, 240, 240)); @@ -411,9 +406,9 @@ final public class VisualizationPanel extends JPanel { placeHolderPanel.setLayout(placeHolderPanelLayout); placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING) .add(placeHolderPanelLayout.createSequentialGroup() - .addContainerGap(250, Short.MAX_VALUE) + .addContainerGap(316, Short.MAX_VALUE) .add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE) - .addContainerGap(423, Short.MAX_VALUE)) + .addContainerGap(481, Short.MAX_VALUE)) ); placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING) .add(placeHolderPanelLayout.createSequentialGroup() @@ -423,12 +418,72 @@ final public class VisualizationPanel extends JPanel { ); borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER); + borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END); + + add(borderLayoutPanel, BorderLayout.CENTER); + + toolbar.setRollover(true); + + backButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N + backButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N + backButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N + backButton.setFocusable(false); + backButton.setHorizontalTextPosition(SwingConstants.CENTER); + backButton.setVerticalTextPosition(SwingConstants.BOTTOM); + backButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + backButtonActionPerformed(evt); + } + }); + toolbar.add(backButton); + + forwardButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N + forwardButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N + forwardButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N + forwardButton.setFocusable(false); + forwardButton.setHorizontalTextPosition(SwingConstants.CENTER); + forwardButton.setVerticalTextPosition(SwingConstants.BOTTOM); + forwardButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + forwardButtonActionPerformed(evt); + } + }); + toolbar.add(forwardButton); + toolbar.add(jSeparator3); + + clearVizButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N + clearVizButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N + clearVizButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N + clearVizButton.setActionCommand(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N + clearVizButton.setFocusable(false); + clearVizButton.setHorizontalTextPosition(SwingConstants.CENTER); + clearVizButton.setVerticalTextPosition(SwingConstants.BOTTOM); + clearVizButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + clearVizButtonActionPerformed(evt); + } + }); + toolbar.add(clearVizButton); fastOrganicLayoutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N fastOrganicLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N fastOrganicLayoutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N fastOrganicLayoutButton.setFocusable(false); + fastOrganicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER); fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM); + fastOrganicLayoutButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + fastOrganicLayoutButtonActionPerformed(evt); + } + }); + toolbar.add(fastOrganicLayoutButton); + toolbar.add(jSeparator2); + + zoomLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N + toolbar.add(zoomLabel); + + zoomPercentLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomPercentLabel.text")); // NOI18N + toolbar.add(zoomPercentLabel); zoomOutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N zoomOutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N @@ -441,30 +496,7 @@ final public class VisualizationPanel extends JPanel { zoomOutButtonActionPerformed(evt); } }); - - zoomInButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N - zoomInButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N - zoomInButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N - zoomInButton.setFocusable(false); - zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER); - zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM); - zoomInButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - zoomInButtonActionPerformed(evt); - } - }); - - zoomActualButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N - zoomActualButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N - zoomActualButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N - zoomActualButton.setFocusable(false); - zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER); - zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM); - zoomActualButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - zoomActualButtonActionPerformed(evt); - } - }); + toolbar.add(zoomOutButton); fitZoomButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N fitZoomButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N @@ -477,116 +509,49 @@ final public class VisualizationPanel extends JPanel { fitZoomButtonActionPerformed(evt); } }); + toolbar.add(fitZoomButton); - zoomLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N - - zoomPercentLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomPercentLabel.text")); // NOI18N - - clearVizButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N - clearVizButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N - clearVizButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N - clearVizButton.setActionCommand(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N - clearVizButton.addActionListener(new ActionListener() { + zoomActualButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N + zoomActualButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N + zoomActualButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N + zoomActualButton.setFocusable(false); + zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER); + zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM); + zoomActualButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - clearVizButtonActionPerformed(evt); + zoomActualButtonActionPerformed(evt); } }); + toolbar.add(zoomActualButton); - jSeparator2.setOrientation(SwingConstants.VERTICAL); - - backButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N - backButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N - backButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N - backButton.addActionListener(new ActionListener() { + zoomInButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N + zoomInButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N + zoomInButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N + zoomInButton.setFocusable(false); + zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER); + zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM); + zoomInButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - backButtonActionPerformed(evt); - } - }); - - forwardButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N - forwardButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N - forwardButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N - forwardButton.setHorizontalTextPosition(SwingConstants.LEADING); - forwardButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - forwardButtonActionPerformed(evt); + zoomInButtonActionPerformed(evt); } }); + toolbar.add(zoomInButton); + toolbar.add(jSeparator1); snapshotButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N snapshotButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N snapshotButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.toolTipText")); // NOI18N + snapshotButton.setFocusable(false); + snapshotButton.setHorizontalTextPosition(SwingConstants.CENTER); + snapshotButton.setVerticalTextPosition(SwingConstants.BOTTOM); snapshotButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { snapshotButtonActionPerformed(evt); } }); + toolbar.add(snapshotButton); - jSeparator3.setOrientation(SwingConstants.VERTICAL); - - jSeparator4.setOrientation(SwingConstants.VERTICAL); - - GroupLayout toolbarLayout = new GroupLayout(toolbar); - toolbar.setLayout(toolbarLayout); - toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING) - .add(toolbarLayout.createSequentialGroup() - .addContainerGap() - .add(backButton) - .addPreferredGap(LayoutStyle.RELATED) - .add(forwardButton) - .addPreferredGap(LayoutStyle.RELATED) - .add(jSeparator4, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(fastOrganicLayoutButton) - .addPreferredGap(LayoutStyle.RELATED) - .add(clearVizButton) - .addPreferredGap(LayoutStyle.RELATED) - .add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(zoomLabel) - .addPreferredGap(LayoutStyle.RELATED) - .add(zoomPercentLabel) - .addPreferredGap(LayoutStyle.RELATED) - .add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(jSeparator3, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.RELATED) - .add(snapshotButton) - .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING) - .add(toolbarLayout.createSequentialGroup() - .add(3, 3, 3) - .add(toolbarLayout.createParallelGroup(GroupLayout.CENTER) - .add(fastOrganicLayoutButton) - .add(zoomOutButton) - .add(zoomInButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(zoomActualButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(fitZoomButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(zoomLabel) - .add(zoomPercentLabel) - .add(clearVizButton) - .add(jSeparator2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(backButton) - .add(forwardButton) - .add(snapshotButton) - .add(jSeparator3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(jSeparator4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .add(3, 3, 3)) - ); - - borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START); - borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END); - - splitPane.setLeftComponent(borderLayoutPanel); - - add(splitPane, BorderLayout.CENTER); + add(toolbar, BorderLayout.NORTH); }// //GEN-END:initComponents private void fitZoomButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fitZoomButtonActionPerformed @@ -726,6 +691,10 @@ final public class VisualizationPanel extends JPanel { } }//GEN-LAST:event_snapshotButtonActionPerformed + private void fastOrganicLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fastOrganicLayoutButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_fastOrganicLayoutButtonActionPerformed + private void fitGraph() { graphComponent.zoomTo(1, true); mxPoint translate = graph.getView().getTranslate(); @@ -883,15 +852,14 @@ final public class VisualizationPanel extends JPanel { private JButton fastOrganicLayoutButton; private JButton fitZoomButton; private JButton forwardButton; + private JToolBar.Separator jSeparator1; private JToolBar.Separator jSeparator2; private JToolBar.Separator jSeparator3; - private JToolBar.Separator jSeparator4; private JTextArea jTextArea1; private JFXPanel notificationsJFXPanel; private JPanel placeHolderPanel; private JButton snapshotButton; - private JSplitPane splitPane; - private JPanel toolbar; + private JToolBar toolbar; private JButton zoomActualButton; private JButton zoomInButton; private JLabel zoomLabel; diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/arrow-180.png b/Core/src/org/sleuthkit/autopsy/communications/images/arrow-180.png new file mode 100755 index 0000000000..4d2aa3ccb2 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/arrow-180.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/arrow-left.png b/Core/src/org/sleuthkit/autopsy/communications/images/arrow-left.png new file mode 100755 index 0000000000..e00d990348 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/arrow-left.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/arrow-right.png b/Core/src/org/sleuthkit/autopsy/communications/images/arrow-right.png new file mode 100755 index 0000000000..cd2c6be8f2 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/arrow-right.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/arrow.png b/Core/src/org/sleuthkit/autopsy/communications/images/arrow.png new file mode 100755 index 0000000000..12077d3324 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/arrow.png differ diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 0e1b9c9fb1..e5793e9c3e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -199,7 +199,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan imageTaggingOptions.setPopupSize(300, 150); //Disable image tagging for non-windows users or upon failure to load OpenCV. - if (!PlatformUtil.isWindowsOS() || !OpenCvLoader.hasOpenCvLoaded()) { + if (!PlatformUtil.isWindowsOS() || !OpenCvLoader.openCvIsLoaded()) { tagsMenu.setEnabled(false); imageTaggingOptions.setEnabled(false); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java index 3199dbd7e8..807acc5e07 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java @@ -56,6 +56,7 @@ import static org.sleuthkit.autopsy.corecomponents.Bundle.*; import org.sleuthkit.autopsy.corecomponents.ResultViewerPersistence.SortCriterion; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.uicomponents.WrapLayout; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java b/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java index 0929bf8078..219d0497ff 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java @@ -16,10 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.coreutils; -import java.io.Closeable; import java.io.File; import java.io.IOException; import java.sql.Connection; @@ -43,74 +41,76 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * An abstraction around an SQLite app DB found in a data source. - * This class makes a copy of it, along with any meta files (WAL, SHM), - * opens a SQLite connection to it, and runs queries on it. + * An abstraction around an SQLite app DB found in a data source. This class + * makes a copy of it, along with any meta files (WAL, SHM), opens a SQLite + * connection to it, and runs queries on it. */ public final class AppSQLiteDB { + private final Logger logger = Logger.getLogger(AppSQLiteDB.class.getName()); - + private final AbstractFile dbAbstractFile; // AbstractFile for the DB file - + private final Connection connection; private final Statement statement; - - + /** - * Class to abstract the abstract file for a DB file and its on disk copy - * + * Class to abstract the abstract file for a DB file and its on disk copy + * */ private static final class AppSQLiteDBFileBundle { + private final AbstractFile dbAbstractFile; private final File dbFileCopy; - + AppSQLiteDBFileBundle(AbstractFile dbAbstractFile, File dbFileCopy) { this.dbAbstractFile = dbAbstractFile; this.dbFileCopy = dbFileCopy; } - + AbstractFile getAbstractFile() { return dbAbstractFile; } - + File getFileCopy() { return dbFileCopy; } - + } - + private AppSQLiteDB(AppSQLiteDBFileBundle appSQLiteDBFileBundle) throws ClassNotFoundException, SQLException { this.dbAbstractFile = appSQLiteDBFileBundle.getAbstractFile(); - + Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver connection = DriverManager.getConnection("jdbc:sqlite:" + appSQLiteDBFileBundle.getFileCopy().getPath()); //NON-NLS statement = connection.createStatement(); } - - + /** - * Looks for the given SQLIte database filename, with matching path substring. - * It looks for exact name or a pattern match based on a input parameter. - * It makes a copy of each matching file, and creates an instance of - * AppSQLiteDB to help query the DB. - * - * A list of AppSQLiteDB instances is returned, one for each - * match found. - * - * @param dataSource data source to search in - * @param dbName db file name to search - * @param matchExactName whether to look for exact file name or a pattern match - * @param parentPathSubstr path substring to match - * - * @return A list of abstract files matching the specified name and path. - * Returns an empty list if no matching database is found. + * Looks for application SQLite database files with a given name or name + * substring and a given parent path or parent path substring. For each + * database file found, a temporary copy is made and an open connection to + * the database in the form of an AppSQLiteDB object is created and + * returned. + * + * @param dataSource The data source to be searched for the database + * files. + * @param dbFileName The database file name or file name substring for + * which to search. + * @param matchExactName Whether or not the database file name argument is + * the full database file name or a substring. + * @param parentPathSubstr The parent path substring, may pass the empty + * string to match any parent path. + * + * @return A list, possibly empty, of AppSQLiteDB objects for the files that + * were found, copied, and connected to. */ public static Collection findAppDatabases(DataSource dataSource, - String dbName, boolean matchExactName, String parentPathSubstr) { - - List appDbs = new ArrayList<> (); + String dbFileName, boolean matchExactName, String parentPathSubstr) { + + List appDbs = new ArrayList<>(); try { - Collection dbFileBundles = findAndCopySQLiteDB( dataSource, dbName, matchExactName, parentPathSubstr, false); + Collection dbFileBundles = findAndCopySQLiteDB(dataSource, dbFileName, matchExactName, parentPathSubstr, false); dbFileBundles.forEach((dbFileBundle) -> { try { AppSQLiteDB appSQLiteDB = new AppSQLiteDB(dbFileBundle); @@ -120,102 +120,105 @@ public final class AppSQLiteDB { } }); } catch (TskCoreException ex) { - Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error finding App database files with name = '%s' and path = '%s'.", dbName, parentPathSubstr), ex); //NON-NLS + Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error finding App database files with name = '%s' and path = '%s'.", dbFileName, parentPathSubstr), ex); //NON-NLS } - + return appDbs; } - + public AbstractFile getDBFile() { return this.dbAbstractFile; } - + /** * Attaches a database to the current connection. - * - * Finds the specified database file in the specified folder. - * If found, makes copy of the database in the case folder and - * run ATTACH DATABASE sql. - * + * + * Finds the specified database file in the specified folder. If found, + * makes copy of the database in the case folder and run ATTACH DATABASE + * sql. + * * @param dataSource data source in which to look file the db file - * @param dbName name of db file to look for - * @param dbPath path in which to look for the db file - * @param dbAlias alias name to attach the database as - * - * @return abstract file for the matching db file. - * null if no match is found. + * @param dbName name of db file to look for + * @param dbPath path in which to look for the db file + * @param dbAlias alias name to attach the database as + * + * @return abstract file for the matching db file. null if no match is + * found. * * @throws SQLException in case of an SQL error */ - public AbstractFile attachDatabase(DataSource dataSource, String dbName, - String dbPath, String dbAlias) throws SQLException { + public AbstractFile attachDatabase(DataSource dataSource, String dbName, + String dbPath, String dbAlias) throws SQLException { try { // find and copy DB files with exact name and path. - Collection dbFileBundles = findAndCopySQLiteDB(dataSource, dbName, true, dbPath, true); + Collection dbFileBundles = findAndCopySQLiteDB(dataSource, dbName, true, dbPath, true); if (!dbFileBundles.isEmpty()) { AppSQLiteDBFileBundle dbFileBundle = dbFileBundles.iterator().next(); String attachDbSql = String.format("ATTACH DATABASE '%s' AS '%s'", dbFileBundle.getFileCopy().getPath(), dbAlias); //NON-NLS - statement.executeUpdate(attachDbSql); - + statement.executeUpdate(attachDbSql); + return dbFileBundle.getAbstractFile(); } } catch (TskCoreException ex) { Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error attaching to App database files with name = '%s' and path = '%s'.", dbName, dbPath), ex); //NON-NLS } - + return null; } - + /** - * Finds database file with the specified name, makes a copy of the file in the case directory, - * and returns the AbstractFile as well as the file copy. - * - * @param dataSource data source to search in - * @param dbName db file name to search - * @param matchExactName whether to look for exact file name or a pattern match - * @param dbPath path to match - * @param matchExactPath whether to look for exact path name or a substring match - * + * Finds database file with the specified name, makes a copy of the file in + * the case directory, and returns the AbstractFile as well as the file + * copy. + * + * @param dataSource data source to search in + * @param dbName db file name to search + * @param matchExactName whether to look for exact file name or a pattern + * match + * @param dbPath path to match + * @param matchExactPath whether to look for exact path name or a substring + * match + * * @return a collection of AppSQLiteDBFileBundle - * - * @throws TskCoreException + * + * @throws TskCoreException */ - private static Collection findAndCopySQLiteDB(DataSource dataSource, String dbName, - boolean matchExactName, String dbPath, boolean matchExactPath) throws TskCoreException { - + private static Collection findAndCopySQLiteDB(DataSource dataSource, String dbName, + boolean matchExactName, String dbPath, boolean matchExactPath) throws TskCoreException { + Case openCase; try { openCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { throw new TskCoreException("Failed to get current case.", ex); } - - List dbFileBundles = new ArrayList<> (); + + List dbFileBundles = new ArrayList<>(); long fileId = 0; String localDiskPath = ""; - + SleuthkitCase skCase = openCase.getSleuthkitCase(); String parentPath = dbPath.replace("\\", "/"); parentPath = SleuthkitCase.escapeSingleQuotes(parentPath); - + String whereClause; if (matchExactName) { whereClause = String.format("LOWER(name) = LOWER('%s')", dbName); } else { - whereClause = String.format("LOWER(name) LIKE LOWER('%%%s%%') AND LOWER(name) NOT LIKE LOWER('%%journal%%')", dbName ); + whereClause = String.format("LOWER(name) LIKE LOWER('%%%s%%') AND LOWER(name) NOT LIKE LOWER('%%journal%%')", dbName); } if (matchExactPath) { - whereClause += String.format(" AND LOWER(parent_path) = LOWER('%s')", parentPath ); + whereClause += String.format(" AND LOWER(parent_path) = LOWER('%s')", parentPath); } else { - whereClause += String.format(" AND LOWER(parent_path) LIKE LOWER('%%%s%%')", parentPath ); + whereClause += String.format(" AND LOWER(parent_path) LIKE LOWER('%%%s%%')", parentPath); } whereClause += String.format(" AND data_source_obj_id = %s", dataSource.getId()); - + List absFiles = skCase.findAllFilesWhere(whereClause); for (AbstractFile absFile : absFiles) { try { localDiskPath = openCase.getTempDirectory() - + File.separator + absFile.getId() + absFile.getName(); + + File.separator + absFile.getId() + absFile.getName(); File jFile = new java.io.File(localDiskPath); fileId = absFile.getId(); ContentUtils.writeToFile(absFile, jFile); @@ -231,61 +234,58 @@ public final class AppSQLiteDB { Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", absFile.getName(), fileId), ex); //NON-NLS } catch (IOException | NoCurrentCaseException | TskCoreException ex) { Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error creating AppSQLiteDB for file '%s' (id=%d) to copied to '%s'.", absFile.getName(), fileId, localDiskPath), ex); //NON-NLS - } + } } - + return dbFileBundles; } - + /** * Detaches the specified database from the connection - * + * * @param dbAlias alias for database to detach - * - * @throws SQLException + * + * @throws SQLException */ - public void detachDatabase(String dbAlias) throws SQLException { + public void detachDatabase(String dbAlias) throws SQLException { String detachDbSql = String.format("DETACH DATABASE '%s'", dbAlias); statement.executeUpdate(detachDbSql); //NON-NLS } - - + /** * Runs the given query on the database and returns result set. - + * * @param queryStr SQL string for the query to run - * - * @return ResultSet from running the query. - * + * + * @return ResultSet from running the query. + * * @throws SQLException in case of an error. - * + * */ public ResultSet runQuery(String queryStr) throws SQLException { ResultSet resultSet = null; - + if (null != queryStr) { resultSet = statement.executeQuery(queryStr); //NON-NLS - } + } return resultSet; } - + /** * Closes the DB connection. - * + * */ public void close() { - + // Close the DB connection try { statement.close(); connection.close(); } catch (SQLException e) { logger.log(Level.SEVERE, "Error closing the database", e); //NON-NLS - } + } } - - - + /** * Searches for a meta file associated with the give SQLite database. If * found, it copies this file into the temp directory of the current case. @@ -313,11 +313,11 @@ public final class AppSQLiteDB { if (metaFiles != null) { for (AbstractFile metaFile : metaFiles) { String localDiskPath = openCase.getTempDirectory() - + File.separator + sqliteFile.getId() + metaFile.getName(); + + File.separator + sqliteFile.getId() + metaFile.getName(); File localMetaFile = new File(localDiskPath); if (!localMetaFile.exists()) { ContentUtils.writeToFile(metaFile, localMetaFile); - } + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index c2ed64987e..0016d84eb5 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -121,7 +121,7 @@ public class ImageUtils { } DEFAULT_THUMBNAIL = tempImage; boolean tempFfmpegLoaded = false; - if (OpenCvLoader.hasOpenCvLoaded()) { + if (OpenCvLoader.openCvIsLoaded()) { try { if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS System.loadLibrary("opencv_ffmpeg248_64"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java b/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java index d6c9097cd3..a22071fa78 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteDBConnect.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012-2018 Basis Technology Corp. + * Copyright 2012-2019 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -30,108 +30,211 @@ import java.sql.Statement; import java.util.logging.Level; /** - * Database connection class & utilities. + * An abstraction that loads a given SQLite driver, establishes a connection to + * a given database, and creates a statement for the connection to support basic + * SQL operations on the database. */ public class SQLiteDBConnect implements AutoCloseable { - public String sDriver = ""; - public String sUrl = null; - public int iTimeout = 30; - public Connection conn = null; - public Statement statement = null; private static final Logger logger = Logger.getLogger(SQLiteDBConnect.class.getName()); + private static final int STMT_EXEC_TIMEOUT_SECS = 30; - /* - * Stub constructor for quick instantiation o/t fly for using some of the - * ancillary stuff + /** + * Constructs an abstraction that loads a given SQLite driver, establishes a + * connection to a given database, and creates a statement for the + * connection to support basic SQL operations on the database. + * + * @param driver The SQLite driver class name. + * @param url The SQLite database URL to which to connect. + * + * @throws SQLException If there is an error loading the driver, + * establishing the connection, or creating a statement + * for the connection. */ - public SQLiteDBConnect() { - } - - /* - * quick and dirty constructor to test the database passing the - * DriverManager name and the fully loaded url to handle - */ - /* - * NB this will typically be available if you make this class concrete and - * not abstract - */ - public SQLiteDBConnect(String sDriverToLoad, String sUrlToLoad) throws SQLException { - init(sDriverToLoad, sUrlToLoad); - } - - public final void init(String sDriverVar, String sUrlVar) throws SQLException { - setDriver(sDriverVar); - setUrl(sUrlVar); - setConnection(); - setStatement(); - } - - private void setDriver(String sDriverVar) { - sDriver = sDriverVar; - } - - private void setUrl(String sUrlVar) { - sUrl = sUrlVar; - } - - public void setConnection() throws SQLException { + public SQLiteDBConnect(String driver, String url) throws SQLException { + sDriver = driver; + sUrl = url; try { Class.forName(sDriver); - } catch (ClassNotFoundException e) { - + } catch (ClassNotFoundException ex) { + throw new SQLException(ex); } conn = DriverManager.getConnection(sUrl); - } - - public Connection getConnection() { - return conn; - } - - public void setStatement() throws SQLException { - if (conn == null) { - setConnection(); - } statement = conn.createStatement(); - statement.setQueryTimeout(iTimeout); // set timeout to 30 sec. + statement.setQueryTimeout(STMT_EXEC_TIMEOUT_SECS); } - public Statement getStatement() { - return statement; - } - - public void executeStmt(String instruction) throws SQLException { - statement.executeUpdate(instruction); - } - - /** processes an array of instructions e.g. a set of SQL command strings - * passed from a file + /** + * Executes an SQL statement. For use with statements that do not return + * result sets. * - * NB you should ensure you either handle empty lines in files by either - * removing them or parsing them out since they will generate spurious - * SQLExceptions when they are encountered during the iteration.... + * @param sqlStatement The SQL statement to execute. + * + * @throws SQLException If there is an error executing the statement. */ - public void executeStmt(String[] instructionSet) throws SQLException { - for (int i = 0; i < instructionSet.length; i++) { - executeStmt(instructionSet[i]); + public void executeStmt(String sqlStatement) throws SQLException { + statement.executeUpdate(sqlStatement); + } + + /** + * Executes one or more SQL statements in sequence. For use with statements + * that do not return result sets. + * + * @param sqlStatements The SQL statements to execute. + * + * @throws SQLException If there is an error executing the statements. + */ + public void executeStmt(String[] sqlStatements) throws SQLException { + for (String stmt : sqlStatements) { + executeStmt(stmt); } } - public ResultSet executeQry(String instruction) throws SQLException { - return statement.executeQuery(instruction); + /** + * Executes an SQL query and returns a result set. The caller should close + * the result set when finished with it, and should not make any other calls + * on this object until finished with the result set. + * + * @param sqlStatement The SQL query to execute. + * + * @return The result set. + * + * @throws SQLException If there is an error executing the query. + */ + public ResultSet executeQry(String sqlStatement) throws SQLException { + return statement.executeQuery(sqlStatement); } + /** + * Closes the connection to the database. Should be called when the use of + * this object is completed, unless the object was constructed in a try with + * resources statement, in which case the closing is automatic when the + * object goes out of scope. + */ public void closeConnection() { + if (conn == null) { + return; + } try { conn.close(); } catch (SQLException ex) { logger.log(Level.WARNING, "Unable to close connection to SQLite DB at " + sUrl, ex); } - //Implementing Autoclosable.close() allows this class to be used in try-with-resources. } @Override public void close() { closeConnection(); } + + /* + * Partially constructs a utility object for doing basic operations on a + * SQLite database. The object is not in a usable state. Further + * initialization is required. See methods below. + * + * @deprecated Do not use. + */ + @Deprecated + public SQLiteDBConnect() { + } + + /** + * Loads a given SQLite driver, establishes a connection to a given + * database, and creates a statement for the connection. + * + * @param driver The SQLite driver class name. + * @param url The SQLite database URL to which to connect. + * + * @throws SQLException If there is an error establishing the connection or + * creating a statement for the connection. + * + * @deprecated Do not use. + */ + @Deprecated + public final void init(String driver, String url) throws SQLException { + sDriver = driver; + sUrl = url; + closeConnection(); + setConnection(); + setStatement(); + } + + /** + * Sets or resets the connection to the SQLite database, if the SQLite + * driver and the database URL have been set. + * + * @throws SQLException If there is an error loading the driver or + * establishing the connection. + * + * @deprecated Do not use. + */ + @Deprecated + public void setConnection() throws SQLException { + if (sDriver == null || sDriver.isEmpty() || sUrl == null || sUrl.isEmpty()) { + throw new SQLException("Driver and or databse URl not initialized"); + } + closeConnection(); + try { + Class.forName(sDriver); + } catch (ClassNotFoundException ex) { + throw new SQLException(ex); + } + conn = DriverManager.getConnection(sUrl); + } + + /** + * Gets the connection, if any, to the database. + * + * @return The connection to the database, may be null. + * + * @deprecated Do not use. + */ + @Deprecated + public Connection getConnection() { + return conn; + } + + /** + * Creates a connection to the database if there is none, and creates a + * statement using the connection. + * + * @throws SQLException If there is an error creating the connection or the + * staement. + * + * @deprecated Do not use. + */ + @Deprecated + public void setStatement() throws SQLException { + if (conn == null) { + setConnection(); + } + statement = conn.createStatement(); + statement.setQueryTimeout(iTimeout); + } + + /** + * Gets the statement, if any, associated with the connection to the + * database, if any. + * + * @return The statement, may be null. + * + * @deprecated Do not use. + */ + @Deprecated + public Statement getStatement() { + return statement; + } + + /* + * The lack of encapsulation of these fields is an error. Access to them + * outside of instances of this class is deprecated. + * + * @deprecated Do not access. + */ + public String sDriver = ""; + public String sUrl = null; + public int iTimeout = STMT_EXEC_TIMEOUT_SECS; + public Connection conn = null; + public Statement statement = null; + } diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java index f6336771bd..33272e0f6c 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java @@ -70,8 +70,8 @@ final class ConfigVisualPanel1 extends JPanel { ConfigVisualPanel1() { initComponents(); configFileTextField.getDocument().addDocumentListener(new MyDocumentListener(this)); - refreshDriveList(); SwingUtilities.invokeLater(() -> { + refreshDriveList(); updateControls(); }); } diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties index 2a296c830d..c293136c40 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties @@ -1,4 +1,16 @@ OpenIDE-Module-Name=Report DefaultReportConfigurationPanel.infoLabel.text=This report will be configured on the next screen. ReportBranding.defaultReportTitle.text=Autopsy Forensic Report -ReportBranding.defaultReportFooter.text=Powered by Autopsy Open Source Digital Forensics Platform - www.sleuthkit.org \ No newline at end of file +ReportBranding.defaultReportFooter.text=Powered by Autopsy Open Source Digital Forensics Platform - www.sleuthkit.org +ReportProgressPanel.pathLabel.text=pathLabel +ReportProgressPanel.reportLabel.text=reportLabel +ReportProgressPanel.statusMessageLabel.text=processingLabel +ReportProgressPanel.separationLabel.text=: +ReportProgressPanel.initPathLabel.noFile=No report file +ReportProgressPanel.start.cancelButton.text=Cancel +ReportProgressPanel.start.progress.text=Starting report... +ReportProgressPanel.complete.processLbl.text=Complete +ReportProgressPanel.complete.processLb2.text=Completed with error +ReportProgressPanel.complete.cancelButton.text=Complete +ReportProgressPanel.cancel.cancelButton.toolTipText=Canceled +ReportProgressPanel.cancel.procLbl.text=Canceled diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED index 2a296c830d..148df03fa2 100755 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED @@ -1,4 +1,21 @@ OpenIDE-Module-Name=Report DefaultReportConfigurationPanel.infoLabel.text=This report will be configured on the next screen. ReportBranding.defaultReportTitle.text=Autopsy Forensic Report -ReportBranding.defaultReportFooter.text=Powered by Autopsy Open Source Digital Forensics Platform - www.sleuthkit.org \ No newline at end of file +ReportBranding.defaultReportFooter.text=Powered by Autopsy Open Source Digital Forensics Platform - www.sleuthkit.org +ReportProgressPanel.pathLabel.text=pathLabel +ReportProgressPanel.progress.canceled=Canceled +ReportProgressPanel.progress.complete=Complete +ReportProgressPanel.progress.error=Error +ReportProgressPanel.progress.queuing=Queuing... +ReportProgressPanel.progress.running=Running... +ReportProgressPanel.reportLabel.text=reportLabel +ReportProgressPanel.statusMessageLabel.text=processingLabel +ReportProgressPanel.separationLabel.text=: +ReportProgressPanel.initPathLabel.noFile=No report file +ReportProgressPanel.start.cancelButton.text=Cancel +ReportProgressPanel.start.progress.text=Starting report... +ReportProgressPanel.complete.processLbl.text=Complete +ReportProgressPanel.complete.processLb2.text=Completed with error +ReportProgressPanel.complete.cancelButton.text=Complete +ReportProgressPanel.cancel.cancelButton.toolTipText=Canceled +ReportProgressPanel.cancel.procLbl.text=Canceled diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties index 3e5659464f..f666513e92 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties @@ -2,3 +2,7 @@ OpenIDE-Module-Name=\u30ec\u30dd\u30fc\u30c8 DefaultReportConfigurationPanel.infoLabel.text=\u3053\u306e\u30ec\u30dd\u30fc\u30c8\u306f\u6b21\u306e\u30b9\u30af\u30ea\u30fc\u30f3\u3067\u8a2d\u5b9a\u3055\u308c\u307e\u3059\u3002 ReportBranding.defaultReportTitle.text=Autopsy\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30ec\u30dd\u30fc\u30c8 ReportBranding.defaultReportFooter.text=Autopsy\u30aa\u30fc\u30d7\u30f3\u30bd\u30fc\u30b9\u30fb\u30c7\u30b8\u30bf\u30eb\u30fb\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30fb\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u306b\u3088\u308a\u63d0\u4f9b - www.sleuthkit.org +ReportProgressPanel.pathLabel.text=\u30d1\u30b9\u30e9\u30d9\u30eb +ReportProgressPanel.reportLabel.text=\u30ec\u30dd\u30fc\u30c8\u30e9\u30d9\u30eb +ReportProgressPanel.statusMessageLabel.text=\u30d7\u30ed\u30bb\u30b7\u30f3\u30b0\u30e9\u30d9\u30eb +ReportProgressPanel.separationLabel.text=: diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportBranding.java b/Core/src/org/sleuthkit/autopsy/report/ReportBranding.java index ba50f34726..93b4ee0081 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportBranding.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportBranding.java @@ -63,7 +63,7 @@ public final class ReportBranding implements ReportBrandingProviderI { //initialize with extracting of resource files if needed, ensure 1 writer at a time synchronized (ReportBranding.class) { - reportsBrandingDir = PlatformUtil.getUserConfigDirectory() + File.separator + ReportGenerator.REPORTS_DIR + File.separator + reportsBrandingDir = PlatformUtil.getUserConfigDirectory() + File.separator + ReportGenerator.getReportsDirectory() + File.separator + "branding"; //NON-NLS File brandingDir = new File(reportsBrandingDir); if (!brandingDir.exists()) { diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressDialog.form b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form similarity index 86% rename from Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressDialog.form rename to Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form index 08cd8ec3f4..597dd89df4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressDialog.form +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.form @@ -79,7 +79,7 @@ - + @@ -91,7 +91,7 @@ - + @@ -104,14 +104,14 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java old mode 100755 new mode 100644 index 486e54789f..9b48b43a67 --- a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2019 Basis Technology Corp. + * Copyright 2012-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,23 +18,137 @@ */ package org.sleuthkit.autopsy.report; +import org.openide.util.NbBundle; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Desktop; +import java.awt.EventQueue; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; + /** - * This interface is necessary in order to not break backwards compatibility of - * GeneralReportModule interface. See JIRA-5354. + * A panel used by a report generation module to show progress. */ -public interface ReportProgressPanel { +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class ReportProgressPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(ReportProgressPanel.class.getName()); + private static final Color GREEN = new Color(50, 205, 50); + private static final Color RED = new Color(178, 34, 34); + private volatile ReportStatus status; /** * Used by a report generation module to communicate report generation * status to this panel and its listeners. */ + @NbBundle.Messages({ + "ReportProgressPanel.progress.queuing=Queuing...", + "ReportProgressPanel.progress.running=Running...", + "ReportProgressPanel.progress.complete=Complete", + "ReportProgressPanel.progress.canceled=Canceled", + "ReportProgressPanel.progress.error=Error",}) public enum ReportStatus { - QUEUING, - RUNNING, - COMPLETE, - CANCELED, - ERROR + QUEUING(Bundle.ReportProgressPanel_progress_queuing()), + RUNNING(Bundle.ReportProgressPanel_progress_running()), + COMPLETE(Bundle.ReportProgressPanel_progress_complete()), + CANCELED(Bundle.ReportProgressPanel_progress_canceled()), + ERROR(Bundle.ReportProgressPanel_progress_error()); + + private final String displayName; + + ReportStatus(String displayName) { + this.displayName = displayName; + } + + /** + * Gets the display name of the report status. + * + * @return The display name. + */ + public String getDisplayName() { + return displayName; + } + } + + /** + * Constructs a panel used by report generation module to show progress. + */ + public ReportProgressPanel() { + initComponents(); + reportProgressBar.setIndeterminate(true); + reportProgressBar.setMaximum(100); + statusMessageLabel.setText(Bundle.ReportProgressPanel_progress_queuing()); + status = ReportStatus.QUEUING; + reportLabel.setText(""); + pathLabel.setText(""); //NON-NLS + } + + /** + * Sets label text. + * + * @param reportName The name of the report being generated. + * @param reportPath The path to the report file. + */ + public final void setLabels(String reportName, String reportPath) { + reportLabel.setText(reportName); + if (null != reportPath) { + pathLabel.setText("" + shortenPath(reportPath) + ""); //NON-NLS + pathLabel.setToolTipText(reportPath); + String linkPath = reportPath; + pathLabel.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent mouseEvent) { + /* + * Do nothing for this event. + */ + } + + @Override + public void mousePressed(MouseEvent mouseEvent) { + /* + * Do nothing for this event. + */ + } + + @Override + public void mouseReleased(MouseEvent mouseEvent) { + File file = new File(linkPath); + try { + Desktop.getDesktop().open(file); + } catch (IOException ioex) { + logger.log(Level.SEVERE, "Error opening report file", ioex); + } catch (IllegalArgumentException iaEx) { + logger.log(Level.SEVERE, "Error opening report file", iaEx); + try { + Desktop.getDesktop().open(file.getParentFile()); + } catch (IOException ioEx2) { + logger.log(Level.SEVERE, "Error opening report file parent", ioEx2); + } + } + } + + @Override + public void mouseEntered(MouseEvent e3) { + pathLabel.setForeground(Color.DARK_GRAY); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + + @Override + public void mouseExited(MouseEvent e4) { + pathLabel.setForeground(Color.BLACK); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + }); + } else { + pathLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.initPathLabel.noFile")); + } } /** @@ -42,41 +156,81 @@ public interface ReportProgressPanel { * * @return The report generation status as a ReportStatus enum. */ - public ReportStatus getStatus(); + public ReportStatus getStatus() { + return status; + } + + /** + * Sets the current status of the generation of the report. + * + * @param status The current status. + */ + protected void setStatus(ReportStatus status) { + this.status = status; + } /** * Starts the progress bar component of this panel. */ - public void start(); + public void start() { + EventQueue.invokeLater(() -> { + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.start.progress.text")); + status = ReportStatus.RUNNING; + }); + } /** * Sets the maximum value of the progress bar component of this panel. * * @param max The maximum value. */ - public void setMaximumProgress(int max); + public void setMaximumProgress(int max) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setMaximum(max); + } + }); + } /** * Increments the current value of the progress bar component of this panel * by one unit. */ - public void increment(); + public void increment() { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setValue(reportProgressBar.getValue() + 1); + } + }); + } /** * Sets the current value of the progress bar component of this panel. * * @param value The value to be set. */ - public void setProgress(int value); + public void setProgress(int value) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setValue(value); + } + }); + } /** * Changes the the progress bar component of this panel to be determinate or * indeterminate. * * @param indeterminate True if the progress bar should be set to - * indeterminate. + * indeterminate. */ - public void setIndeterminate(boolean indeterminate); + public void setIndeterminate(boolean indeterminate) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + reportProgressBar.setIndeterminate(indeterminate); + } + }); + } /** * Changes the status message label component of this panel to show a given @@ -85,7 +239,13 @@ public interface ReportProgressPanel { * * @param statusMessage String to use as label text. */ - public void updateStatusLabel(String statusMessage); + public void updateStatusLabel(String statusMessage) { + EventQueue.invokeLater(() -> { + if (status != ReportStatus.CANCELED) { + statusMessageLabel.setText(statusMessage); + } + }); + } /** * Makes the components of this panel indicate the final status of @@ -93,16 +253,196 @@ public interface ReportProgressPanel { * * @param reportStatus The final status, must be COMPLETE or ERROR. */ - public void complete(ReportStatus reportStatus); + public void complete(ReportStatus reportStatus) { + + switch (reportStatus) { + case COMPLETE: + complete(reportStatus, NbBundle.getMessage(this.getClass(), "ReportProgressPanel.complete.processLbl.text")); + break; + case ERROR: + complete(reportStatus, NbBundle.getMessage(this.getClass(), "ReportProgressPanel.complete.processLb2.text")); + break; + default: + complete(reportStatus, ""); + break; + } + } /** * Makes the components of this panel indicate the final status of * generation of the report. * - * @param reportStatus The final status, must be COMPLETE or ERROR. + * @param reportStatus The final status, must be COMPLETE or ERROR. * @param statusMessage String to use as label or error text. */ - public void complete(ReportStatus reportStatus, String statusMessage); + public void complete(ReportStatus reportStatus, String statusMessage) { + EventQueue.invokeLater(() -> { + reportProgressBar.setIndeterminate(false); + if (status != ReportStatus.CANCELED) { + switch (reportStatus) { + case COMPLETE: { + ReportStatus oldValue = status; + status = ReportStatus.COMPLETE; + statusMessageLabel.setForeground(Color.BLACK); + statusMessageLabel.setText(statusMessage); + reportProgressBar.setValue(reportProgressBar.getMaximum()); + reportProgressBar.setStringPainted(true); + reportProgressBar.setForeground(GREEN); + reportProgressBar.setString(ReportStatus.COMPLETE.getDisplayName()); + firePropertyChange(ReportStatus.COMPLETE.toString(), oldValue, status); + break; + } + case ERROR: { + ReportStatus oldValue = status; + status = ReportStatus.ERROR; + statusMessageLabel.setForeground(RED); + statusMessageLabel.setText(statusMessage); + reportProgressBar.setValue(reportProgressBar.getMaximum()); + reportProgressBar.setStringPainted(true); + reportProgressBar.setForeground(RED); + reportProgressBar.setString(ReportStatus.ERROR.getDisplayName()); + firePropertyChange(ReportStatus.COMPLETE.toString(), oldValue, status); + break; + } + default: { + break; + } + } + } + }); + } + + /** + * Makes the components of this panel indicate generation of the report was + * cancelled. + */ + public void cancel() { + switch (status) { + case COMPLETE: + break; + case CANCELED: + break; + case ERROR: + break; + default: + ReportStatus oldValue = status; + status = ReportStatus.CANCELED; + reportProgressBar.setIndeterminate(false); + reportProgressBar.setValue(0); + reportProgressBar.setStringPainted(true); + reportProgressBar.setForeground(RED); // Red + reportProgressBar.setString(ReportStatus.CANCELED.getDisplayName()); + firePropertyChange(ReportStatus.CANCELED.toString(), oldValue, status); + statusMessageLabel.setForeground(RED); + statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressPanel.cancel.procLbl.text")); + break; + } + } + + /** + * Gets a shortened version of a file path. + * + * @param path The path to shorten. + * + * @return The shortened path. + */ + private String shortenPath(String path) { + if (path.length() > 100) { + return path.substring(0, 10 + path.substring(10).indexOf(File.separator) + 1) + "..." + + path.substring((path.length() - 70) + path.substring(path.length() - 70).indexOf(File.separator)); + } else { + return path; + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + reportProgressBar = new javax.swing.JProgressBar(); + reportLabel = new javax.swing.JLabel(); + pathLabel = new javax.swing.JLabel(); + separationLabel = new javax.swing.JLabel(); + statusMessageLabel = new javax.swing.JLabel(); + + setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + setMinimumSize(new java.awt.Dimension(486, 68)); + + reportProgressBar.setFont(reportProgressBar.getFont().deriveFont(reportProgressBar.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + + reportLabel.setFont(reportLabel.getFont().deriveFont(reportLabel.getFont().getStyle() | java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(reportLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.reportLabel.text")); // NOI18N + + pathLabel.setFont(pathLabel.getFont().deriveFont(pathLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.pathLabel.text")); // NOI18N + pathLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + + separationLabel.setFont(separationLabel.getFont().deriveFont(separationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(separationLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.separationLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(statusMessageLabel, org.openide.util.NbBundle.getMessage(ReportProgressPanel.class, "ReportProgressPanel.statusMessageLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(statusMessageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(reportProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(reportLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(separationLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 548, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(reportProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(reportLabel) + .addComponent(pathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(separationLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(statusMessageLabel) + .addGap(13, 13, 13)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel pathLabel; + private javax.swing.JLabel reportLabel; + private javax.swing.JProgressBar reportProgressBar; + private javax.swing.JLabel separationLabel; + private javax.swing.JLabel statusMessageLabel; + // End of variables declaration//GEN-END:variables + + /** + * Constructs a panel used by a report generation module to show progress. + * + * @param reportName The report name. + * @param reportPath The report path. + * + * @deprecated Use {@link #ReportProgressPanel()} and {@link #setLabels()} + * instead. + */ + @Deprecated + public ReportProgressPanel(String reportName, String reportPath) { + this(); + setLabels(reportName, reportPath); + } /** * Makes the components of this panel indicate the generation of the report @@ -111,5 +451,8 @@ public interface ReportProgressPanel { * @deprecated Use {@link #complete(ReportStatus)} */ @Deprecated - public void complete(); + public void complete() { + complete(ReportStatus.COMPLETE); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties index 38c1f3696d..c6f840be32 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties @@ -6,10 +6,6 @@ ReportWizardFileOptionsVisualPanel.selectAllButton.text=Select All ReportWizardPortableCaseOptionsVisualPanel.errorLabel.text=Windows only ReportWizardPortableCaseOptionsVisualPanel.compressCheckbox.toolTipText= ReportWizardPortableCaseOptionsVisualPanel.compressCheckbox.text=Package case into an archive: -ReportProgressDialog.reportLabel.text=reportLabel -ReportProgressDialog.statusMessageLabel.text=processingLabel -ReportProgressDialog.separationLabel.text=: -ReportProgressDialog.pathLabel.text=pathLabel PortableCaseTagsListPanel.jAllTagsCheckBox.text=All Tagged Results PortableCaseTagsListPanel.deselectButton.text=Deselect All PortableCaseTagsListPanel.selectButton.text=Select All @@ -151,15 +147,6 @@ ReportGenerator.artTableColHdr.localPath=Local path ReportGenerator.artTableColHdr.remotePath=Remote path ReportGenerator.errors.reportErrorTitle=Error generating report ReportGenerator.errors.reportErrorText=Error generating report: -ReportProgressDialog.progress.queuing=Queuing... -ReportProgressDialog.initPathLabel.noFile=No report file -ReportProgressDialog.start.cancelButton.text=Cancel -ReportProgressDialog.start.progress.text=Starting report... -ReportProgressDialog.complete.processLbl.text=Complete -ReportProgressDialog.complete.processLb2.text=Completed with error -ReportProgressDialog.complete.cancelButton.text=Complete -ReportProgressDialog.cancel.cancelButton.toolTipText=Canceled -ReportProgressDialog.cancel.procLbl.text=Canceled ReportVisualPanel1.getName.text=Select and Configure Report Modules ReportVisualPanel2.getName.text=Configure Report ReportWizardAction.actionName.text=Generate Report diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED index b2ca427081..c3bca8db45 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED @@ -9,16 +9,18 @@ PortableCaseTagsListPanel.error.noOpenCase=There is no case open ReportGenerator.artTableColHdr.comment=Comment ReportGenerator.errList.noOpenCase=No open case available. ReportGenerator.tagTable.header.userName=User Name +ReportProgressIndicator.cancelledMessage=Report generation cancelled +ReportProgressIndicator.completedMessage=Report generation completed +ReportProgressIndicator.completedWithErrorsMessage=Report generation completed with errors +ReportProgressIndicator.startMessage=Report generation started +ReportProgressIndicator.switchToDeterminateMessage=Report generation progress switched to determinate +ReportProgressIndicator.switchToIndeterminateMessage=Report generation progress switched to indeterminate ReportWizardFileOptionsVisualPanel.jLabel1.text=Select items to include in File Report: ReportWizardFileOptionsVisualPanel.deselectAllButton.text=Deselect All ReportWizardFileOptionsVisualPanel.selectAllButton.text=Select All ReportWizardPortableCaseOptionsVisualPanel.errorLabel.text=Windows only ReportWizardPortableCaseOptionsVisualPanel.compressCheckbox.toolTipText= ReportWizardPortableCaseOptionsVisualPanel.compressCheckbox.text=Package case into an archive: -ReportProgressDialog.reportLabel.text=reportLabel -ReportProgressDialog.statusMessageLabel.text=processingLabel -ReportProgressDialog.separationLabel.text=: -ReportProgressDialog.pathLabel.text=pathLabel PortableCaseTagsListPanel.jAllTagsCheckBox.text=All Tagged Results PortableCaseTagsListPanel.deselectButton.text=Deselect All PortableCaseTagsListPanel.selectButton.text=Select All @@ -160,15 +162,6 @@ ReportGenerator.artTableColHdr.localPath=Local path ReportGenerator.artTableColHdr.remotePath=Remote path ReportGenerator.errors.reportErrorTitle=Error generating report ReportGenerator.errors.reportErrorText=Error generating report: -ReportProgressDialog.progress.queuing=Queuing... -ReportProgressDialog.initPathLabel.noFile=No report file -ReportProgressDialog.start.cancelButton.text=Cancel -ReportProgressDialog.start.progress.text=Starting report... -ReportProgressDialog.complete.processLbl.text=Complete -ReportProgressDialog.complete.processLb2.text=Completed with error -ReportProgressDialog.complete.cancelButton.text=Complete -ReportProgressDialog.cancel.cancelButton.toolTipText=Canceled -ReportProgressDialog.cancel.procLbl.text=Canceled ReportVisualPanel1.getName.text=Select and Configure Report Modules ReportVisualPanel2.getName.text=Configure Report ReportWizardAction.actionName.text=Generate Report diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties index 6aefb4b05b..c911dd381d 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties @@ -2,10 +2,6 @@ CTL_ReportWizardAction=\u30ec\u30dd\u30fc\u30c8\u3092\u5b9f\u884c ReportWizardFileOptionsVisualPanel.selectAllButton.text=\u5168\u3066\u9078\u629e ReportWizardFileOptionsVisualPanel.jLabel1.text=\u30d5\u30a1\u30a4\u30eb\u30ec\u30dd\u30fc\u30c8\u306b\u542b\u3081\u308b\u30a2\u30a4\u30c6\u30e0\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044\uff1a ReportWizardFileOptionsVisualPanel.deselectAllButton.text=\u5168\u3066\u9078\u629e\u89e3\u9664 -ReportProgressDialog.pathLabel.text=\u30d1\u30b9\u30e9\u30d9\u30eb -ReportProgressDialog.reportLabel.text=\u30ec\u30dd\u30fc\u30c8\u30e9\u30d9\u30eb -ReportProgressDialog.statusMessageLabel.text=\u30d7\u30ed\u30bb\u30b7\u30f3\u30b0\u30e9\u30d9\u30eb -ReportProgressDialog.separationLabel.text=: ReportGenerationPanel.closeButton.text=\u9589\u3058\u308b ReportGenerationPanel.cancelButton.actionCommand=\u30ad\u30e3\u30f3\u30bb\u30eb ReportGenerationPanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerationPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerationPanel.java index ec391d6d93..021c330372 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerationPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,21 +25,21 @@ import javax.swing.Box; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; +import org.sleuthkit.autopsy.report.ReportProgressPanel; /** * A panel that displays a panel used by a report generation module to show * progress. It provides OK and Cancel buttons. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -class ReportGenerationPanel extends javax.swing.JPanel { +final class ReportGenerationPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private final GridBagConstraints constraints; private final Component glue; private ActionListener actionListener; - ReportProgressDialog progressPanel; + private final ReportProgressPanel progressPanel; /** * Constructs a panel that displays a panel used by a report generation @@ -54,10 +54,10 @@ class ReportGenerationPanel extends javax.swing.JPanel { constraints.gridy = 0; constraints.weightx = 1.0; glue = Box.createVerticalGlue(); - progressPanel = new ReportProgressDialog(); + progressPanel = new ReportProgressPanel(); } - - ReportProgressDialog getProgressPanel() { + + ReportProgressPanel getProgressPanel() { return progressPanel; } diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java index 68d69ed88f..c88d05b94e 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java @@ -41,7 +41,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import javax.swing.JDialog; -import javax.swing.JFrame; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; @@ -55,24 +54,33 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +/** + * A report generator that generates one or more reports by running + * user-selected report modules. + */ public class ReportGenerator { private static final Logger logger = Logger.getLogger(ReportGenerator.class.getName()); - - private ReportProgressPanel progressPanel = null; - private ReportGenerationPanel reportGenerationPanel = null; - + private final ReportProgressPanel progressIndicator; + private final ReportGenerationPanel reportGenerationPanel; private static final String REPORT_PATH_FMT_STR = "%s" + File.separator + "%s %s %s" + File.separator; - private final String configName; - - public static final String REPORTS_DIR = "Reports"; //NON-NLS - - private List errorList; + private static final String REPORTS_DIR = "Reports"; //NON-NLS + private List errorList = new ArrayList<>(); /** - * Displays the list of errors during report generation in user-friendly - * way. + * Gets the name of the reports directory within the case direcotry + * hierarchy. + * + * @return The directory name. + */ + public static String getReportsDirectory() { + return REPORTS_DIR; + } + + /** + * Displays a list of errors emitted by report modules during report + * generation using this report generator's report progress indicator. */ private void displayReportErrors() { if (!errorList.isEmpty()) { @@ -80,41 +88,41 @@ public class ReportGenerator { for (String error : errorList) { errorString += error + "\n"; } - progressPanel.updateStatusLabel(errorString); + progressIndicator.updateStatusLabel(errorString); } } /** - * Creates a report generator. This constructor uses a logger instead of UI - * panel. + * Constructs a report generator that generates one or more reports by + * running user-selected report modules and uses a report progress indicator + * to display progress. * - * @param configName Name of the reporting configuration to use - * @param progress Fully instantiated progress logger + * @param configName The name of the reporting configuration to use. + * @param progressIndicator The report progress indicator. */ - public ReportGenerator(String configName, ReportProgressLogger progress) { - this.errorList = new ArrayList<>(); - this.progressPanel = progress; + public ReportGenerator(String configName, ReportProgressIndicator progressIndicator) { + this.progressIndicator = progressIndicator; this.reportGenerationPanel = null; this.configName = configName; } - + /** - * Creates a report generator. This constructor uses UI panel to display - * progress. + * Constructs a report generator that generates one or more reports by + * running user-selected report modules and uses a report generation panel + * to display progress. * - * @param configName Name of the reporting configuration to use - * @param panel Fully instantiated progress panel + * @param configName The name of the reporting configuration to use. + * @param panel The report generation panel. */ - public ReportGenerator(String configName, ReportGenerationPanel panel) { - this.errorList = new ArrayList<>(); + ReportGenerator(String configName, ReportGenerationPanel panel) { this.reportGenerationPanel = panel; - this.progressPanel = panel.getProgressPanel(); + this.progressIndicator = panel.getProgressPanel(); this.configName = configName; } /** - * Generate reports according to previously specified reporting - * configuration. + * Generates the reports specified by the reporting configuration passed in + * via the constructor. */ public void generateReports() { ReportingConfig config = null; @@ -122,13 +130,13 @@ public class ReportGenerator { config = ReportingConfigLoader.loadConfig(configName); } catch (ReportConfigException ex) { logger.log(Level.SEVERE, "Unable to load reporting configuration " + configName + ". Exiting", ex); - progressPanel.updateStatusLabel("Unable to load reporting configuration " + configName + ". Exiting"); + progressIndicator.updateStatusLabel("Unable to load reporting configuration " + configName + ". Exiting"); return; } if (config == null) { logger.log(Level.SEVERE, "Unable to load reporting configuration {0}. Exiting", configName); - progressPanel.updateStatusLabel("Unable to load reporting configuration " + configName + ". Exiting"); + progressIndicator.updateStatusLabel("Unable to load reporting configuration " + configName + ". Exiting"); return; } @@ -162,7 +170,7 @@ public class ReportGenerator { ReportModule module = modules.get(moduleName); if (module == null) { logger.log(Level.SEVERE, "Report module {0} not found", moduleName); - progressPanel.updateStatusLabel("Report module " + moduleName + " not found"); + progressIndicator.updateStatusLabel("Report module " + moduleName + " not found"); continue; } @@ -189,7 +197,7 @@ public class ReportGenerator { TableReportSettings tableSettings = config.getTableReportSettings(); if (tableSettings == null) { logger.log(Level.SEVERE, "No table report settings for report module {0}", moduleName); - progressPanel.updateStatusLabel("No table report settings for report module " + moduleName); + progressIndicator.updateStatusLabel("No table report settings for report module " + moduleName); continue; } @@ -201,7 +209,7 @@ public class ReportGenerator { FileReportSettings fileSettings = config.getFileReportSettings(); if (fileSettings == null) { logger.log(Level.SEVERE, "No file report settings for report module {0}", moduleName); - progressPanel.updateStatusLabel("No file report settings for report module " + moduleName); + progressIndicator.updateStatusLabel("No file report settings for report module " + moduleName); continue; } @@ -213,7 +221,7 @@ public class ReportGenerator { settings = new PortableCaseReportModuleSettings(); } else if (!(settings instanceof PortableCaseReportModuleSettings)) { logger.log(Level.SEVERE, "Invalid settings for report module {0}", moduleName); - progressPanel.updateStatusLabel("Invalid settings for report module " + moduleName); + progressIndicator.updateStatusLabel("Invalid settings for report module " + moduleName); continue; } @@ -221,12 +229,11 @@ public class ReportGenerator { } else { logger.log(Level.SEVERE, "Report module {0} has unsupported report module type", moduleName); - progressPanel.updateStatusLabel("Report module " + moduleName + " has unsupported report module type"); - continue; + progressIndicator.updateStatusLabel("Report module " + moduleName + " has unsupported report module type"); } } catch (IOException e) { logger.log(Level.SEVERE, "Exception while running report module {0}: {1}", new Object[]{moduleName, e.getMessage()}); - progressPanel.updateStatusLabel("Exception while running report module " + moduleName); + progressIndicator.updateStatusLabel("Exception while running report module " + moduleName); } } } finally { @@ -244,7 +251,7 @@ public class ReportGenerator { return; } - final JDialog dialog = new JDialog((JFrame) WindowManager.getDefault().getMainWindow(), true); + final JDialog dialog = new JDialog(WindowManager.getDefault().getMainWindow(), true); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setTitle(NbBundle.getMessage(this.getClass(), "ReportGenerator.displayProgress.title.text")); dialog.add(this.reportGenerationPanel); @@ -275,7 +282,7 @@ public class ReportGenerator { if (generalReportModule != null) { String reportDir = createReportDirectory(generalReportModule); setupProgressPanel(generalReportModule, reportDir); - generalReportModule.generateReport(reportDir, progressPanel); + generalReportModule.generateReport(reportDir, progressIndicator); } } @@ -290,11 +297,11 @@ public class ReportGenerator { String reportDir = createReportDirectory(tableReport); setupProgressPanel(tableReport, reportDir); tableReport.startReport(reportDir); - TableReportGenerator generator = new TableReportGenerator(tableReportSettings, progressPanel, tableReport); + TableReportGenerator generator = new TableReportGenerator(tableReportSettings, progressIndicator, tableReport); generator.execute(); tableReport.endReport(); // finish progress, wrap up - progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE); + progressIndicator.complete(ReportProgressPanel.ReportStatus.COMPLETE); errorList = generator.getErrorList(); } } @@ -315,34 +322,34 @@ public class ReportGenerator { } } setupProgressPanel(fileReportModule, reportDir); - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - progressPanel.start(); - progressPanel.updateStatusLabel( + if (progressIndicator.getStatus() != ReportStatus.CANCELED) { + progressIndicator.start(); + progressIndicator.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); } List files = getFiles(); int numFiles = files.size(); - if (progressPanel.getStatus() != ReportStatus.CANCELED) { + if (progressIndicator.getStatus() != ReportStatus.CANCELED) { fileReportModule.startReport(reportDir); fileReportModule.startTable(enabled); } - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(numFiles); + progressIndicator.setIndeterminate(false); + progressIndicator.setMaximumProgress(numFiles); int i = 0; // Add files to report. for (AbstractFile file : files) { // Check to see if any reports have been cancelled. - if (progressPanel.getStatus() == ReportStatus.CANCELED) { + if (progressIndicator.getStatus() == ReportStatus.CANCELED) { return; } else { fileReportModule.addRow(file, enabled); - progressPanel.increment(); + progressIndicator.increment(); } if ((i % 100) == 0) { - progressPanel.updateStatusLabel( + progressIndicator.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", file.getName())); } @@ -351,7 +358,7 @@ public class ReportGenerator { fileReportModule.endTable(); fileReportModule.endReport(); - progressPanel.complete(ReportStatus.COMPLETE); + progressIndicator.complete(ReportStatus.COMPLETE); } } @@ -362,7 +369,7 @@ public class ReportGenerator { if (portableCaseReportModule != null) { String reportDir = createReportDirectory(portableCaseReportModule); setupProgressPanel(portableCaseReportModule, reportDir); - portableCaseReportModule.generateReport(reportDir, settings, progressPanel); + portableCaseReportModule.generateReport(reportDir, settings, progressIndicator); } } @@ -378,7 +385,7 @@ public class ReportGenerator { absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS return absFiles; } catch (TskCoreException | NoCurrentCaseException ex) { - progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage()); + progressIndicator.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage()); logger.log(Level.SEVERE, "failed to generate reports. Unable to get all files in the image.", ex); //NON-NLS return Collections.emptyList(); } diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressDialog.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressDialog.java deleted file mode 100644 index 6116edc3d0..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressDialog.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 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.report.infrastructure; - -import org.openide.util.NbBundle; -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Desktop; -import java.awt.EventQueue; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.io.File; -import java.io.IOException; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.report.ReportProgressPanel; - -/** - * A panel used by a report generation module to show progress. - */ -@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -class ReportProgressDialog extends javax.swing.JPanel implements ReportProgressPanel { - - private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(ReportProgressDialog.class.getName()); - private static final Color GREEN = new Color(50, 205, 50); - private static final Color RED = new Color(178, 34, 34); - private volatile ReportProgressPanel.ReportStatus status; - - /** - * Constructs a panel used by report generation module to show progress. - */ - ReportProgressDialog() { - initComponents(); - reportProgressBar.setIndeterminate(true); - reportProgressBar.setMaximum(100); - statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressDialog.progress.queuing")); - status = ReportStatus.QUEUING; - reportLabel.setText(""); - pathLabel.setText(""); //NON-NLS - } - - /** - * Sets label text. - * - * @param reportName The name of the report being generated. - * @param reportPath The path to the report file. - */ - void setLabels(String reportName, String reportPath) { - reportLabel.setText(reportName); - if (null != reportPath) { - pathLabel.setText("" + shortenPath(reportPath) + ""); //NON-NLS - pathLabel.setToolTipText(reportPath); - String linkPath = reportPath; - pathLabel.addMouseListener(new MouseListener() { - - @Override - public void mouseClicked(MouseEvent mouseEvent) { - } - - @Override - public void mousePressed(MouseEvent mouseEvent) { - } - - @Override - public void mouseReleased(MouseEvent mouseEvent) { - File file = new File(linkPath); - try { - Desktop.getDesktop().open(file); - } catch (IOException ioex) { - logger.log(Level.SEVERE, "Error opening report file", ioex); - } catch (IllegalArgumentException iaEx) { - logger.log(Level.SEVERE, "Error opening report file", iaEx); - try { - Desktop.getDesktop().open(file.getParentFile()); - } catch (IOException ioEx2) { - logger.log(Level.SEVERE, "Error opening report file parent", ioEx2); - } - } - } - - @Override - public void mouseEntered(MouseEvent e3) { - pathLabel.setForeground(Color.DARK_GRAY); - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - - @Override - public void mouseExited(MouseEvent e4) { - pathLabel.setForeground(Color.BLACK); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - }); - } else { - pathLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressDialog.initPathLabel.noFile")); - } - } - - /** - * Gets the current status of the generation of the report. - * - * @return The report generation status as a ReportStatus enum. - */ - @Override - public ReportStatus getStatus() { - return status; - } - - /** - * Starts the progress bar component of this panel. - */ - @Override - public void start() { - EventQueue.invokeLater(() -> { - statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressDialog.start.progress.text")); - status = ReportStatus.RUNNING; - }); - } - - /** - * Sets the maximum value of the progress bar component of this panel. - * - * @param max The maximum value. - */ - @Override - public void setMaximumProgress(int max) { - EventQueue.invokeLater(() -> { - if (status != ReportStatus.CANCELED) { - reportProgressBar.setMaximum(max); - } - }); - } - - /** - * Increments the current value of the progress bar component of this panel - * by one unit. - */ - @Override - public void increment() { - EventQueue.invokeLater(() -> { - if (status != ReportStatus.CANCELED) { - reportProgressBar.setValue(reportProgressBar.getValue() + 1); - } - }); - } - - /** - * Sets the current value of the progress bar component of this panel. - * - * @param value The value to be set. - */ - @Override - public void setProgress(int value) { - EventQueue.invokeLater(() -> { - if (status != ReportStatus.CANCELED) { - reportProgressBar.setValue(value); - } - }); - } - - /** - * Changes the the progress bar component of this panel to be determinate or - * indeterminate. - * - * @param indeterminate True if the progress bar should be set to - * indeterminate. - */ - @Override - public void setIndeterminate(boolean indeterminate) { - EventQueue.invokeLater(() -> { - if (status != ReportStatus.CANCELED) { - reportProgressBar.setIndeterminate(indeterminate); - } - }); - } - - /** - * Changes the status message label component of this panel to show a given - * processing status message. For example, updateStatusLabel("Now processing - * files...") sets the label text to "Now processing files..." - * - * @param statusMessage String to use as label text. - */ - @Override - public void updateStatusLabel(String statusMessage) { - EventQueue.invokeLater(() -> { - if (status != ReportStatus.CANCELED) { - statusMessageLabel.setText(statusMessage); - } - }); - } - - /** - * Makes the components of this panel indicate the final status of - * generation of the report. - * - * @param reportStatus The final status, must be COMPLETE or ERROR. - */ - @Override - public void complete(ReportStatus reportStatus) { - - switch (reportStatus) { - case COMPLETE: - complete(reportStatus, NbBundle.getMessage(this.getClass(), "ReportProgressDialog.complete.processLbl.text")); - break; - case ERROR: - complete(reportStatus, NbBundle.getMessage(this.getClass(), "ReportProgressDialog.complete.processLb2.text")); - break; - default: - complete(reportStatus, ""); - break; - } - } - - /** - * Makes the components of this panel indicate the final status of - * generation of the report. - * - * @param reportStatus The final status, must be COMPLETE or ERROR. - * @param statusMessage String to use as label or error text. - */ - @Override - public void complete(ReportStatus reportStatus, String statusMessage) { - EventQueue.invokeLater(() -> { - reportProgressBar.setIndeterminate(false); - if (status != ReportStatus.CANCELED) { - switch (reportStatus) { - case COMPLETE: { - ReportStatus oldValue = status; - status = ReportStatus.COMPLETE; - statusMessageLabel.setForeground(Color.BLACK); - statusMessageLabel.setText(statusMessage); - reportProgressBar.setValue(reportProgressBar.getMaximum()); - reportProgressBar.setStringPainted(true); - reportProgressBar.setForeground(GREEN); - reportProgressBar.setString("Complete"); //NON-NLS - firePropertyChange(ReportStatus.COMPLETE.toString(), oldValue, status); - break; - } - case ERROR: { - ReportStatus oldValue = status; - status = ReportStatus.ERROR; - statusMessageLabel.setForeground(RED); - statusMessageLabel.setText(statusMessage); - reportProgressBar.setValue(reportProgressBar.getMaximum()); - reportProgressBar.setStringPainted(true); - reportProgressBar.setForeground(RED); - reportProgressBar.setString("Error"); //NON-NLS - firePropertyChange(ReportStatus.COMPLETE.toString(), oldValue, status); - break; - } - default: { - break; - } - } - } - }); - } - - /** - * Makes the components of this panel indicate generation of the report was - * cancelled. - */ - void cancel() { - switch (status) { - case COMPLETE: - break; - case CANCELED: - break; - case ERROR: - break; - default: - ReportStatus oldValue = status; - status = ReportStatus.CANCELED; - reportProgressBar.setIndeterminate(false); - reportProgressBar.setValue(0); - reportProgressBar.setStringPainted(true); - reportProgressBar.setForeground(RED); // Red - reportProgressBar.setString("Cancelled"); //NON-NLS - firePropertyChange(ReportStatus.CANCELED.toString(), oldValue, status); - statusMessageLabel.setForeground(RED); - statusMessageLabel.setText(NbBundle.getMessage(this.getClass(), "ReportProgressDialog.cancel.procLbl.text")); - break; - } - } - - /** - * Gets a shortened version of a file path. - * - * @param path The path to shorten. - * - * @return The shortened path. - */ - private String shortenPath(String path) { - if (path.length() > 100) { - return path.substring(0, 10 + path.substring(10).indexOf(File.separator) + 1) + "..." - + path.substring((path.length() - 70) + path.substring(path.length() - 70).indexOf(File.separator)); - } else { - return path; - } - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - reportProgressBar = new javax.swing.JProgressBar(); - reportLabel = new javax.swing.JLabel(); - pathLabel = new javax.swing.JLabel(); - separationLabel = new javax.swing.JLabel(); - statusMessageLabel = new javax.swing.JLabel(); - - setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - setMinimumSize(new java.awt.Dimension(486, 68)); - - reportProgressBar.setFont(reportProgressBar.getFont().deriveFont(reportProgressBar.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - - reportLabel.setFont(reportLabel.getFont().deriveFont(reportLabel.getFont().getStyle() | java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(reportLabel, org.openide.util.NbBundle.getMessage(ReportProgressDialog.class, "ReportProgressDialog.reportLabel.text")); // NOI18N - - pathLabel.setFont(pathLabel.getFont().deriveFont(pathLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ReportProgressDialog.class, "ReportProgressDialog.pathLabel.text")); // NOI18N - pathLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); - - separationLabel.setFont(separationLabel.getFont().deriveFont(separationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(separationLabel, org.openide.util.NbBundle.getMessage(ReportProgressDialog.class, "ReportProgressDialog.separationLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(statusMessageLabel, org.openide.util.NbBundle.getMessage(ReportProgressDialog.class, "ReportProgressDialog.statusMessageLabel.text")); // NOI18N - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(statusMessageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(reportProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(reportLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(separationLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 548, Short.MAX_VALUE))) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(reportProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(reportLabel) - .addComponent(pathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(separationLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(statusMessageLabel) - .addGap(13, 13, 13)) - ); - }// //GEN-END:initComponents - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel pathLabel; - private javax.swing.JLabel reportLabel; - private javax.swing.JProgressBar reportProgressBar; - private javax.swing.JLabel separationLabel; - private javax.swing.JLabel statusMessageLabel; - // End of variables declaration//GEN-END:variables - - /** - * Makes the components of this panel indicate the generation of the report - * is completed. - * - * @deprecated Use {@link #complete(ReportStatus)} - */ - @Deprecated - @Override - public void complete() { - complete(ReportStatus.COMPLETE); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressIndicator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressIndicator.java new file mode 100755 index 0000000000..a0e0b968fc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressIndicator.java @@ -0,0 +1,141 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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.report.infrastructure; + +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.progress.ProgressIndicator; +import org.sleuthkit.autopsy.report.ReportProgressPanel; + +/** + * An adapter that adapts the ReportProgressPanel interface to the + * ProgressIndicator interface so that a given progress indicator can be used + * where a ReportProgressPanel is expected. + */ +public class ReportProgressIndicator extends ReportProgressPanel { + + private static final long serialVersionUID = 1L; + private final ProgressIndicator progressIndicator; + private int workUnitsCompleted; + + /** + * Constructs an adapter that adapts the ReportProgressPanel interface to + * the ProgressIndicator interface so that a given progress indicator can be + * used where a ReportProgressPanel is expected. + * + * @param progressIndicator The progress indicator to be adapted. + */ + public ReportProgressIndicator(ProgressIndicator progressIndicator) { + this.progressIndicator = progressIndicator; + } + + @Override + @NbBundle.Messages({ + "ReportProgressIndicator.startMessage=Report generation started" + }) + public void start() { + workUnitsCompleted = 0; + setStatus(ReportStatus.RUNNING); + progressIndicator.start(Bundle.ReportProgressIndicator_startMessage()); + } + + @Override + @NbBundle.Messages({ + "ReportProgressIndicator.switchToDeterminateMessage=Report generation progress switched to determinate" + }) + public void setMaximumProgress(int max) { + progressIndicator.switchToDeterminate(Bundle.ReportProgressIndicator_switchToDeterminateMessage(), 0, max); + } + + @Override + public void increment() { + ++workUnitsCompleted; + progressIndicator.progress(workUnitsCompleted); + } + + @Override + public void setProgress(int value) { + workUnitsCompleted = value; + progressIndicator.progress(workUnitsCompleted); + } + + @Override + @NbBundle.Messages({ + "ReportProgressIndicator.switchToIndeterminateMessage=Report generation progress switched to indeterminate" + }) + public void setIndeterminate(boolean indeterminate) { + progressIndicator.switchToIndeterminate(Bundle.ReportProgressIndicator_switchToIndeterminateMessage()); + } + + @Override + public void updateStatusLabel(String statusMessage) { + if (getStatus() != ReportStatus.CANCELED) { + progressIndicator.progress(statusMessage); + } + } + + @Override + @NbBundle.Messages({ + "ReportProgressIndicator.completedMessage=Report generation completed", + "ReportProgressIndicator.completedWithErrorsMessage=Report generation completed with errors",}) + public void complete(ReportStatus reportStatus) { + if (getStatus() != ReportStatus.CANCELED) { + switch (reportStatus) { + case COMPLETE: { + progressIndicator.progress(Bundle.ReportProgressIndicator_completedMessage()); + break; + } + case ERROR: { + progressIndicator.progress(Bundle.ReportProgressIndicator_completedWithErrorsMessage()); + break; + } + default: { + break; + } + } + } + progressIndicator.finish(); + } + + @Override + public void complete(ReportStatus reportStatus, String statusMessage) { + if (getStatus() != ReportStatus.CANCELED) { + progressIndicator.progress(statusMessage); + } + complete(reportStatus); + } + + @Override + @NbBundle.Messages({ + "ReportProgressIndicator.cancelledMessage=Report generation cancelled",}) + public void cancel() { + switch (getStatus()) { + case COMPLETE: + break; + case CANCELED: + break; + case ERROR: + break; + default: + setStatus(ReportStatus.CANCELED); + progressIndicator.progress(Bundle.ReportProgressIndicator_cancelledMessage()); + break; + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressLogger.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressLogger.java deleted file mode 100755 index 697050052c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportProgressLogger.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 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.report.infrastructure; - -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.report.ReportProgressPanel; - -/** - * Writes progress and status messages to the application log. - */ -public class ReportProgressLogger implements ReportProgressPanel { - - private static final Logger logger = Logger.getLogger(ReportProgressLogger.class.getName()); - private volatile ReportProgressPanel.ReportStatus status; - - public ReportProgressLogger() { - status = ReportStatus.QUEUING; - } - - /** - * Gets the current status of the generation of the report. - * - * @return The report generation status as a ReportStatus enum. - */ - @Override - public ReportStatus getStatus() { - return status; - } - - /** - * Logs that the report has been started. - */ - @Override - public void start() { - status = ReportStatus.RUNNING; - logger.log(Level.INFO, "Report started"); - } - - /** - * NO-OP. - * - * @param max The maximum value. - */ - @Override - public void setMaximumProgress(int max) { - } - - /** - * NO-OP. - */ - @Override - public void increment() { - } - - /** - * NO-OP. - * - * @param value The value to be set. - */ - @Override - public void setProgress(int value) { - } - - /** - * NO-OP. - * - * @param indeterminate True if the progress bar should be set to - * indeterminate. - */ - @Override - public void setIndeterminate(boolean indeterminate) { - } - - /** - * Logs the status message. - * - * @param statusMessage String to use as label text. - */ - @Override - public void updateStatusLabel(String statusMessage) { - if (status != ReportStatus.CANCELED) { - logger.log(Level.INFO, statusMessage); - } - } - - /** - * Logs the final status of the report generation. - * - * @param reportStatus The final status, must be COMPLETE or ERROR. - * @param statusMessage String to use as label or error text. - */ - @Override - public void complete(ReportStatus reportStatus, String statusMessage) { - if (!statusMessage.isEmpty()) { - logger.log(Level.INFO, statusMessage); - } - if (status != ReportStatus.CANCELED) { - switch (reportStatus) { - case COMPLETE: { - status = ReportStatus.COMPLETE; - logger.log(Level.INFO, "Report completed"); - break; - } - case ERROR: { - status = ReportStatus.ERROR; - logger.log(Level.INFO, "Report completed with errors"); - break; - } - default: { - break; - } - } - } - } - - /** - * Logs the final status of the report generation. - * - * @param reportStatus The final status, must be COMPLETE or ERROR. - */ - @Override - public void complete(ReportStatus reportStatus) { - complete(reportStatus, ""); - } - - /** - * Logs that the generation of the report was cancelled. - */ - void cancel() { - switch (status) { - case COMPLETE: - break; - case CANCELED: - break; - case ERROR: - break; - default: - status = ReportStatus.CANCELED; - logger.log(Level.INFO, "Report cancelled"); - break; - } - } - - /** - * Logs the final status of the report generation. - * - * @deprecated Use {@link #complete(ReportStatus)} - */ - @Deprecated - @Override - public void complete() { - complete(ReportStatus.COMPLETE); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java index 1e5ffea430..e336538d4d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java @@ -1,19 +1,19 @@ /* * * Autopsy Forensic Browser - * - * Copyright 2013-2018 Basis Technology Corp. - * + * + * Copyright 2012-2019 Basis Technology Corp. + * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com * Project Contact/Architect: 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. @@ -74,10 +74,11 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr * reporting wizard. When the wizard is finished, create a ReportGenerator * with the wizard information, and start all necessary reports. * - * @param configName Name of the reporting configuration to use + * @param configName Name of the reporting configuration to use * @param displayCaseSpecificData Flag whether to use case specific data in - * UI panels or to use all possible result types - * @param runReports Flag whether to produce report(s) + * UI panels or to use all possible result + * types + * @param runReports Flag whether to produce report(s) */ @SuppressWarnings("unchecked") public static void doReportWizard(String configName, boolean displayCaseSpecificData, boolean runReports) { @@ -92,7 +93,7 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr } catch (ReportConfigException ex) { logger.log(Level.SEVERE, "Failed to save reporting configuration " + configName, ex); //NON-NLS NotifyDescriptor descriptor = new NotifyDescriptor.Message( - NbBundle.getMessage(ReportWizardAction.class, "ReportWizardAction.unableToSaveConfig.errorLabel.text"), + NbBundle.getMessage(ReportWizardAction.class, "ReportWizardAction.unableToSaveConfig.errorLabel.text"), NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notify(descriptor); } @@ -110,6 +111,7 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr } } + @SuppressWarnings(value = "unchecked") private static void saveReportingConfiguration(String configName, WizardDescriptor wiz) throws ReportConfigException { ReportingConfig reportingConfig = new ReportingConfig(configName); diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportingConfigLoader.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportingConfigLoader.java index 6ab57f8578..6472105888 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportingConfigLoader.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportingConfigLoader.java @@ -55,11 +55,14 @@ final class ReportingConfigLoader { * an atomic, thread safe way. * * @param configName Name of the reporting configuration + * * @return ReportingConfig object if a persisted configuration exists, null - * otherwise + * otherwise + * * @throws ReportConfigException if an error occurred while reading the - * configuration + * configuration */ + @SuppressWarnings("unchecked") static synchronized ReportingConfig loadConfig(String configName) throws ReportConfigException { // construct the configuration directory path @@ -77,7 +80,7 @@ final class ReportingConfigLoader { // read in the configuration ReportingConfig config = new ReportingConfig(configName); - + // read table report settings String filePath = reportDirPath.toString() + File.separator + TABLE_REPORT_CONFIG_FILE; try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) { @@ -85,7 +88,7 @@ final class ReportingConfigLoader { } catch (IOException | ClassNotFoundException ex) { throw new ReportConfigException("Unable to read table report settings " + filePath, ex); } - + // read file report settings filePath = reportDirPath.toString() + File.separator + FILE_REPORT_CONFIG_FILE; try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) { @@ -93,7 +96,7 @@ final class ReportingConfigLoader { } catch (IOException | ClassNotFoundException ex) { throw new ReportConfigException("Unable to read file report settings " + filePath, ex); } - + // read map of module configuration objects Map moduleConfigs = null; filePath = reportDirPath.toString() + File.separator + MODULE_CONFIG_FILE; @@ -102,11 +105,11 @@ final class ReportingConfigLoader { } catch (IOException | ClassNotFoundException ex) { throw new ReportConfigException("Unable to read module configurations map " + filePath, ex); } - + if (moduleConfigs == null || moduleConfigs.isEmpty()) { return config; } - + // read each ReportModuleSettings object individually for (Iterator> iterator = moduleConfigs.entrySet().iterator(); iterator.hasNext();) { ReportModuleConfig moduleConfig = iterator.next().getValue(); @@ -114,16 +117,19 @@ final class ReportingConfigLoader { try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePath))) { moduleConfig.setModuleSettings((ReportModuleSettings) in.readObject()); } catch (IOException | ClassNotFoundException ex) { - /* NOTE: we do not want to re-throw the exception because we do not - want a single error while reading in a (3rd party) report module - to prevent us from reading the entire reporting configuration.*/ + /* + * NOTE: we do not want to re-throw the exception because we do + * not want a single error while reading in a (3rd party) report + * module to prevent us from reading the entire reporting + * configuration. + */ logger.log(Level.SEVERE, "Unable to read module settings " + filePath, ex); iterator.remove(); } } - + config.setModuleConfigs(moduleConfigs); - + return config; } @@ -132,15 +138,16 @@ final class ReportingConfigLoader { * an atomic, thread safe way. * * @param reportConfig ReportingConfig object to serialize to disk + * * @throws ReportConfigException if an error occurred while saving the - * configuration + * configuration */ static synchronized void saveConfig(ReportingConfig reportConfig) throws ReportConfigException { if (reportConfig == null) { throw new ReportConfigException("Reporting configuration is NULL"); } - + // construct the configuration directory path Path pathToConfigDir = Paths.get(ReportingConfigLoader.REPORT_CONFIG_FOLDER_PATH, reportConfig.getName()); @@ -168,7 +175,7 @@ final class ReportingConfigLoader { } // save map of module configuration objects - filePath = pathToConfigDir.toString() + File.separator + MODULE_CONFIG_FILE; + filePath = pathToConfigDir.toString() + File.separator + MODULE_CONFIG_FILE; try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(filePath))) { out.writeObject(reportConfig.getModuleConfigs()); } catch (IOException ex) { @@ -176,10 +183,13 @@ final class ReportingConfigLoader { } // save each ReportModuleSettings object individually - /* NOTE: This is done to protect us from errors in reading/writing 3rd - party report module settings. If we were to serialize the entire ReportingConfig - object, then a single error while reading in a 3rd party report module - would prevent us from reading the entire reporting configuration.*/ + /* + * NOTE: This is done to protect us from errors in reading/writing 3rd + * party report module settings. If we were to serialize the entire + * ReportingConfig object, then a single error while reading in a 3rd + * party report module would prevent us from reading the entire + * reporting configuration. + */ if (reportConfig.getModuleConfigs() == null) { return; } diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java index 8432526e4e..264ed461c4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java @@ -80,10 +80,10 @@ class TableReportGenerator { this.progressPanel = progressPanel; this.tableReport = tableReport; this.columnHeaderMap = new HashMap<>(); - errorList = new ArrayList<>(); + errorList = new ArrayList<>(); this.settings = settings; } - + private void getAllExistingTags() throws NoCurrentCaseException, TskCoreException { List tagNames = new ArrayList<>(); @@ -98,6 +98,7 @@ class TableReportGenerator { tagNamesFilter = new HashSet<>(tagNames); } + @SuppressWarnings("deprecation") private void getAllExistingArtiactTypes() throws NoCurrentCaseException, TskCoreException { // get all possible artifact types ArrayList doNotReport = new ArrayList<>(); @@ -116,7 +117,7 @@ class TableReportGenerator { progressPanel.start(); progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.readingTagsArtifacts.text")); - + if (settings.useStoredTagsAndArtifactsLists()) { // Get the artifact types selected by the user. artifactTypes = settings.getArtifactSelections(); @@ -130,7 +131,7 @@ class TableReportGenerator { if (settings.getSelectedReportOption() == TableReportSettings.TableReportOption.ALL_TAGGED_RESULTS) { getAllExistingTags(); } - + // get all possible artifact types getAllExistingArtiactTypes(); } catch (NoCurrentCaseException | TskCoreException ex) { @@ -139,11 +140,11 @@ class TableReportGenerator { return; } } - + // Start the progress indicators for each active TableReportModule. progressPanel.setIndeterminate(false); progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - + // report on the blackboard results if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { makeBlackboardArtifactTables(); 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 aac5f8beef..2968ed43c4 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties-MERGED @@ -38,8 +38,10 @@ SaveSnapShotAsReport.ReportSavedAt=Report saved at [{0}] SaveSnapShotAsReport.Success=Success SaveSnapShotAsReport_OK_Button=OK SaveSnapShotAsReport_Open_Button=Open Report +# {0} - supplied report name SaveSnapShotAsReport_Path_Failure_Report=Failed to create report. Supplied report name has invalid characters: {0} SaveSnapShotAsReport_Report_Failed=Report failed +# {0} - report location SaveSnapShotAsReport_success_message=Snapshot report successfully created at location: \n\n {0} Timeline.ModuleName=Timeline ViewArtifactInTimelineAction.displayName=View Result 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 bb9cfc2328..6208714e06 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -84,7 +84,9 @@ public class SaveSnapshotAsReport extends Action { "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", + "# {0} - supplied report name", "SaveSnapShotAsReport_Path_Failure_Report=Failed to create report. Supplied report name has invalid characters: {0}", + "# {0} - report location", "SaveSnapShotAsReport_success_message=Snapshot report successfully created at location: \n\n {0}", "SaveSnapShotAsReport_Open_Button=Open Report", "SaveSnapShotAsReport_OK_Button=OK" diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java b/Core/src/org/sleuthkit/autopsy/uicomponents/WrapLayout.java old mode 100644 new mode 100755 similarity index 97% rename from Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java rename to Core/src/org/sleuthkit/autopsy/uicomponents/WrapLayout.java index be35ea0581..5daf8d5646 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java +++ b/Core/src/org/sleuthkit/autopsy/uicomponents/WrapLayout.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.corecomponents; +package org.sleuthkit.autopsy.uicomponents; import java.awt.Component; import java.awt.Container; @@ -32,8 +32,9 @@ import javax.swing.SwingUtilities; * Originally written by Rob Camick * https://tips4java.wordpress.com/2008/11/06/wrap-layout/ */ -class WrapLayout extends FlowLayout { - +public class WrapLayout extends FlowLayout { + + private static final long serialVersionUID = 1L; /** * Constructs a new WrapLayout with a left alignment and a * default 5-unit horizontal and vertical gap. diff --git a/CoreLibs/manifest.mf b/CoreLibs/manifest.mf index 24af339d11..1f7fcc545e 100644 --- a/CoreLibs/manifest.mf +++ b/CoreLibs/manifest.mf @@ -1,8 +1,8 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.corelibs/3 -OpenIDE-Module-Implementation-Version: 5 +OpenIDE-Module-Implementation-Version: 6 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/corelibs/Bundle.properties -OpenIDE-Module-Specification-Version: 1.2 +OpenIDE-Module-Specification-Version: 1.3 AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java b/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java index 79e4678e91..ffc08a597f 100644 --- a/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java +++ b/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java @@ -59,7 +59,7 @@ public final class OpenCvLoader { * * @return True or false. */ - public static boolean hasOpenCvLoaded() { + public static boolean openCvIsLoaded() { return openCvLoaded; } @@ -78,7 +78,7 @@ public final class OpenCvLoader { * of the core OpenCV library during static * initialization of this class. * - * @deprecated Use hasOpenCvLoaded instead. + * @deprecated Use openCvIsLoaded instead. */ @Deprecated public static boolean isOpenCvLoaded() throws UnsatisfiedLinkError { diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index 1523e88e06..c6e222b422 100644 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -135,7 +135,7 @@ 10 - 10.16 + 10.17 @@ -144,7 +144,7 @@ 3 - 1.2 + 1.3 diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java index 9ba93585bf..be7a3c72a7 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/objectdetection/ObjectDetectectionFileIngestModule.java @@ -84,7 +84,7 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter throw new IngestModule.IngestModuleException(errorMsg); } - if(!OpenCvLoader.hasOpenCvLoaded()) { + if(!OpenCvLoader.openCvIsLoaded()) { String errorMsg = Bundle.ObjectDetectionFileIngestModule_openCVNotLoaded(); logger.log(Level.SEVERE, errorMsg); throw new IngestModule.IngestModuleException(errorMsg); diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index 2220f662b4..634ed81534 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -127,7 +127,7 @@ 10 - 10.16 + 10.17 @@ -136,7 +136,7 @@ 3 - 1.2 + 1.3 diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 3f40ab3ace..c68f7a3abd 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -119,7 +119,7 @@ 10 - 10.16 + 10.17 @@ -128,7 +128,7 @@ 3 - 1.2 + 1.3 diff --git a/RecentActivity/nbproject/project.xml b/RecentActivity/nbproject/project.xml index 269723962e..29b5d1362a 100644 --- a/RecentActivity/nbproject/project.xml +++ b/RecentActivity/nbproject/project.xml @@ -60,7 +60,7 @@ 10 - 10.16 + 10.17 @@ -69,7 +69,7 @@ 3 - 1.2 + 1.3 diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 4f2d1d4fd9..805e776717 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -2,9 +2,14 @@ cannotBuildXmlParser=Unable to build XML parser: cannotLoadSEUQA=Unable to load Search Engine URL Query Analyzer settings file, SEUQAMappings.xml: cannotParseXml=Unable to parse XML file: ChromeCacheExtractor.moduleName=ChromeCacheExtractor +# {0} - module name +# {1} - row number +# {2} - table length +# {3} - cache path ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3} DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_FlashDrive=Flash Drive +# {0} - OS name DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.parentModuleName=Recent Activity Extract.indexError.message=Failed to index artifact for keyword search. @@ -183,6 +188,7 @@ RecentDocumentsByLnk.parentModuleName.noSpace=RecentActivity RecentDocumentsByLnk.parentModuleName=Recent Activity RegRipperFullNotFound=Full version RegRipper executable not found. RegRipperNotFound=Autopsy RegRipper executable not found. +# {0} - file name SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}. SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine SearchEngineURLQueryAnalyzer.engineName.none=NONE diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 3fa746cf82..d3af457a1f 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -258,7 +258,7 @@ final class ExtractRecycleBin extends Extract { addFileSystemFile(skCase, fsContent, parentFolder, fsContent.getName(), deletedTimeStamp); } else if (fsContent.isDir()) { String newPath = parentPath + "\\" + fsContent.getName(); - AbstractFile childFolder = getOrMakeFolder(skCase, (FsContent) fsContent, parentPath); + AbstractFile childFolder = getOrMakeFolder(skCase, fsContent, parentPath); popuplateDeletedDirectory(skCase, childFolder, fsContent.getChildren(), newPath, deletedTimeStamp); } } diff --git a/Testing/nbproject/project.xml b/Testing/nbproject/project.xml index 4ed9232a8f..41dc8b253e 100644 --- a/Testing/nbproject/project.xml +++ b/Testing/nbproject/project.xml @@ -47,7 +47,7 @@ 10 - 10.15 + 10.17 diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 158d4a62d7..4fd4fb33d8 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Wed, 02 Oct 2019 12:06:32 -0400 +#Fri, 04 Oct 2019 14:30:10 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 3f60232032..17f4cb7436 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Wed, 02 Oct 2019 12:06:32 -0400 +#Fri, 04 Oct 2019 14:30:10 -0400 CTL_MainWindow_Title=Autopsy 4.13.0 CTL_MainWindow_Title_No_Project=Autopsy 4.13.0 diff --git a/docs/doxygen-user/communications.dox b/docs/doxygen-user/communications.dox index c7c77e6a30..9efd0f02f1 100644 --- a/docs/doxygen-user/communications.dox +++ b/docs/doxygen-user/communications.dox @@ -14,7 +14,7 @@ The Communications Visualization Tool is loaded through the Tools->Communication \image html cvt_main.png -From the left hand column, you can choose which devices to display, which types of data to display, and optionally select a time range. You can also choose to limit the display to only the most recent communications. After any changes to the filters, use the Apply button to update the tables. +From the left hand column, you can choose which devices to display, which types of data to display, and optionally select a time range. You can also choose to limit the display to only the most recent communications. After any changes to the filters, use the Apply button to update the tables. You can hide this column by clicking the left arrow at the top of the column. The middle column displays each account, its device and type, and the number of associated messages (emails, call logs, etc.). By default it will be sorted in descending order of frequency. The middle column and the right hand column both have a \ref ui_quick_search feature which can be used to quickly find a visible item in their section's table. diff --git a/docs/doxygen-user/images/cvt_main.png b/docs/doxygen-user/images/cvt_main.png index 9093f0e9f8..1c9ec9e903 100644 Binary files a/docs/doxygen-user/images/cvt_main.png and b/docs/doxygen-user/images/cvt_main.png differ diff --git a/nbproject/project.properties b/nbproject/project.properties index 8132096d48..c561519599 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.13.0 ### build.type must be one of: DEVELOPMENT, RELEASE -#build.type=RELEASE -build.type=DEVELOPMENT +build.type=RELEASE +#build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental diff --git a/thunderbirdparser/nbproject/project.xml b/thunderbirdparser/nbproject/project.xml index 2f4d0ad72d..52e915e2f3 100644 --- a/thunderbirdparser/nbproject/project.xml +++ b/thunderbirdparser/nbproject/project.xml @@ -36,7 +36,7 @@ 10 - 10.16 + 10.17