From 364bef5c3ce58716766b42bf64b806f0968118ca Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 2 Jan 2019 15:33:38 -0500 Subject: [PATCH 1/9] 4568 bring in FileTypeUtils from timeline-event-mgr branch and move to datamodel.utils --- .../datamodel/utils/FileTypeUtils.java | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java new file mode 100644 index 0000000000..74545fcc40 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java @@ -0,0 +1,207 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018-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.datamodel.utils; + +import com.google.common.collect.ImmutableSet; +import static java.util.Arrays.asList; +import java.util.Collection; +import java.util.Collections; +import javax.imageio.ImageIO; +import static org.apache.commons.collections4.ListUtils.removeAll; +import org.openide.util.NbBundle; + +/** + * Utilities for dealing with file/mime-types + */ +public final class FileTypeUtils { + + private static final ImmutableSet IMAGE_MIME_TYPES + = new ImmutableSet.Builder() + .addAll(removeAll(asList(ImageIO.getReaderMIMETypes()), + asList("application/octet-stream"))) //this claims to be supported, but is not really an image. + .add("image/bmp", //NON-NLS + "image/gif", //NON-NLS + "image/jpeg", //NON-NLS + "image/png", //NON-NLS + "image/tiff", //NON-NLS + "image/vnd.adobe.photoshop", //NON-NLS + "image/x-raw-nikon", //NON-NLS + "image/x-ms-bmp", //NON-NLS + "image/x-icon", //NON-NLS + "image/webp", //NON-NLS + "image/vnd.microsoft.icon", //NON-NLS + "image/x-rgb", //NON-NLS + "image/x-ms-bmp", //NON-NLS + "image/x-xbitmap", //NON-NLS + "image/x-portable-graymap", //NON-NLS + "image/x-portable-bitmap" //NON-NLS + ).build(); + private static final ImmutableSet AUDIO_MIME_TYPES + = new ImmutableSet.Builder() + .add("audio/midi", //NON-NLS + "audio/mpeg", //NON-NLS + "audio/webm", //NON-NLS + "audio/ogg", //NON-NLS + "audio/wav", //NON-NLS + "audio/vnd.wave", //NON-NLS + "audio/x-ms-wma"//NON-NLS + ).build(); + private static final ImmutableSet VIDEO_MIME_TYPES + = new ImmutableSet.Builder() + .add("video/webm", //NON-NLS + "video/3gpp", //NON-NLS + "video/3gpp2", //NON-NLS + "video/ogg", //NON-NLS + "video/mpeg", //NON-NLS + "video/mp4", //NON-NLS + "video/quicktime", //NON-NLS + "video/x-msvideo", //NON-NLS + "video/x-flv", //NON-NLS + "video/x-m4v", //NON-NLS + "video/x-ms-wmv"//NON-NLS + ).build(); + private static final ImmutableSet DOCUMENT_MIME_TYPES + = new ImmutableSet.Builder() + .add("text/plain", //NON-NLS + "text/css", //NON-NLS + "text/html", //NON-NLS + "text/csv", //NON-NLS + "text/xml", //NON-NLS + "text/x-log", //NON-NLS + "application/rtf", //NON-NLS + "application/pdf", //NON-NLS + "application/json", //NON-NLS + "application/javascript", //NON-NLS + "application/xml", //NON-NLS + "application/x-msoffice", //NON-NLS + "application/x-ooxml", //NON-NLS + "application/msword", //NON-NLS + "application/msword2", //NON-NLS + "application/vnd.wordperfect", //NON-NLS + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS + "application/vnd.ms-powerpoint", //NON-NLS + "application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS + "application/vnd.ms-excel", //NON-NLS + "application/vnd.ms-excel.sheet.4", //NON-NLS + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS + "application/vnd.oasis.opendocument.presentation", //NON-NLS + "application/vnd.oasis.opendocument.spreadsheet", //NON-NLS + "application/vnd.oasis.opendocument.text" //NON-NLS + ).build(); + private static final ImmutableSet EXECUTABLE_MIME_TYPES + = new ImmutableSet.Builder() + .add("application/x-bat",//NON-NLS + "application/x-dosexec",//NON-NLS + "application/vnd.microsoft.portable-executable",//NON-NLS + "application/x-msdownload",//NON-NLS + "application/exe",//NON-NLS + "application/x-exe",//NON-NLS + "application/dos-exe",//NON-NLS + "vms/exe",//NON-NLS + "application/x-winexe",//NON-NLS + "application/msdos-windows",//NON-NLS + "application/x-msdos-program"//NON-NLS + ).build(); + private static final ImmutableSet MULTI_MEDIA_MIME_TYPES + = new ImmutableSet.Builder() + .addAll(IMAGE_MIME_TYPES) + .addAll(AUDIO_MIME_TYPES) + .addAll(VIDEO_MIME_TYPES) + .build(); + private static final ImmutableSet VISUAL_MEDIA_MIME_TYPES + = new ImmutableSet.Builder() + .addAll(IMAGE_MIME_TYPES) + .addAll(VIDEO_MIME_TYPES) + .add("application/vnd.ms-asf", //NON-NLS + "application/vnd.rn-realmedia", //NON-NLS + "application/x-shockwave-flash" //NON-NLS + ).build(); + + private FileTypeUtils() { + + } + + /** + * Enum of categories/groups of file types. + */ + @NbBundle.Messages({ + "FileTypeCategory.Audio.displayName=Audio", + "FileTypeCategory.Video.displayName=Video", + "FileTypeCategory.Image.displayName=Image", + "FileTypeCategory.Media.displayName=Media", + "FileTypeCategory.Visual.displayName=Visual", + "FileTypeCategory.Documents.displayName=Documents", + "FileTypeCategory.Executables.displayName=Executables"}) + public enum FileTypeCategory { + + IMAGE(Bundle.FileTypeCategory_Image_displayName(), + IMAGE_MIME_TYPES, + Collections.emptyList()), + VIDEO(Bundle.FileTypeCategory_Video_displayName(), + VIDEO_MIME_TYPES, + Collections.emptyList()), + AUDIO(Bundle.FileTypeCategory_Audio_displayName(), + AUDIO_MIME_TYPES, + Collections.emptyList()), + /** + * Images, Videos, flash Animations, etc + */ + VISUAL(Bundle.FileTypeCategory_Media_displayName(), + VISUAL_MEDIA_MIME_TYPES, + Collections.emptyList()), + /** + * VISUAL plus AUDIO. + */ + MEDIA(Bundle.FileTypeCategory_Media_displayName(), + MULTI_MEDIA_MIME_TYPES, + Collections.emptyList()), + EXECUTABLE(Bundle.FileTypeCategory_Executables_displayName(), + EXECUTABLE_MIME_TYPES, + Collections.emptyList()), + /** + * (Plain) Text and "Office" documents. + */ + DOCUMENTS(Bundle.FileTypeCategory_Documents_displayName(), + DOCUMENT_MIME_TYPES, + Collections.emptyList()); + + private final String displayName; + private final ImmutableSet mediaTypes; + private final ImmutableSet extensions; + + private FileTypeCategory(String displayName, Collection mediaTypes, Collection extensions) { + this.displayName = displayName; + this.mediaTypes = ImmutableSet.copyOf(mediaTypes); + this.extensions = ImmutableSet.copyOf(extensions); + } + + public String getDisplayName() { + return displayName; + } + + public ImmutableSet getMediaTypes() { + return mediaTypes; + + } + + public ImmutableSet getExtensions() { + throw new UnsupportedOperationException("This method is not implemented yet."); //just to be explicit. + } + } +} From 1d143a315b586db4f79b5f9f22252928f8aa6425 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 3 Jan 2019 16:02:19 -0500 Subject: [PATCH 2/9] 4568 add initial Data source summary dialog and action --- .../sleuthkit/autopsy/casemodule/Case.java | 3 + .../casemodule/CasePropertiesAction.java | 2 +- .../casemodule/IngestJobInfoPanel.java | 3 +- .../datasourceSummary/Bundle.properties | 9 + .../DataSourceSummaryAction.java | 72 ++++ .../DataSourceSummaryPanel.form | 224 +++++++++++ .../DataSourceSummaryPanel.java | 375 ++++++++++++++++++ Core/src/org/sleuthkit/autopsy/core/layer.xml | 5 + 8 files changed, 691 insertions(+), 2 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c580309cba..46e9dad2bc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -67,6 +67,7 @@ import org.sleuthkit.autopsy.appservices.AutopsyService; import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext; import static org.sleuthkit.autopsy.casemodule.Bundle.*; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; @@ -1165,6 +1166,7 @@ public class Case { CallableSystemAction.get(AddImageAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); + CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true); CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true); @@ -1218,6 +1220,7 @@ public class Case { CallableSystemAction.get(AddImageAction.class).setEnabled(false); CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); + CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(false); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false); CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java index 6a9d1d2f2f..2a70c91483 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java @@ -55,7 +55,7 @@ final class CasePropertiesAction extends CallableSystemAction { casePropertiesDialog = new JDialog(mainWindow, title, true); CaseInformationPanel caseInformationPanel = new CaseInformationPanel(); caseInformationPanel.addCloseButtonAction((ActionEvent e) -> { - casePropertiesDialog.setVisible(false); + casePropertiesDialog.dispose(); }); casePropertiesDialog.add(caseInformationPanel); casePropertiesDialog.setResizable(true); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 940f6a9cd5..e274245edd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -61,7 +61,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private void customizeComponents() { refresh(); this.ingestJobTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { - this.ingestModuleTableModel = new IngestModuleTableModel(this.ingestJobs.get(ingestJobTable.getSelectedRow())); + IngestJobInfo currJob = (ingestJobTable.getSelectedRow() < 0 ? null : this.ingestJobs.get(ingestJobTable.getSelectedRow())); + this.ingestModuleTableModel = new IngestModuleTableModel(currJob); this.ingestModuleTable.setModel(this.ingestModuleTableModel); }); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties new file mode 100644 index 0000000000..2c7eea054f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -0,0 +1,9 @@ +CTL_DataSourceSummaryAction=Data Source Summary +DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) +DataSourceSummaryPanel.opperatingSystemLabel.text=OS: +DataSourceSummaryPanel.opperatingSystemValueLabel.text= +DataSourceSummaryPanel.ingestHistoryDetailsLabel.text=View Ingest History for more details +DataSourceSummaryPanel.ingestHistoryButton.text=Ingest History +DataSourceSummaryPanel.openButton.text=Goto Datasource +DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs +DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java new file mode 100644 index 0000000000..f33dada13c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -0,0 +1,72 @@ +/* + * 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.casemodule.datasourceSummary; + +import java.awt.Frame; +import java.awt.event.ActionEvent; +import javax.swing.Action; +import javax.swing.JDialog; +import javax.swing.SwingUtilities; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; + +public class DataSourceSummaryAction extends CallableSystemAction { + + private static final long serialVersionUID = 1L; + private static JDialog dataSourceSummaryDialog; + + DataSourceSummaryAction() { + putValue(Action.NAME, NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction")); + this.setEnabled(false); + } + + @Messages({"DataSourceSummaryAction.window.title=Data Source Summary"}) + @Override + public void performAction() { + SwingUtilities.invokeLater(() -> { + String title = NbBundle.getMessage(this.getClass(), "DataSourceSummaryAction.window.title"); + Frame mainWindow = WindowManager.getDefault().getMainWindow(); + dataSourceSummaryDialog = new JDialog(mainWindow, title, true); + DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); + dataSourceSummaryPanel.addCloseButtonAction((ActionEvent e) -> { + dataSourceSummaryDialog.dispose(); + }); + dataSourceSummaryDialog.add(dataSourceSummaryPanel); + dataSourceSummaryDialog.setResizable(true); + dataSourceSummaryDialog.pack(); + dataSourceSummaryDialog.setLocationRelativeTo(mainWindow); + dataSourceSummaryDialog.setVisible(true); + dataSourceSummaryDialog.toFront(); + }); + } + + @Override + public String getName() { + return NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction"); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form new file mode 100644 index 0000000000..90d4aea1a1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -0,0 +1,224 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java new file mode 100644 index 0000000000..e09aec86e8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -0,0 +1,375 @@ +/* + * 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.casemodule.datasourceSummary; + +import java.awt.event.ActionListener; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.table.AbstractTableModel; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +public class DataSourceSummaryPanel extends javax.swing.JPanel { + + private final List allIngestJobs = new ArrayList<>(); + private List ingestJobs = new ArrayList<>(); + private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); + private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); + private final List dataSources = new ArrayList<>(); + private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName()); + + /** + * Creates new form DataSourceSummary + */ + @Messages({"DataSourceSummaryPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.", + "DataSourceSummaryPanel.getDataSources.error.title=Load Failure"}) + public DataSourceSummaryPanel() { + initComponents(); + ingestJobsTable.getTableHeader().setReorderingAllowed(false); + fileCountsTable.getTableHeader().setReorderingAllowed(false); + dataSourcesTable.getTableHeader().setReorderingAllowed(false); + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + allIngestJobs.addAll(skCase.getIngestJobs()); + dataSources.addAll(skCase.getDataSources()); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex); + JOptionPane.showMessageDialog(this, Bundle.DataSourceSummaryPanel_getDataSources_error_text(), Bundle.DataSourceSummaryPanel_getDataSources_error_title(), JOptionPane.ERROR_MESSAGE); + } + dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + if (!e.getValueIsAdjusting()) { + updateIngestJobs(); + } + }); + } + + @Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.", + "DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"}) + private void updateIngestJobs() { + Long selectedDataSourceId = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow()).getId()); + ingestJobs.clear(); + if (selectedDataSourceId != null) { + for (IngestJobInfo ingestJob : allIngestJobs) { + if (ingestJob.getObjectId() == selectedDataSourceId) { + ingestJobs.add(ingestJob); + } + } + } + ingestJobTableModel = new IngestJobTableModel(); + ingestJobsTable.setModel(ingestJobTableModel); + this.repaint(); + } + + /** + * 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() { + + jSeparator1 = new javax.swing.JSeparator(); + dataSourcesScrollPane = new javax.swing.JScrollPane(); + dataSourcesTable = new javax.swing.JTable(); + ingestJobsScrollPane = new javax.swing.JScrollPane(); + ingestJobsTable = new javax.swing.JTable(); + fileCountsScrollPane = new javax.swing.JScrollPane(); + fileCountsTable = new javax.swing.JTable(); + opperatingSystemLabel = new javax.swing.JLabel(); + opperatingSystemValueLabel = new javax.swing.JLabel(); + fileCountsLabel = new javax.swing.JLabel(); + ingestJobsLabel = new javax.swing.JLabel(); + ingestHistoryDetailsLabel = new javax.swing.JLabel(); + closeButton = new javax.swing.JButton(); + openButton = new javax.swing.JButton(); + ingestHistoryButton = new javax.swing.JButton(); + + dataSourcesTable.setModel(dataSourceTableModel); + dataSourcesScrollPane.setViewportView(dataSourcesTable); + + ingestJobsTable.setModel(ingestJobTableModel); + ingestJobsScrollPane.setViewportView(ingestJobsTable); + + fileCountsTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {"Images", "0"}, + {"Videos", "0"}, + {"Audio", "0"}, + {"Documents", "0"}, + {"Executables", "0"} + }, + new String [] { + "File type", "Count" + } + )); + fileCountsScrollPane.setViewportView(fileCountsTable); + + org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemValueLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemValueLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(fileCountsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.fileCountsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryDetailsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryDetailsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.openButton.text")); // NOI18N + openButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + openButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryButton.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(openButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(closeButton)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(opperatingSystemLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(ingestHistoryDetailsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ingestHistoryButton)) + .addComponent(ingestJobsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE)))) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, ingestHistoryButton, openButton}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(8, 8, 8) + .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 5, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(fileCountsLabel) + .addComponent(ingestJobsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(opperatingSystemLabel) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createSequentialGroup() + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(ingestHistoryButton) + .addComponent(ingestHistoryDetailsLabel)) + .addGap(10, 10, 10))) + .addGap(0, 0, 0) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(openButton)) + .addContainerGap()) + ); + }// //GEN-END:initComponents + + /** + * Adds an action listener to the Close button of the panel. + * + * @param action + */ + void addCloseButtonAction(ActionListener action) { + this.closeButton.addActionListener(action); + } + + private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_openButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private javax.swing.JScrollPane dataSourcesScrollPane; + private javax.swing.JTable dataSourcesTable; + private javax.swing.JLabel fileCountsLabel; + private javax.swing.JScrollPane fileCountsScrollPane; + private javax.swing.JTable fileCountsTable; + private javax.swing.JButton ingestHistoryButton; + private javax.swing.JLabel ingestHistoryDetailsLabel; + private javax.swing.JLabel ingestJobsLabel; + private javax.swing.JScrollPane ingestJobsScrollPane; + private javax.swing.JTable ingestJobsTable; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JButton openButton; + private javax.swing.JLabel opperatingSystemLabel; + private javax.swing.JLabel opperatingSystemValueLabel; + // End of variables declaration//GEN-END:variables + + @Messages({"DataSourceSummaryPanel.IngestJobTableModel.StartTime.header=Start Time", + "DataSourceSummaryPanel.IngestJobTableModel.EndTime.header=End Time", + "DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) + private class IngestJobTableModel extends AbstractTableModel { + + private final List columnHeaders = new ArrayList<>(); + + IngestJobTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_StartTime_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_EndTime_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_IngestStatus_header()); + } + + @Override + public int getRowCount() { + return ingestJobs.size(); + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + IngestJobInfo currIngestJob = ingestJobs.get(rowIndex); + switch (columnIndex) { + case 0: + return datetimeFormat.format(currIngestJob.getStartDateTime()); + case 1: + Date endDate = currIngestJob.getEndDateTime(); + if (endDate.getTime() == 0) { + return "N/A"; + } + return datetimeFormat.format(currIngestJob.getEndDateTime()); + case 2: + return currIngestJob.getStatus().getDisplayName(); + default: + break; + } + return null; + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + } + + @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", + "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", + "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", + "DataSourceSummaryPanel.DataSourceTableModel.results.header=Results", + "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) + private class DataSourceTableModel extends AbstractTableModel { + + private final List columnHeaders = new ArrayList<>(); + + DataSourceTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); + } + + @Override + public int getRowCount() { + return dataSources.size(); + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DataSource currentDataSource = dataSources.get(rowIndex); + switch (columnIndex) { + case 0: + return currentDataSource.getName(); + case 1: + return ""; + case 2: { + return ""; +// try { +// return currentDataSource.getChildrenCount(); +// } catch (TskCoreException ex) { +// return "UNABLE TO GET DS CHILD SIZE"; +// } + } + case 3: { + return ""; +// try { +// return currentDataSource.getAllArtifactsCount(); +// } catch (TskCoreException ex) { +// return "UNABLE TO GET ARTIFACT COUNT"; +// } + } + case 4: + return ""; + default: + break; + } + return null; + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 7fef77ee04..783aaf5b42 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -48,6 +48,7 @@ + @@ -182,6 +183,10 @@ + + + + From 82bab1779564f8ebb8d9193e997b31cb3f74a9aa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 3 Jan 2019 18:43:45 -0500 Subject: [PATCH 3/9] 4568 populate file/result/tag count columns for data sources --- .../datasourceSummary/Bundle.properties | 2 +- .../DataSourceSummaryPanel.form | 8 ++- .../DataSourceSummaryPanel.java | 61 +++++++++++++------ 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index 2c7eea054f..982d7ee1ff 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -4,6 +4,6 @@ DataSourceSummaryPanel.opperatingSystemLabel.text=OS: DataSourceSummaryPanel.opperatingSystemValueLabel.text= DataSourceSummaryPanel.ingestHistoryDetailsLabel.text=View Ingest History for more details DataSourceSummaryPanel.ingestHistoryButton.text=Ingest History -DataSourceSummaryPanel.openButton.text=Goto Datasource +DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 90d4aea1a1..cff9ef1929 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -1,6 +1,6 @@ -
+ @@ -110,6 +110,9 @@ + + + @@ -126,6 +129,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index e09aec86e8..4c759befe3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; public class DataSourceSummaryPanel extends javax.swing.JPanel { @@ -115,9 +116,11 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { ingestHistoryButton = new javax.swing.JButton(); dataSourcesTable.setModel(dataSourceTableModel); + dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); dataSourcesScrollPane.setViewportView(dataSourcesTable); ingestJobsTable.setModel(ingestJobTableModel); + ingestJobsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); ingestJobsScrollPane.setViewportView(ingestJobsTable); fileCountsTable.setModel(new javax.swing.table.DefaultTableModel( @@ -261,6 +264,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { "DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) private class IngestJobTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; + private final List columnHeaders = new ArrayList<>(); IngestJobTableModel() { @@ -313,6 +318,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) private class DataSourceTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; + private final List columnHeaders = new ArrayList<>(); DataSourceTableModel() { @@ -341,30 +348,50 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return currentDataSource.getName(); case 1: return ""; - case 2: { - return ""; -// try { -// return currentDataSource.getChildrenCount(); -// } catch (TskCoreException ex) { -// return "UNABLE TO GET DS CHILD SIZE"; -// } - } - case 3: { - return ""; -// try { -// return currentDataSource.getAllArtifactsCount(); -// } catch (TskCoreException ex) { -// return "UNABLE TO GET ARTIFACT COUNT"; -// } - } + case 2: + return getCountOfFiles(currentDataSource); + case 3: + return getCountOfArtifacts(currentDataSource); case 4: - return ""; + return getCountOfTags(currentDataSource); default: break; } return null; } + private long getCountOfFiles(DataSource currentDataSource) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND name<>''"); + } catch (TskCoreException | NoCurrentCaseException ex) { + return 0; + } + } + + private long getCountOfArtifacts(DataSource currentDataSource) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.getBlackboardArtifactsCountForDatasource(currentDataSource.getId()); + } catch (TskCoreException | NoCurrentCaseException ex) { + return 0; + } + } + + private long getCountOfTags(DataSource currentDataSource) { + long countOfTags = 0; + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + countOfTags = skCase.getBlackboardArtifactTagsCountForDataSource(currentDataSource.getId()); + countOfTags += skCase.getContentTagsCountForDataSource(currentDataSource.getId()); + } catch (TskCoreException | NoCurrentCaseException ex) { + } + return countOfTags; + } + @Override public String getColumnName(int column) { return columnHeaders.get(column); From 06d5c55fb2ade18c2cdf15413b28176637f74136 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 4 Jan 2019 10:57:13 -0500 Subject: [PATCH 4/9] 4568 add counts for file types to Data source summary --- .../DataSourceSummaryPanel.form | 19 +--- .../DataSourceSummaryPanel.java | 105 +++++++++++++++--- 2 files changed, 93 insertions(+), 31 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index cff9ef1929..7c03337b7a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -145,23 +145,8 @@ - - - - - - - - - - - - - - - - -
+ +
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 4c759befe3..dea71e43f2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -24,6 +24,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -32,6 +33,7 @@ import javax.swing.table.AbstractTableModel; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -44,6 +46,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private List ingestJobs = new ArrayList<>(); private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); + private FilesTableModel filesTableModel = new FilesTableModel(); private final List dataSources = new ArrayList<>(); private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName()); @@ -69,6 +72,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { updateIngestJobs(); + filesTableModel = new FilesTableModel(); + fileCountsTable.setModel(filesTableModel); + this.repaint(); } }); } @@ -87,7 +93,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } ingestJobTableModel = new IngestJobTableModel(); ingestJobsTable.setModel(ingestJobTableModel); - this.repaint(); } /** @@ -123,18 +128,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { ingestJobsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); ingestJobsScrollPane.setViewportView(ingestJobsTable); - fileCountsTable.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - {"Images", "0"}, - {"Videos", "0"}, - {"Audio", "0"}, - {"Documents", "0"}, - {"Executables", "0"} - }, - new String [] { - "File type", "Count" - } - )); + fileCountsTable.setModel(filesTableModel); fileCountsScrollPane.setViewportView(fileCountsTable); org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N @@ -311,6 +305,89 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } + @Messages({"DataSourceSummaryPanel.FilesTableModel.type.header=File Type", + "DataSourceSummaryPanel.FilesTableModel.count.header=Count"}) + private class FilesTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + private final List columnHeaders = new ArrayList<>(); + + FilesTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header()); + } + + @Override + public int getRowCount() { + return 5; + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (columnIndex == 0) { + switch (rowIndex) { + case 0: + return "Images"; + case 1: + return "Videos"; + case 2: + return "Audio"; + case 3: + return "Documents"; + case 4: + return "Executables"; + default: + break; + } + } else if (columnIndex == 1) { + DataSource currentDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + if (currentDataSource != null) { + switch (rowIndex) { + case 0: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); + case 1: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); + case 2: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); + case 3: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); + case 4: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); + default: + break; + } + } + } + return null; + } + + private long getCountOfFiles(DataSource currentDataSource, Set setOfMimeTypes) { + try { + String inClause = String.join("', '", setOfMimeTypes); + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND mime_type IN ('" + inClause + "')" + + " AND name<>''"); + } catch (TskCoreException | NoCurrentCaseException ex) { + return 0; + } + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + } + @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", @@ -350,7 +427,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return ""; case 2: return getCountOfFiles(currentDataSource); - case 3: + case 3: return getCountOfArtifacts(currentDataSource); case 4: return getCountOfTags(currentDataSource); From 2aa99083070fdc0f4c29039ee91a620ce4635a28 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 4 Jan 2019 13:39:55 -0500 Subject: [PATCH 5/9] 4568 make use of CaseDbAccessManager to eliminate need for datamodel changes --- .../DataSourceSummaryPanel.java | 99 ++++++++++++++++--- 1 file changed, 83 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index dea71e43f2..40519ce6db 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -19,11 +19,16 @@ package org.sleuthkit.autopsy.casemodule.datasourceSummary; import java.awt.event.ActionListener; +import java.sql.ResultSet; +import java.sql.SQLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,6 +39,8 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -398,6 +405,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private final List columnHeaders = new ArrayList<>(); + private final Map fileCountsMap; + private final Map artifactCountsMap; + private final Map tagCountsMap; DataSourceTableModel() { columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); @@ -405,6 +415,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); + fileCountsMap = getCountsOfFiles(); + artifactCountsMap = getCountsOfArtifacts(); + tagCountsMap = getCountsOfTags(); + } @Override @@ -420,53 +434,79 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { DataSource currentDataSource = dataSources.get(rowIndex); + Long count; switch (columnIndex) { case 0: return currentDataSource.getName(); case 1: return ""; case 2: - return getCountOfFiles(currentDataSource); + count = fileCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; case 3: - return getCountOfArtifacts(currentDataSource); + count = artifactCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; case 4: - return getCountOfTags(currentDataSource); + count = tagCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; default: break; } return null; } - private long getCountOfFiles(DataSource currentDataSource) { + private Map getCountsOfFiles() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>''"); + + " AND name<>'' GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countFilesQuery, callback); + return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { - return 0; + return Collections.emptyMap(); } } - private long getCountOfArtifacts(DataSource currentDataSource) { + private Map getCountsOfArtifacts() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return skCase.getBlackboardArtifactsCountForDatasource(currentDataSource.getId()); + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() + + " GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); + return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { - return 0; + return Collections.emptyMap(); } } - private long getCountOfTags(DataSource currentDataSource) { - long countOfTags = 0; + private Map getCountsOfTags() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - countOfTags = skCase.getBlackboardArtifactTagsCountForDataSource(currentDataSource.getId()); - countOfTags += skCase.getContentTagsCountForDataSource(currentDataSource.getId()); + DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); + String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM content_tags as content_tags, tsk_files as tsk_files" + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); + Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); + DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); + String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); + //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query + artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); + return tagCountMap; } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); } - return countOfTags; + } @Override @@ -474,6 +514,33 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return columnHeaders.get(column); } + private class DataSourceCountsCallback implements CaseDbAccessQueryCallback { + + Map dataSourceObjIdCounts = new HashMap<>(); + + @Override + public void process(ResultSet rs) { + try { + while (rs.next()) { + try { + long dataSourceObjectId = rs.getLong("data_source_obj_id"); + long count = rs.getLong("count"); + dataSourceObjIdCounts.put(dataSourceObjectId, count); + } catch (SQLException ex) { + System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); + } + } + } catch (SQLException ex) { + System.out.println("Failed to get next result" + ex.getMessage()); + } + } + + Map getMapOfCounts() { + return Collections.unmodifiableMap(dataSourceObjIdCounts); + } + + } + } } From 783b1846cca28d9d91a9cf31f7753e52dc79d887 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 12:16:47 -0500 Subject: [PATCH 6/9] 4568 add context menu action and selection of datasource --- .../datasourceSummary/Bundle.properties | 4 +- .../DataSourceSummaryAction.java | 17 +- .../DataSourceSummaryPanel.form | 65 ++---- .../DataSourceSummaryPanel.java | 210 ++++++++++-------- .../autopsy/datamodel/ImageNode.java | 2 + .../datamodel/SpecialDirectoryNode.java | 2 + 6 files changed, 160 insertions(+), 140 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index 982d7ee1ff..90534d59ae 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -1,9 +1,7 @@ -CTL_DataSourceSummaryAction=Data Source Summary +CTL_DataSourceSummaryAction=View Summary Information DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) DataSourceSummaryPanel.opperatingSystemLabel.text=OS: DataSourceSummaryPanel.opperatingSystemValueLabel.text= -DataSourceSummaryPanel.ingestHistoryDetailsLabel.text=View Ingest History for more details -DataSourceSummaryPanel.ingestHistoryButton.text=Ingest History DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java index f33dada13c..6be01d62ce 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.casemodule.datasourceSummary; import java.awt.Frame; import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.util.EnumSet; import javax.swing.Action; import javax.swing.JDialog; import javax.swing.SwingUtilities; @@ -28,15 +30,27 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; public class DataSourceSummaryAction extends CallableSystemAction { private static final long serialVersionUID = 1L; private static JDialog dataSourceSummaryDialog; + private final Long selectDataSource; + @Messages({"DataSourceSummaryAction.caseMenuName.text=Data Source Summary"}) DataSourceSummaryAction() { + this(false, null); + putValue(Action.NAME, Bundle.DataSourceSummaryAction_caseMenuName_text()); + } + + public DataSourceSummaryAction(boolean enabled, Long selectedDataSource) { putValue(Action.NAME, NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction")); - this.setEnabled(false); + this.setEnabled(enabled); + selectDataSource = selectedDataSource; + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { + setEnabled(null != evt.getNewValue()); + }); } @Messages({"DataSourceSummaryAction.window.title=Data Source Summary"}) @@ -50,6 +64,7 @@ public class DataSourceSummaryAction extends CallableSystemAction { dataSourceSummaryPanel.addCloseButtonAction((ActionEvent e) -> { dataSourceSummaryDialog.dispose(); }); + dataSourceSummaryPanel.selectDataSource(selectDataSource); dataSourceSummaryDialog.add(dataSourceSummaryPanel); dataSourceSummaryDialog.setResizable(true); dataSourceSummaryDialog.pack(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 7c03337b7a..b7c26d4c22 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -27,25 +27,20 @@ - + - - + + + + + + + + - - - - - - - - - - - @@ -57,7 +52,7 @@ - + @@ -67,25 +62,15 @@ - - - - - - - - - - - - - - - - - + + - + + + + + + @@ -180,13 +165,6 @@ - - - - - - - @@ -204,12 +182,5 @@ - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 40519ce6db..63fa47c568 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule.datasourceSummary; +import java.awt.Rectangle; import java.awt.event.ActionListener; import java.sql.ResultSet; import java.sql.SQLException; @@ -39,10 +40,13 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.OSInfo; +import org.sleuthkit.datamodel.OSUtility; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -53,10 +57,11 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private List ingestJobs = new ArrayList<>(); private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); - private FilesTableModel filesTableModel = new FilesTableModel(); + private FilesTableModel filesTableModel = new FilesTableModel(null); private final List dataSources = new ArrayList<>(); private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName()); + private List osInfoList; /** * Creates new form DataSourceSummary @@ -72,28 +77,49 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); allIngestJobs.addAll(skCase.getIngestJobs()); dataSources.addAll(skCase.getDataSources()); + osInfoList = OSUtility.getOSInfo(skCase); } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex); JOptionPane.showMessageDialog(this, Bundle.DataSourceSummaryPanel_getDataSources_error_text(), Bundle.DataSourceSummaryPanel_getDataSources_error_title(), JOptionPane.ERROR_MESSAGE); } dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { - updateIngestJobs(); - filesTableModel = new FilesTableModel(); + DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + updateIngestJobs(selectedDataSource); + filesTableModel = new FilesTableModel(selectedDataSource); fileCountsTable.setModel(filesTableModel); + opperatingSystemValueLabel.setText(getOSName(selectedDataSource)); this.repaint(); } }); } + private String getOSName(DataSource selectedDataSource) { + String osName = ""; + if (selectedDataSource != null) { + for (OSInfo osInfo : osInfoList) { + try { + if (!osInfo.getArtifacts().isEmpty() && osInfo.getArtifacts().get(0).getDataSource().getId() == selectedDataSource.getId()) { + osName = osInfo.getOSName(); + if (!osName.isEmpty()) { + break; + } + } + } catch (TskCoreException ex) { + + } + } + } + return osName; + } + @Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.", "DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"}) - private void updateIngestJobs() { - Long selectedDataSourceId = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow()).getId()); + private void updateIngestJobs(DataSource selectedDataSource) { ingestJobs.clear(); - if (selectedDataSourceId != null) { + if (selectedDataSource != null) { for (IngestJobInfo ingestJob : allIngestJobs) { - if (ingestJob.getObjectId() == selectedDataSourceId) { + if (ingestJob.getObjectId() == selectedDataSource.getId()) { ingestJobs.add(ingestJob); } } @@ -122,10 +148,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { opperatingSystemValueLabel = new javax.swing.JLabel(); fileCountsLabel = new javax.swing.JLabel(); ingestJobsLabel = new javax.swing.JLabel(); - ingestHistoryDetailsLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); openButton = new javax.swing.JButton(); - ingestHistoryButton = new javax.swing.JButton(); dataSourcesTable.setModel(dataSourceTableModel); dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); @@ -146,8 +170,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryDetailsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryDetailsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.openButton.text")); // NOI18N @@ -157,8 +179,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryButton.text")); // NOI18N - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -175,30 +195,26 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(closeButton)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(opperatingSystemLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(ingestHistoryDetailsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(ingestHistoryButton)) .addComponent(ingestJobsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE)))) + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(opperatingSystemLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, ingestHistoryButton, openButton}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, openButton}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(8, 8, 8) - .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE) + .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 120, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 5, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -207,20 +223,13 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(ingestJobsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(opperatingSystemLabel) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(layout.createSequentialGroup() - .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(ingestHistoryButton) - .addComponent(ingestHistoryDetailsLabel)) - .addGap(10, 10, 10))) - .addGap(0, 0, 0) + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(opperatingSystemLabel) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) .addComponent(openButton)) @@ -235,10 +244,29 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { */ void addCloseButtonAction(ActionListener action) { this.closeButton.addActionListener(action); + this.openButton.addActionListener(action); + } + + void selectDataSource(Long dataSourceID) { + if (dataSourceID != null) { + for (int i = 0; i < dataSources.size(); i++) { + if (dataSources.get(i).getId() == dataSourceID) { + dataSourcesTable.setRowSelectionInterval(i, i); + dataSourcesTable.scrollRectToVisible(new Rectangle(dataSourcesTable.getCellRect(i, 0, true))); + return; + } + } + } + if (!dataSources.isEmpty()) { + dataSourcesTable.setRowSelectionInterval(0, 0); + } } private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed - // TODO add your handling code here: + DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + if (selectedDataSource != null) { + new ViewContextAction("", selectedDataSource).actionPerformed(evt); + } }//GEN-LAST:event_openButtonActionPerformed @@ -249,8 +277,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private javax.swing.JLabel fileCountsLabel; private javax.swing.JScrollPane fileCountsScrollPane; private javax.swing.JTable fileCountsTable; - private javax.swing.JButton ingestHistoryButton; - private javax.swing.JLabel ingestHistoryDetailsLabel; private javax.swing.JLabel ingestJobsLabel; private javax.swing.JScrollPane ingestJobsScrollPane; private javax.swing.JTable ingestJobsTable; @@ -317,12 +343,13 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private class FilesTableModel extends AbstractTableModel { private static final long serialVersionUID = 1L; - + private final DataSource currentDataSource; private final List columnHeaders = new ArrayList<>(); - FilesTableModel() { + FilesTableModel(DataSource selectedDataSource) { columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header()); + currentDataSource = selectedDataSource; } @Override @@ -335,57 +362,64 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return columnHeaders.size(); } + @Messages({ + "DataSourceSummaryPanel.FilesTableModel.images.row=Images", + "DataSourceSummaryPanel.FilesTableModel.videos.row=Videos", + "DataSourceSummaryPanel.FilesTableModel.audio.row=Audio", + "DataSourceSummaryPanel.FilesTableModel.documents.row=Documents", + "DataSourceSummaryPanel.FilesTableModel.executables.row=Executables" + }) @Override public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex == 0) { switch (rowIndex) { case 0: - return "Images"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_images_row(); case 1: - return "Videos"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_videos_row(); case 2: - return "Audio"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_audio_row(); case 3: - return "Documents"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_documents_row(); case 4: - return "Executables"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_executables_row(); default: break; } } else if (columnIndex == 1) { - DataSource currentDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); - if (currentDataSource != null) { - switch (rowIndex) { - case 0: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); - case 1: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); - case 2: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); - case 3: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); - case 4: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); - default: - break; - } + switch (rowIndex) { + case 0: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); + case 1: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); + case 2: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); + case 3: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); + case 4: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); + default: + break; } } return null; } - private long getCountOfFiles(DataSource currentDataSource, Set setOfMimeTypes) { - try { - String inClause = String.join("', '", setOfMimeTypes); - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() - + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND mime_type IN ('" + inClause + "')" - + " AND name<>''"); - } catch (TskCoreException | NoCurrentCaseException ex) { - return 0; + private Long getCountOfFiles(Set setOfMimeTypes) { + if (currentDataSource != null) { + try { + String inClause = String.join("', '", setOfMimeTypes); + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND mime_type IN ('" + inClause + "')" + + " AND name<>''"); + } catch (TskCoreException | NoCurrentCaseException ex) { + + } } + return null; } @Override @@ -434,7 +468,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { DataSource currentDataSource = dataSources.get(rowIndex); - Long count; + Long count; switch (columnIndex) { case 0: return currentDataSource.getName(); @@ -459,10 +493,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); DataSourceCountsCallback callback = new DataSourceCountsCallback(); - String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>'' GROUP BY data_source_obj_id"; + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countFilesQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -474,9 +508,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); DataSourceCountsCallback callback = new DataSourceCountsCallback(); - String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() - + " GROUP BY data_source_obj_id"; + + " GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -488,17 +522,17 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); - String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM content_tags as content_tags, tsk_files as tsk_files" + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " GROUP BY data_source_obj_id"; + + " GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); - String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " GROUP BY data_source_obj_id"; + + " GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); @@ -523,9 +557,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { while (rs.next()) { try { - long dataSourceObjectId = rs.getLong("data_source_obj_id"); - long count = rs.getLong("count"); - dataSourceObjIdCounts.put(dataSourceObjectId, count); + dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); } catch (SQLException ex) { System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 0bb186d75e..e33099b2b3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -34,6 +34,7 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -108,6 +109,7 @@ public class ImageNode extends AbstractContentNode { actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); actionsList.add(new FileSearchAction( Bundle.ImageNode_getActions_openFileSearchByAttr_text())); + actionsList.add(new DataSourceSummaryAction(true, content.getId())); actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index 7dc18a7394..a31f0932ae 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import javax.swing.Action; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -63,6 +64,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); } else { actions.add(new RunIngestModulesAction(content)); From 9e298d608ec54cde4dc2abfba09c520337ac2d09 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 13:48:04 -0500 Subject: [PATCH 7/9] 4568 create second action to avoid multiple instances of CallableSystemAction being created --- .../datasourceSummary/Bundle.properties | 2 - .../DataSourceSummaryAction.java | 55 +++++---------- .../DataSourceSummaryPanel.form | 5 -- .../DataSourceSummaryPanel.java | 2 - .../ViewSummaryInformationAction.java | 67 +++++++++++++++++++ .../autopsy/datamodel/ImageNode.java | 4 +- .../datamodel/SpecialDirectoryNode.java | 4 +- 7 files changed, 89 insertions(+), 50 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index 90534d59ae..df9cb9a3bb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -1,7 +1,5 @@ -CTL_DataSourceSummaryAction=View Summary Information DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) DataSourceSummaryPanel.opperatingSystemLabel.text=OS: -DataSourceSummaryPanel.opperatingSystemValueLabel.text= DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java index 6be01d62ce..ae9980b357 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -18,70 +18,51 @@ */ package org.sleuthkit.autopsy.casemodule.datasourceSummary; -import java.awt.Frame; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.util.EnumSet; import javax.swing.Action; -import javax.swing.JDialog; -import javax.swing.SwingUtilities; +import org.openide.awt.ActionID; +import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction") +@ActionRegistration(displayName = "#CTL_DataSourceSummaryAction", lazy = false) +@Messages({"CTL_DataSourceSummaryAction=Data Source Summary"}) public class DataSourceSummaryAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - private static JDialog dataSourceSummaryDialog; - private final Long selectDataSource; - - @Messages({"DataSourceSummaryAction.caseMenuName.text=Data Source Summary"}) + DataSourceSummaryAction() { - this(false, null); - putValue(Action.NAME, Bundle.DataSourceSummaryAction_caseMenuName_text()); - } - - public DataSourceSummaryAction(boolean enabled, Long selectedDataSource) { - putValue(Action.NAME, NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction")); - this.setEnabled(enabled); - selectDataSource = selectedDataSource; + putValue(Action.NAME, Bundle.CTL_DataSourceSummaryAction()); + this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { setEnabled(null != evt.getNewValue()); - }); + }); } - - @Messages({"DataSourceSummaryAction.window.title=Data Source Summary"}) + @Override public void performAction() { - SwingUtilities.invokeLater(() -> { - String title = NbBundle.getMessage(this.getClass(), "DataSourceSummaryAction.window.title"); - Frame mainWindow = WindowManager.getDefault().getMainWindow(); - dataSourceSummaryDialog = new JDialog(mainWindow, title, true); - DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); - dataSourceSummaryPanel.addCloseButtonAction((ActionEvent e) -> { - dataSourceSummaryDialog.dispose(); - }); - dataSourceSummaryPanel.selectDataSource(selectDataSource); - dataSourceSummaryDialog.add(dataSourceSummaryPanel); - dataSourceSummaryDialog.setResizable(true); - dataSourceSummaryDialog.pack(); - dataSourceSummaryDialog.setLocationRelativeTo(mainWindow); - dataSourceSummaryDialog.setVisible(true); - dataSourceSummaryDialog.toFront(); - }); + //perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used + new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, "")); } @Override public String getName() { - return NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction"); + return Bundle.CTL_DataSourceSummaryAction(); } @Override public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } + + @Override + public boolean asynchronous(){ + return false; + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index b7c26d4c22..0ff4d08b72 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -145,11 +145,6 @@ - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 63fa47c568..bd6a4dc457 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -164,8 +164,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemValueLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemValueLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(fileCountsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.fileCountsLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java new file mode 100644 index 0000000000..400af48209 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java @@ -0,0 +1,67 @@ +/* + * 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.casemodule.datasourceSummary; + +import java.awt.Frame; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.JDialog; +import javax.swing.SwingUtilities; +import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; + +/** + * + * @author wschaefer + */ +public final class ViewSummaryInformationAction extends AbstractAction { + + private static JDialog dataSourceSummaryDialog; + private static Long selectDataSource; + private static final long serialVersionUID = 1L; + + @NbBundle.Messages({"ViewSummaryInformationAction.name.text=View Summary Information"}) + public ViewSummaryInformationAction(Long selectedDataSource) { + super(Bundle.ViewSummaryInformationAction_name_text()); + this.setEnabled(true); + selectDataSource = selectedDataSource; + } + + @NbBundle.Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"}) + @Override + public void actionPerformed(ActionEvent actionEvent) { + SwingUtilities.invokeLater(() -> { + String title = Bundle.ViewSummaryInformationAction_window_title(); + Frame mainWindow = WindowManager.getDefault().getMainWindow(); + dataSourceSummaryDialog = new JDialog(mainWindow, title, true); + DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); + dataSourceSummaryPanel.addCloseButtonAction((ActionEvent event) -> { + dataSourceSummaryDialog.dispose(); + }); + dataSourceSummaryPanel.selectDataSource(selectDataSource); + dataSourceSummaryDialog.add(dataSourceSummaryPanel); + dataSourceSummaryDialog.setResizable(true); + dataSourceSummaryDialog.pack(); + dataSourceSummaryDialog.setLocationRelativeTo(mainWindow); + dataSourceSummaryDialog.setVisible(true); + dataSourceSummaryDialog.toFront(); + }); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index e33099b2b3..9025b325e3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -34,7 +34,7 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.ViewSummaryInformationAction; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -109,7 +109,7 @@ public class ImageNode extends AbstractContentNode { actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); actionsList.add(new FileSearchAction( Bundle.ImageNode_getActions_openFileSearchByAttr_text())); - actionsList.add(new DataSourceSummaryAction(true, content.getId())); + actionsList.add(new ViewSummaryInformationAction(content.getId())); actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index a31f0932ae..9509ccb483 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.List; import javax.swing.Action; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.ViewSummaryInformationAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -64,7 +64,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); } else { actions.add(new RunIngestModulesAction(content)); From 97f5d1cd3e179dc1f5f84a05b5bf3e843829a17a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 15:50:12 -0500 Subject: [PATCH 8/9] 4568 add comments and clean up classes in regards to data source summary --- .../datasourceSummary/Bundle.properties | 2 +- .../DataSourceSummaryAction.java | 23 +- .../DataSourceSummaryPanel.form | 16 +- .../DataSourceSummaryPanel.java | 452 +++++++++++------- .../ViewSummaryInformationAction.java | 22 +- 5 files changed, 322 insertions(+), 193 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index df9cb9a3bb..855f75bd20 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -1,5 +1,5 @@ DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) DataSourceSummaryPanel.opperatingSystemLabel.text=OS: -DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close +DataSourceSummaryPanel.gotoDataSourceButton.text=Goto Data Source diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java index ae9980b357..5dc3035867 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -32,22 +32,29 @@ import org.sleuthkit.autopsy.casemodule.Case; @ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction") @ActionRegistration(displayName = "#CTL_DataSourceSummaryAction", lazy = false) @Messages({"CTL_DataSourceSummaryAction=Data Source Summary"}) +/** + * DataSourceSummaryAction action for the Case menu to activate a ViewSummaryInformationAction selecting the first data source. + */ public class DataSourceSummaryAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - + + /** + * Create a datasource summary action which will be disabled when no case is + * open. + */ DataSourceSummaryAction() { putValue(Action.NAME, Bundle.CTL_DataSourceSummaryAction()); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { setEnabled(null != evt.getNewValue()); - }); + }); } - + @Override public void performAction() { - //perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used - new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, "")); + //perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used + new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, "")); } @Override @@ -59,10 +66,4 @@ public class DataSourceSummaryAction extends CallableSystemAction { public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } - - @Override - public boolean asynchronous(){ - return false; - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 0ff4d08b72..16fa26c1a0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -23,7 +23,7 @@ - + @@ -66,14 +66,16 @@ - + - + + + - + @@ -167,14 +169,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index bd6a4dc457..5f7315a566 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -51,8 +51,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -public class DataSourceSummaryPanel extends javax.swing.JPanel { +final class DataSourceSummaryPanel extends javax.swing.JPanel { + private static final long serialVersionUID = 1L; private final List allIngestJobs = new ArrayList<>(); private List ingestJobs = new ArrayList<>(); private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); @@ -64,11 +65,13 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private List osInfoList; /** - * Creates new form DataSourceSummary + * Creates new form DataSourceSummaryPanel for displaying a summary of the + * data sources for the fcurrent case and the contents found for each + * datasource. */ @Messages({"DataSourceSummaryPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.", "DataSourceSummaryPanel.getDataSources.error.title=Load Failure"}) - public DataSourceSummaryPanel() { + DataSourceSummaryPanel() { initComponents(); ingestJobsTable.getTableHeader().setReorderingAllowed(false); fileCountsTable.getTableHeader().setReorderingAllowed(false); @@ -94,25 +97,44 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { }); } + /** + * Get the name of the operating system if it is available. Otherwise get + * and empty string. + * + * @param selectedDataSource the datasource to get the OS information for + * + * @return the name of the opperating system on the specified datasource, + * empty string if no opperating system info found + */ private String getOSName(DataSource selectedDataSource) { String osName = ""; if (selectedDataSource != null) { for (OSInfo osInfo : osInfoList) { try { + //assumes only one Opperating System per datasource + //get the datasource id from the OSInfo's first artifact if it has artifacts if (!osInfo.getArtifacts().isEmpty() && osInfo.getArtifacts().get(0).getDataSource().getId() == selectedDataSource.getId()) { osName = osInfo.getOSName(); + //if this OSInfo object has a name use it otherwise keep checking OSInfo objects if (!osName.isEmpty()) { break; } } - } catch (TskCoreException ex) { - + } catch (TskCoreException ignored) { + //unable to get datasource for the OSInfo Object + //continue checking for OSInfo objects which we can get the desired information from } } } return osName; } + /** + * Update the ingestJobs list with the ingest jobs for the + * selectedDataSource + * + * @param selectedDataSource the datasource to find the ingest jobs for + */ @Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.", "DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"}) private void updateIngestJobs(DataSource selectedDataSource) { @@ -149,7 +171,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { fileCountsLabel = new javax.swing.JLabel(); ingestJobsLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); - openButton = new javax.swing.JButton(); + gotoDataSourceButton = new javax.swing.JButton(); dataSourcesTable.setModel(dataSourceTableModel); dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); @@ -170,10 +192,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.openButton.text")); // NOI18N - openButton.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(gotoDataSourceButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.gotoDataSourceButton.text")); // NOI18N + gotoDataSourceButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - openButtonActionPerformed(evt); + gotoDataSourceButtonActionPerformed(evt); } }); @@ -188,7 +210,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) - .addComponent(openButton) + .addComponent(gotoDataSourceButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(closeButton)) .addGroup(layout.createSequentialGroup() @@ -206,7 +228,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, openButton}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, gotoDataSourceButton}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -224,13 +246,14 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(opperatingSystemLabel) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(opperatingSystemLabel, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) - .addComponent(openButton)) + .addComponent(gotoDataSourceButton)) .addContainerGap()) ); }// //GEN-END:initComponents @@ -242,30 +265,46 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { */ void addCloseButtonAction(ActionListener action) { this.closeButton.addActionListener(action); - this.openButton.addActionListener(action); + //the gotoDataSourceButton should also close the dialog + this.gotoDataSourceButton.addActionListener(action); } + /** + * Select the data source with the specicied data source id. If no data + * source matches the dataSourceID it will select the first datasource. + * + * @param dataSourceID the ID of the datasource to select, null will cause + * the first datasource to be selected + */ void selectDataSource(Long dataSourceID) { if (dataSourceID != null) { for (int i = 0; i < dataSources.size(); i++) { if (dataSources.get(i).getId() == dataSourceID) { dataSourcesTable.setRowSelectionInterval(i, i); + //scroll down from top of table to where selected datasource is dataSourcesTable.scrollRectToVisible(new Rectangle(dataSourcesTable.getCellRect(i, 0, true))); return; } } - } + } + //if there are data sources in the list and none were found that matched the specied dataSourceID select the first one if (!dataSources.isEmpty()) { dataSourcesTable.setRowSelectionInterval(0, 0); } } - private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed + /** + * Performed when the Goto Data Source button is clicked, will cause the + * window to be closed and the data source which was selected to be + * navigated to in the tree. + */ + private void gotoDataSourceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gotoDataSourceButtonActionPerformed + //the dialog will be closed due to the action listener added in addCloseButtonAction DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); if (selectedDataSource != null) { new ViewContextAction("", selectedDataSource).actionPerformed(evt); } - }//GEN-LAST:event_openButtonActionPerformed + }//GEN-LAST:event_gotoDataSourceButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -275,15 +314,214 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private javax.swing.JLabel fileCountsLabel; private javax.swing.JScrollPane fileCountsScrollPane; private javax.swing.JTable fileCountsTable; + private javax.swing.JButton gotoDataSourceButton; private javax.swing.JLabel ingestJobsLabel; private javax.swing.JScrollPane ingestJobsScrollPane; private javax.swing.JTable ingestJobsTable; private javax.swing.JSeparator jSeparator1; - private javax.swing.JButton openButton; private javax.swing.JLabel opperatingSystemLabel; private javax.swing.JLabel opperatingSystemValueLabel; // End of variables declaration//GEN-END:variables + /** + * Table model for the Data source table, to display all data sources for + * the current case. + */ + @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", + "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", + "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", + "DataSourceSummaryPanel.DataSourceTableModel.results.header=Results", + "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) + private class DataSourceTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + private final List columnHeaders = new ArrayList<>(); + private final Map fileCountsMap; + private final Map artifactCountsMap; + private final Map tagCountsMap; + + /** + * Create a new DataSourceTableModel for the current case. + */ + DataSourceTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); + fileCountsMap = getCountsOfFiles(); + artifactCountsMap = getCountsOfArtifacts(); + tagCountsMap = getCountsOfTags(); + + } + + @Override + public int getRowCount() { + return dataSources.size(); + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DataSource currentDataSource = dataSources.get(rowIndex); + Long count; + switch (columnIndex) { + case 0: + return currentDataSource.getName(); + case 1: + return ""; + case 2: + //display 0 if no count is found + count = fileCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; + case 3: + //display 0 if no count is found + count = artifactCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; + case 4: + //display 0 if no count is found + count = tagCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; + default: + break; + } + return null; + } + + /** + * Get a map containing the number of files in each data source in the + * current case. + * + * @return Collection which maps datasource id to a count for the number + * of files in the datasource, will only contain entries for + * datasources which have at least 1 file + */ + private Map getCountsOfFiles() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countFilesQuery, callback); + return callback.getMapOfCounts(); + } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); + } + } + + /** + * Get a map containing the number of artifacts in each data source in + * the current case. + * + * @return Collection which maps datasource id to a count for the number + * of artifacts in the datasource, will only contain entries for + * datasources which have at least 1 artifact + */ + private Map getCountsOfArtifacts() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() + + " GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); + return callback.getMapOfCounts(); + } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); + } + } + + /** + * Get a map containing the number of tags which have been applied in + * each data source in the current case. Not necessarily the same as the + * number of items tagged, as an item can have any number of tags. + * + * @return Collection which maps datasource id to a count for the number + * of tags which have been applied in the datasource, will only + * contain entries for datasources which have at least 1 item + * tagged. + */ + private Map getCountsOfTags() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); + final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM content_tags as content_tags, tsk_files as tsk_files" + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); + Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); + DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); + final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); + //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query + artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); + return tagCountMap; + } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); + } + + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + /** + * Get the map of Data Source ID to counts of items found for a query + * which selects data_source_obj_id and count(*) with a group by + * data_source_obj_id clause. + */ + private class DataSourceCountsCallback implements CaseDbAccessQueryCallback { + + Map dataSourceObjIdCounts = new HashMap<>(); + + @Override + public void process(ResultSet rs) { + try { + while (rs.next()) { + try { + dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); + } catch (SQLException ex) { + System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); + } + } + } catch (SQLException ex) { + System.out.println("Failed to get next result" + ex.getMessage()); + } + } + + /** + * Get the processed results + * + * @return Collection which maps datasource id to a count for the + * number of items found with that datasource id, only + * contains entries for datasources with at least 1 item + * found. + */ + Map getMapOfCounts() { + return Collections.unmodifiableMap(dataSourceObjIdCounts); + } + + } + + } + + /** + * Table model for the Ingest Job table to display ingest jobs for the + * selected datasource. + */ @Messages({"DataSourceSummaryPanel.IngestJobTableModel.StartTime.header=Start Time", "DataSourceSummaryPanel.IngestJobTableModel.EndTime.header=End Time", "DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) @@ -293,6 +531,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private final List columnHeaders = new ArrayList<>(); + /** + * Create a new IngestJobTableModel + */ IngestJobTableModel() { columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_StartTime_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_EndTime_header()); @@ -336,6 +577,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } + /** + * Table model for the files table model to display counts of specific file + * types found in the currently selected data source. + */ @Messages({"DataSourceSummaryPanel.FilesTableModel.type.header=File Type", "DataSourceSummaryPanel.FilesTableModel.count.header=Count"}) private class FilesTableModel extends AbstractTableModel { @@ -344,6 +589,12 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private final DataSource currentDataSource; private final List columnHeaders = new ArrayList<>(); + /** + * Create a FilesTableModel for the speicified datasource. + * + * @param selectedDataSource the datasource which this filesTablemodel + * will represent + */ FilesTableModel(DataSource selectedDataSource) { columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header()); @@ -352,6 +603,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { @Override public int getRowCount() { + //should be kept equal to the number of types we are displaying in the tables return 5; } @@ -403,6 +655,17 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return null; } + /** + * Get the number of files in the case database for the current data + * source which have the specified mimetypes. + * + * @param setOfMimeTypes the set of mime types which we are finding the + * number of occurences of + * + * @return a Long value which represents the number of occurrences of + * the specified mime types in the current case for the + * specified data source, null if no count was retrieved + */ private Long getCountOfFiles(Set setOfMimeTypes) { if (currentDataSource != null) { try { @@ -414,7 +677,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { + " AND mime_type IN ('" + inClause + "')" + " AND name<>''"); } catch (TskCoreException | NoCurrentCaseException ex) { - + logger.log(Level.INFO, "Unable to get count of files for specified mime types", ex); + //unable to get count of files for the specified mimetypes cell will be displayed as empty } } return null; @@ -427,150 +691,4 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } - @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", - "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", - "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", - "DataSourceSummaryPanel.DataSourceTableModel.results.header=Results", - "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) - private class DataSourceTableModel extends AbstractTableModel { - - private static final long serialVersionUID = 1L; - - private final List columnHeaders = new ArrayList<>(); - private final Map fileCountsMap; - private final Map artifactCountsMap; - private final Map tagCountsMap; - - DataSourceTableModel() { - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); - fileCountsMap = getCountsOfFiles(); - artifactCountsMap = getCountsOfArtifacts(); - tagCountsMap = getCountsOfTags(); - - } - - @Override - public int getRowCount() { - return dataSources.size(); - } - - @Override - public int getColumnCount() { - return columnHeaders.size(); - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - DataSource currentDataSource = dataSources.get(rowIndex); - Long count; - switch (columnIndex) { - case 0: - return currentDataSource.getName(); - case 1: - return ""; - case 2: - count = fileCountsMap.get(currentDataSource.getId()); - return count == null ? 0 : count; - case 3: - count = artifactCountsMap.get(currentDataSource.getId()); - return count == null ? 0 : count; - case 4: - count = tagCountsMap.get(currentDataSource.getId()); - return count == null ? 0 : count; - default: - break; - } - return null; - } - - private Map getCountsOfFiles() { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - DataSourceCountsCallback callback = new DataSourceCountsCallback(); - final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() - + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countFilesQuery, callback); - return callback.getMapOfCounts(); - } catch (TskCoreException | NoCurrentCaseException ex) { - return Collections.emptyMap(); - } - } - - private Map getCountsOfArtifacts() { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - DataSourceCountsCallback callback = new DataSourceCountsCallback(); - final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() - + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); - return callback.getMapOfCounts(); - } catch (TskCoreException | NoCurrentCaseException ex) { - return Collections.emptyMap(); - } - } - - private Map getCountsOfTags() { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); - final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM content_tags as content_tags, tsk_files as tsk_files" - + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); - Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); - DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); - final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" - + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); - //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query - artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); - return tagCountMap; - } catch (TskCoreException | NoCurrentCaseException ex) { - return Collections.emptyMap(); - } - - } - - @Override - public String getColumnName(int column) { - return columnHeaders.get(column); - } - - private class DataSourceCountsCallback implements CaseDbAccessQueryCallback { - - Map dataSourceObjIdCounts = new HashMap<>(); - - @Override - public void process(ResultSet rs) { - try { - while (rs.next()) { - try { - dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); - } catch (SQLException ex) { - System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); - } - } - } catch (SQLException ex) { - System.out.println("Failed to get next result" + ex.getMessage()); - } - } - - Map getMapOfCounts() { - return Collections.unmodifiableMap(dataSourceObjIdCounts); - } - - } - - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java index 400af48209..96572fbf51 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java @@ -23,12 +23,12 @@ import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JDialog; import javax.swing.SwingUtilities; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; /** - * - * @author wschaefer + * ViewSummaryInformationAction action for opening a Data Source Summary Panel + * with the specified data source selected if it is present. */ public final class ViewSummaryInformationAction extends AbstractAction { @@ -36,14 +36,20 @@ public final class ViewSummaryInformationAction extends AbstractAction { private static Long selectDataSource; private static final long serialVersionUID = 1L; - @NbBundle.Messages({"ViewSummaryInformationAction.name.text=View Summary Information"}) + /** + * Create a ViewSummaryInformationAction for the selected datasource. + * + * @param selectedDataSource - the data source which is currently selected + * and will be selected initially when the + * DataSourceSummaryPanel opens. + */ + @Messages({"ViewSummaryInformationAction.name.text=View Summary Information"}) public ViewSummaryInformationAction(Long selectedDataSource) { super(Bundle.ViewSummaryInformationAction_name_text()); - this.setEnabled(true); selectDataSource = selectedDataSource; } - - @NbBundle.Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"}) + + @Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"}) @Override public void actionPerformed(ActionEvent actionEvent) { SwingUtilities.invokeLater(() -> { @@ -51,9 +57,11 @@ public final class ViewSummaryInformationAction extends AbstractAction { Frame mainWindow = WindowManager.getDefault().getMainWindow(); dataSourceSummaryDialog = new JDialog(mainWindow, title, true); DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); + //allow the buttons in DataSourceSummaryPanel to close this dialog dataSourceSummaryPanel.addCloseButtonAction((ActionEvent event) -> { dataSourceSummaryDialog.dispose(); }); + //select the specifed data source dataSourceSummaryPanel.selectDataSource(selectDataSource); dataSourceSummaryDialog.add(dataSourceSummaryPanel); dataSourceSummaryDialog.setResizable(true); From 72046156c831dcade654ede54dc806f285dbef3b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 16:01:52 -0500 Subject: [PATCH 9/9] 4568 add exception logging and disable goto datasource button when no datasource selected --- .../DataSourceSummaryPanel.form | 5 ++--- .../DataSourceSummaryPanel.java | 16 ++++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 16fa26c1a0..255af69ffa 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -68,9 +68,7 @@ - - - + @@ -174,6 +172,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 5f7315a566..6fc2ca56e5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -88,6 +88,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + gotoDataSourceButton.setEnabled(selectedDataSource != null); updateIngestJobs(selectedDataSource); filesTableModel = new FilesTableModel(selectedDataSource); fileCountsTable.setModel(filesTableModel); @@ -122,7 +123,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { } } catch (TskCoreException ignored) { //unable to get datasource for the OSInfo Object - //continue checking for OSInfo objects which we can get the desired information from + //continue checking for OSInfo objects to try and get get the desired information } } } @@ -193,6 +194,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(gotoDataSourceButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.gotoDataSourceButton.text")); // NOI18N + gotoDataSourceButton.setEnabled(false); gotoDataSourceButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { gotoDataSourceButtonActionPerformed(evt); @@ -248,8 +250,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(opperatingSystemLabel, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) @@ -412,6 +413,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { skCase.getCaseDbAccessManager().select(countFilesQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex); return Collections.emptyMap(); } } @@ -434,6 +436,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of artifacts for all datasources, providing empty results", ex); return Collections.emptyMap(); } } @@ -468,6 +471,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); return tagCountMap; } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of tags for all datasources, providing empty results", ex); return Collections.emptyMap(); } @@ -494,11 +498,11 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { try { dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); } catch (SQLException ex) { - System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); + logger.log(Level.WARNING, "Unable to get data_source_obj_id or count from result set", ex); } } } catch (SQLException ex) { - System.out.println("Failed to get next result" + ex.getMessage()); + logger.log(Level.WARNING, "Failed to get next result for counts by datasource", ex); } } @@ -677,7 +681,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { + " AND mime_type IN ('" + inClause + "')" + " AND name<>''"); } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.INFO, "Unable to get count of files for specified mime types", ex); + logger.log(Level.WARNING, "Unable to get count of files for specified mime types", ex); //unable to get count of files for the specified mimetypes cell will be displayed as empty } }