From 1ca277aae8be3115ede39dbe596ea4d6335fbec0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 23 Jul 2020 15:32:09 -0400 Subject: [PATCH] panel integration and refactoring --- .../DataSourceSummaryDetailsPanel.java | 165 ++++++++++-------- .../DataSourceSummaryDialog.form | 5 + .../DataSourceSummaryDialog.java | 19 +- .../DataSourceSummaryResultViewer.java | 64 +++++-- 4 files changed, 154 insertions(+), 99 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDetailsPanel.java index 1b898f4995..61667dbb42 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDetailsPanel.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.table.DefaultTableModel; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Image; @@ -36,23 +37,48 @@ class DataSourceSummaryDetailsPanel extends javax.swing.JPanel { //Because this panel was made using the gridbaglayout and netbean's Customize Layout tool it will be best to continue to modify it through that private static final long serialVersionUID = 1L; - private Map osDetailMap = new HashMap<>(); private static final Integer SIZE_COVERSION_CONSTANT = 1000; private static final DecimalFormat APPROXIMATE_SIZE_FORMAT = new DecimalFormat("#.##"); - private final Map unallocatedFilesSizeMap; - private final Map usageMap; private static final Logger logger = Logger.getLogger(DataSourceSummaryDetailsPanel.class.getName()); + private DataSource dataSource; + /** * Creates new form DataSourceSummaryDetailsPanel */ @Messages({"DataSourceSummaryDetailsPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.", "DataSourceSummaryDetailsPanel.getDataSources.error.title=Load Failure"}) - DataSourceSummaryDetailsPanel(Map usageMap) { + DataSourceSummaryDetailsPanel() { initComponents(); - this.usageMap = usageMap; - this.unallocatedFilesSizeMap = DataSourceInfoUtilities.getSizeOfUnallocatedFiles(); - osDetailMap = DataSourceInfoUtilities.getOperatingSystems(); + setDataSource(null); + } + + /** + * The datasource currently used as the model in this panel. + * + * @return The datasource currently being used as the model in this panel. + */ + public DataSource getDataSource() { + return dataSource; + } + + /** + * Sets datasource to visualize in the panel. + * + * @param dataSource The datasource to use in this panel. + */ + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + + if (dataSource == null) { + updateDetailsPanelData(null, null, null, null); + } else { + long id = dataSource.getId(); + updateDetailsPanelData(dataSource, + DataSourceInfoUtilities.getSizeOfUnallocatedFiles().get(id), + DataSourceInfoUtilities.getOperatingSystems().get(id), + DataSourceInfoUtilities.getDataSourceTypes().get(id)); + } } /** @@ -60,77 +86,80 @@ class DataSourceSummaryDetailsPanel extends javax.swing.JPanel { * * @param selectedDataSource the DataSource to display details about. */ - void updateDetailsPanelData(DataSource selectedDataSource) { + private void updateDetailsPanelData(DataSource selectedDataSource, Long unallocatedFilesSize, String osDetails, String usage) { clearTableValues(); if (selectedDataSource != null) { - String sizeString = ""; - String sectorSizeString = ""; - String md5String = ""; - String sha1String = ""; - String sha256String = ""; - String acquisitionDetailsString = ""; - String imageTypeString = ""; - String[] filePaths = new String[0]; - String osDetailString = osDetailMap.get(selectedDataSource.getId()) == null ? "" : osDetailMap.get(selectedDataSource.getId()); - String dataSourceTypeString = usageMap.get(selectedDataSource.getId()) == null ? "" : usageMap.get(selectedDataSource.getId()); - try { - acquisitionDetailsString = selectedDataSource.getAcquisitionDetails(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Unable to get aquisition details for selected data source", ex); - } - if (selectedDataSource instanceof Image) { - imageTypeString = ((Image) selectedDataSource).getType().getName(); - filePaths = ((Image) selectedDataSource).getPaths(); - sizeString = getSizeString(selectedDataSource.getSize()); - sectorSizeString = getSizeString(((Image) selectedDataSource).getSsize()); - try { - //older databases may have null as the hash values - md5String = ((Image) selectedDataSource).getMd5(); - if (md5String == null) { - md5String = ""; - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Unable to get MD5 for selected data source", ex); - } - try { - sha1String = ((Image) selectedDataSource).getSha1(); - if (sha1String == null) { - sha1String = ""; - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Unable to get SHA1 for selected data source", ex); - } - try { - sha256String = ((Image) selectedDataSource).getSha256(); - if (sha256String == null) { - sha256String = ""; - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Unable to get SHA256 for selected data source", ex); - } - } + unallocatedSizeValue.setText(getSizeString(unallocatedFilesSize)); + operatingSystemValue.setText(StringUtils.isBlank(osDetails) ? "" : osDetails); + dataSourceUsageValue.setText(StringUtils.isBlank(usage) ? "" : usage); + + timeZoneValue.setText(selectedDataSource.getTimeZone()); displayNameValue.setText(selectedDataSource.getName()); originalNameValue.setText(selectedDataSource.getName()); deviceIdValue.setText(selectedDataSource.getDeviceId()); - dataSourceUsageValue.setText(dataSourceTypeString); - operatingSystemValue.setText(osDetailString); - timeZoneValue.setText(selectedDataSource.getTimeZone()); - acquisitionDetailsTextArea.setText(acquisitionDetailsString); - imageTypeValue.setText(imageTypeString); - sizeValue.setText(sizeString); - unallocatedSizeValue.setText(getSizeString(unallocatedFilesSizeMap.get(selectedDataSource.getId()))); - sectorSizeValue.setText(sectorSizeString); - md5HashValue.setText(md5String); - sha1HashValue.setText(sha1String); - sha256HashValue.setText(sha256String); - for (String path : filePaths) { - ((DefaultTableModel) filePathsTable.getModel()).addRow(new Object[]{path}); + + try { + acquisitionDetailsTextArea.setText(selectedDataSource.getAcquisitionDetails()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to get aquisition details for selected data source", ex); + } + + if (selectedDataSource instanceof Image) { + setFieldsForImage((Image) selectedDataSource); } } updateFieldVisibility(); this.repaint(); } + /** + * Sets text fields for an image. This should be called after + * clearTableValues and before updateFieldVisibility to ensure the proper + * rendering. + * + * @param selectedImage The selected image. + */ + private void setFieldsForImage(Image selectedImage) { + imageTypeValue.setText(selectedImage.getType().getName()); + sizeValue.setText(getSizeString(selectedImage.getSize())); + sectorSizeValue.setText(getSizeString(selectedImage.getSsize())); + + for (String path : selectedImage.getPaths()) { + ((DefaultTableModel) filePathsTable.getModel()).addRow(new Object[]{path}); + } + + try { + //older databases may have null as the hash values + String md5String = selectedImage.getMd5(); + if (md5String == null) { + md5String = ""; + } + md5HashValue.setText(md5String); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to get MD5 for selected data source", ex); + } + + try { + String sha1String = selectedImage.getSha1(); + if (sha1String == null) { + sha1String = ""; + } + sha1HashValue.setText(sha1String); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to get SHA1 for selected data source", ex); + } + + try { + String sha256String = selectedImage.getSha256(); + if (sha256String == null) { + sha256String = ""; + } + sha256HashValue.setText(sha256String); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to get SHA256 for selected data source", ex); + } + } + /** * Get a long size in bytes as a string formated to be read by users. * @@ -147,7 +176,7 @@ class DataSourceSummaryDetailsPanel extends javax.swing.JPanel { "DataSourceSummaryDetailsPanel.units.terabytes= TB", "DataSourceSummaryDetailsPanel.units.petabytes= PB" }) - private String getSizeString(Long size) { + private static String getSizeString(Long size) { if (size == null) { return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.form index 72c45cb5a7..272fc9b041 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.form @@ -68,6 +68,11 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java index 3c68b7b3ed..e1197fa83a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java @@ -27,7 +27,6 @@ import java.util.Observer; import java.util.Set; import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent.Reason; @@ -41,10 +40,8 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser private static final long serialVersionUID = 1L; private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); - private final DataSourceSummaryCountsPanel countsPanel; - private final DataSourceSummaryDetailsPanel detailsPanel; private final DataSourceBrowser dataSourcesPanel; - private final IngestJobInfoPanel ingestHistoryPanel; + private final DataSourceSummaryTabbedPane dataSourceSummaryTabbedPane; /** * Creates new form DataSourceSummaryDialog for displaying a summary of the @@ -61,21 +58,14 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser super(owner, Bundle.DataSourceSummaryDialog_window_title(), true); Map usageMap = DataSourceInfoUtilities.getDataSourceTypes(); Map fileCountsMap = DataSourceInfoUtilities.getCountsOfFiles(); - countsPanel = new DataSourceSummaryCountsPanel(fileCountsMap); - detailsPanel = new DataSourceSummaryDetailsPanel(usageMap); dataSourcesPanel = new DataSourceBrowser(usageMap, fileCountsMap); - ingestHistoryPanel = new IngestJobInfoPanel(); + dataSourceSummaryTabbedPane = new DataSourceSummaryTabbedPane(); initComponents(); dataSourceSummarySplitPane.setLeftComponent(dataSourcesPanel); - dataSourceTabbedPane.addTab(Bundle.DataSourceSummaryDialog_detailsTab_title(), detailsPanel); - dataSourceTabbedPane.addTab(Bundle.DataSourceSummaryDialog_countsTab_title(), countsPanel); - dataSourceTabbedPane.addTab(Bundle.DataSourceSummaryDialog_ingestHistoryTab_title(), ingestHistoryPanel); dataSourcesPanel.addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { DataSource selectedDataSource = dataSourcesPanel.getSelectedDataSource(); - countsPanel.updateCountsTableData(selectedDataSource); - detailsPanel.updateDetailsPanelData(selectedDataSource); - ingestHistoryPanel.setDataSource(selectedDataSource); + dataSourceSummaryTabbedPane.setDataSource(selectedDataSource); this.repaint(); } }); @@ -116,7 +106,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser closeButton = new javax.swing.JButton(); dataSourceSummarySplitPane = new javax.swing.JSplitPane(); - dataSourceTabbedPane = new javax.swing.JTabbedPane(); + javax.swing.JTabbedPane dataSourceTabbedPane = dataSourceSummaryTabbedPane; org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryDialog.class, "DataSourceSummaryDialog.closeButton.text")); // NOI18N closeButton.addActionListener(new java.awt.event.ActionListener() { @@ -173,6 +163,5 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton closeButton; private javax.swing.JSplitPane dataSourceSummarySplitPane; - private javax.swing.JTabbedPane dataSourceTabbedPane; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/resultviewers/summary/DataSourceSummaryResultViewer.java b/Core/src/org/sleuthkit/autopsy/resultviewers/summary/DataSourceSummaryResultViewer.java index 90c53e6217..4a528c06d2 100644 --- a/Core/src/org/sleuthkit/autopsy/resultviewers/summary/DataSourceSummaryResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/resultviewers/summary/DataSourceSummaryResultViewer.java @@ -18,22 +18,31 @@ */ package org.sleuthkit.autopsy.resultviewers.summary; +import java.awt.BorderLayout; +import java.awt.Cursor; +import java.util.logging.Level; +import javax.swing.SwingUtilities; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryTabbedPane; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; - +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; /** - * - * @author gregd + * A tabular result viewer that displays a summary of the selected Data Source. */ +@ServiceProvider(service = DataResultViewer.class) +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives public class DataSourceSummaryResultViewer extends AbstractDataResultViewer { + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(DataSourceSummaryResultViewer.class.getName()); + private final String title; public DataSourceSummaryResultViewer() { @@ -50,6 +59,7 @@ public class DataSourceSummaryResultViewer extends AbstractDataResultViewer { public DataSourceSummaryResultViewer(ExplorerManager explorerManager, String title) { super(explorerManager); this.title = title; + initComponents(); } @Override @@ -59,25 +69,47 @@ public class DataSourceSummaryResultViewer extends AbstractDataResultViewer { @Override public boolean isSupported(Node node) { - if (node == null) { - return false; - } - - DataSource contentItem = node.getLookup().lookup(DataSource.class); - if (contentItem == null) { - return false; - } - - Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(datasourceObjId); + return getDataSource(node) != null; + } + + private DataSource getDataSource(Node node) { + return node == null ? null: node.getLookup().lookup(DataSource.class); } @Override + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void setNode(Node node) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!SwingUtilities.isEventDispatchThread()) { + LOGGER.log(Level.SEVERE, "Attempting to run setNode() from non-EDT thread."); + return; + } + + DataSource dataSource = getDataSource(node); + + if (dataSource == null) { + LOGGER.log(Level.SEVERE, "No datasource for node found."); + return; + } + + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + summaryPanel.setDataSource(dataSource); + } + finally { + this.setCursor(null); + } } @Override public String getTitle() { return title; } + + private void initComponents() { + summaryPanel = new DataSourceSummaryTabbedPane(); + setLayout(new BorderLayout()); + add(summaryPanel, BorderLayout.CENTER); + } + + private DataSourceSummaryTabbedPane summaryPanel; }