diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties index 3d0207ef87..c67ff8aa08 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties @@ -19,7 +19,6 @@ ResultsDialog.exitButton.text=Exit ResultsDialog.searchButton.text=Run another search FileSearchPanel.sortingPanel.border.title=Sorting FileSearchPanel.searchButton.text=Show -FileSearchPanel.fileTypeLabel.text=File Type: FileSearchPanel.addButton.text=Add FileSearchPanel.substringRadioButton.text=Substring FileSearchPanel.fullRadioButton.text=Full @@ -62,3 +61,6 @@ FileSearchPanel.includeRadioButton.text=Include FileSearchPanel.excludeRadioButton.text=Exclude FileSearchPanel.knownFilesCheckbox.toolTipText= FileSearchPanel.knownFilesCheckbox.text=Hide known files +GroupListPanel.groupKeyList.border.title=Groups +DiscoveryTopComponent.imagesButton.text=Images +DiscoveryTopComponent.videosButton.text=Videos diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED index 3cd2698d6b..b947682e5b 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED @@ -25,11 +25,15 @@ FileSearch.KeywordListGroupKey.noKeywords=None FileSearch.NoGroupingGroupKey.allFiles=All Files FileSearch.ObjectDetectedGroupKey.noSets=None FileSearchData.FileSize.OVER_100KB.displayName=100 KB - 1 MB +FileSearchData.FileSize.OVER_10GB.displayName=10 GB+ FileSearchData.FileSize.OVER_16KB.displayName=16 KB - 100 KB -FileSearchData.FileSize.OVER_1GB.displayName=1 GB+ +FileSearchData.FileSize.OVER_1GB_IMAGE.displayName=1 GB+ +FileSearchData.FileSize.OVER_1GB_VIDEO.displayName=1 - 5 GB FileSearchData.FileSize.OVER_1MB.displayName=1 - 50 MB FileSearchData.FileSize.OVER_200MB.displayName=200 MB - 1 GB FileSearchData.FileSize.OVER_50MB.displayName=50 - 200 MB +FileSearchData.FileSize.OVER_5GB.displayName=5 - 10 GB +FileSearchData.FileSize.UNDER_100KB.displayName=Under 100 KB FileSearchData.FileSize.UNDER_16KB.displayName=Under 16 KB FileSearchData.FileType.Audio.displayName=Audio FileSearchData.FileType.Documents.displayName=Documents @@ -116,8 +120,8 @@ FileSorter.SortingMethod.filename.displayName=By file name FileSorter.SortingMethod.filesize.displayName=By file size FileSorter.SortingMethod.filetype.displayName=By file type FileSorter.SortingMethod.frequency.displayName=By central repo frequency +FileSorter.SortingMethod.fullPath.displayName=By full path FileSorter.SortingMethod.keywordlist.displayName=By keyword list names -FileSorter.SortingMethod.parent.displayName=By parent path # {0} - numberOfInstances ImageThumbnailPanel.countLabel.text=Number of Instances: {0} ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. @@ -132,7 +136,6 @@ ResultsDialog.exitButton.text=Exit ResultsDialog.searchButton.text=Run another search FileSearchPanel.sortingPanel.border.title=Sorting FileSearchPanel.searchButton.text=Show -FileSearchPanel.fileTypeLabel.text=File Type: FileSearchPanel.addButton.text=Add FileSearchPanel.substringRadioButton.text=Substring FileSearchPanel.fullRadioButton.text=Full @@ -183,6 +186,9 @@ FileSearchPanel.includeRadioButton.text=Include FileSearchPanel.excludeRadioButton.text=Exclude FileSearchPanel.knownFilesCheckbox.toolTipText= FileSearchPanel.knownFilesCheckbox.text=Hide known files +GroupListPanel.groupKeyList.border.title=Groups +DiscoveryTopComponent.imagesButton.text=Images +DiscoveryTopComponent.videosButton.text=Videos ResultsPanel.viewFileInDir.name=View File in Directory SearchNode.getName.text=Search Result # {0} - numberOfInstances diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form index 3e1b796825..c3ad04da7d 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.form @@ -71,5 +71,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java index 40c7793498..4a4060410a 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryTopComponent.java @@ -18,7 +18,8 @@ */ package org.sleuthkit.autopsy.filequery; -import java.util.logging.Level; +import com.google.common.eventbus.Subscribe; +import java.awt.Color; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; @@ -27,14 +28,11 @@ import org.openide.windows.Mode; import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.corecomponents.DataContentPanel; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; import org.sleuthkit.datamodel.AbstractFile; /** @@ -48,7 +46,8 @@ public final class DiscoveryTopComponent extends TopComponent { private static final long serialVersionUID = 1L; private static final String PREFERRED_ID = "DiscoveryTopComponent"; // NON-NLS - private final static Logger logger = Logger.getLogger(DiscoveryTopComponent.class.getName()); + private static final Color SELECTED_COLOR = new Color(216, 230, 242); + private static final Color UNSELECTED_COLOR = new Color(240, 240, 240); private final FileSearchPanel fileSearchPanel; private final GroupListPanel groupListPanel; private final DataContentPanel dataContentPanel; @@ -60,19 +59,10 @@ public final class DiscoveryTopComponent extends TopComponent { @ThreadConfined(type = ThreadConfined.ThreadType.AWT) DiscoveryTopComponent() { initComponents(); - // Load the central repository database. - EamDb centralRepoDb = null; - if (EamDb.isEnabled()) { - try { - centralRepoDb = EamDb.getInstance(); - } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for File Discovery", ex); - } - } setName(Bundle.DiscoveryTopComponent_name()); - fileSearchPanel = new FileSearchPanel(Case.getCurrentCase().getSleuthkitCase(), centralRepoDb); + fileSearchPanel = new FileSearchPanel(); dataContentPanel = DataContentPanel.createInstance(); - resultsPanel = new ResultsPanel(centralRepoDb); + resultsPanel = new ResultsPanel(); groupListPanel = new GroupListPanel(); leftSplitPane.setLeftComponent(fileSearchPanel); leftSplitPane.setRightComponent(groupListPanel); @@ -110,27 +100,49 @@ public final class DiscoveryTopComponent extends TopComponent { mode.dockInto(tc); } tc.open(); + tc.updateSearchSettings(); } tc.toFront(); + } } + /** + * Get the current DiscoveryTopComponent if it is open. + * + * @return The open DiscoveryTopComponent or null if it has not been opened. + */ public static DiscoveryTopComponent getTopComponent() { return (DiscoveryTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID); } /** - * Reset the top component so it isn't displaying any results. + * Reset the top component so it isn't displaying any results. */ public void resetTopComponent() { resultsPanel.resetResultViewer(); groupListPanel.resetGroupList(); } + /** + * Update the search settings to a default state. + */ + private void updateSearchSettings() { + fileSearchPanel.resetPanel(); + imagesButton.setSelected(true); + imagesButton.setEnabled(false); + imagesButton.setBackground(SELECTED_COLOR); + videosButton.setSelected(false); + videosButton.setEnabled(true); + videosButton.setBackground(UNSELECTED_COLOR); + fileSearchPanel.setSelectedType(FileSearchData.FileType.IMAGE); + } + @Override public void componentOpened() { super.componentOpened(); WindowManager.getDefault().setTopComponentFloating(this, true); + DiscoveryEvents.getDiscoveryEventBus().register(this); DiscoveryEvents.getDiscoveryEventBus().register(resultsPanel); DiscoveryEvents.getDiscoveryEventBus().register(groupListPanel); DiscoveryEvents.getDiscoveryEventBus().register(fileSearchPanel); @@ -139,6 +151,7 @@ public final class DiscoveryTopComponent extends TopComponent { @Override protected void componentClosed() { fileSearchPanel.cancelSearch(); + DiscoveryEvents.getDiscoveryEventBus().unregister(this); DiscoveryEvents.getDiscoveryEventBus().unregister(fileSearchPanel); DiscoveryEvents.getDiscoveryEventBus().unregister(groupListPanel); DiscoveryEvents.getDiscoveryEventBus().unregister(resultsPanel); @@ -157,6 +170,10 @@ public final class DiscoveryTopComponent extends TopComponent { javax.swing.JSplitPane mainSplitPane = new javax.swing.JSplitPane(); leftSplitPane = new javax.swing.JSplitPane(); rightSplitPane = new javax.swing.JSplitPane(); + javax.swing.JPanel toolBarPanel = new javax.swing.JPanel(); + javax.swing.JToolBar toolBar = new javax.swing.JToolBar(); + imagesButton = new javax.swing.JButton(); + videosButton = new javax.swing.JButton(); setPreferredSize(new java.awt.Dimension(1100, 700)); setLayout(new java.awt.BorderLayout()); @@ -176,12 +193,132 @@ public final class DiscoveryTopComponent extends TopComponent { mainSplitPane.setRightComponent(rightSplitPane); add(mainSplitPane, java.awt.BorderLayout.CENTER); + + toolBar.setFloatable(false); + toolBar.setRollover(true); + + imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryTopComponent.class, "DiscoveryTopComponent.imagesButton.text")); // NOI18N + imagesButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N + imagesButton.setFocusable(false); + imagesButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + imagesButton.setMaximumSize(new java.awt.Dimension(90, 43)); + imagesButton.setMinimumSize(new java.awt.Dimension(90, 43)); + imagesButton.setPreferredSize(new java.awt.Dimension(90, 43)); + imagesButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + imagesButtonActionPerformed(evt); + } + }); + toolBar.add(imagesButton); + + videosButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/video-icon.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(videosButton, org.openide.util.NbBundle.getMessage(DiscoveryTopComponent.class, "DiscoveryTopComponent.videosButton.text")); // NOI18N + videosButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/video-icon.png"))); // NOI18N + videosButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/video-icon.png"))); // NOI18N + videosButton.setFocusable(false); + videosButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + videosButton.setMaximumSize(new java.awt.Dimension(90, 43)); + videosButton.setMinimumSize(new java.awt.Dimension(90, 43)); + videosButton.setPreferredSize(new java.awt.Dimension(90, 43)); + videosButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + videosButtonActionPerformed(evt); + } + }); + toolBar.add(videosButton); + + javax.swing.GroupLayout toolBarPanelLayout = new javax.swing.GroupLayout(toolBarPanel); + toolBarPanel.setLayout(toolBarPanelLayout); + toolBarPanelLayout.setHorizontalGroup( + toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(toolBarPanelLayout.createSequentialGroup() + .addContainerGap(459, Short.MAX_VALUE) + .addComponent(toolBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(459, Short.MAX_VALUE)) + ); + toolBarPanelLayout.setVerticalGroup( + toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, toolBarPanelLayout.createSequentialGroup() + .addComponent(toolBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + + add(toolBarPanel, java.awt.BorderLayout.PAGE_START); }// //GEN-END:initComponents + private void imagesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_imagesButtonActionPerformed + resetTopComponent(); + imagesButton.setSelected(true); + imagesButton.setEnabled(false); + imagesButton.setBackground(SELECTED_COLOR); + videosButton.setSelected(false); + videosButton.setEnabled(true); + videosButton.setBackground(UNSELECTED_COLOR); + fileSearchPanel.setSelectedType(FileSearchData.FileType.IMAGE); + }//GEN-LAST:event_imagesButtonActionPerformed + + private void videosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_videosButtonActionPerformed + resetTopComponent(); + imagesButton.setSelected(false); + imagesButton.setEnabled(true); + imagesButton.setBackground(UNSELECTED_COLOR); + videosButton.setSelected(true); + videosButton.setEnabled(false); + videosButton.setBackground(SELECTED_COLOR); + fileSearchPanel.setSelectedType(FileSearchData.FileType.VIDEO); + }//GEN-LAST:event_videosButtonActionPerformed + + /** + * Update the user interface in response to a search being cancelled. + * + * @param searchCancelledEvent The SearchCancelledEvent received. + */ + @Subscribe + void handleSearchCancelledEvent(DiscoveryEvents.SearchCancelledEvent searchCancelledEvent) { + SwingUtilities.invokeLater(() -> { + if (fileSearchPanel.getSelectedType() == FileType.VIDEO) { + imagesButton.setEnabled(true); + } else if (fileSearchPanel.getSelectedType() == FileType.IMAGE) { + videosButton.setEnabled(true); + } + }); + } + + /** + * Update the user interface in response to a search being completed. + * + * @param searchCompletedEvent The SearchCompletedEvent received. + */ + @Subscribe + void handleSearchCompletedEvent(DiscoveryEvents.SearchCompleteEvent searchCompletedEvent) { + SwingUtilities.invokeLater(() -> { + if (fileSearchPanel.getSelectedType() == FileType.VIDEO) { + imagesButton.setEnabled(true); + } else if (fileSearchPanel.getSelectedType() == FileType.IMAGE) { + videosButton.setEnabled(true); + } + }); + } + + /** + * Update the user interface in response to a search being started. + * + * @param searchStartedEvent The SearchStartedEvent received. + */ + @Subscribe + void handleSearchStartedEvent(DiscoveryEvents.SearchStartedEvent searchStartedEvent) { + SwingUtilities.invokeLater(() -> { + imagesButton.setEnabled(false); + videosButton.setEnabled(false); + }); + } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton imagesButton; private javax.swing.JSplitPane leftSplitPane; private javax.swing.JSplitPane rightSplitPane; + private javax.swing.JButton videosButton; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index dd5f62b8c3..aad5d901ce 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -62,6 +63,7 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * Main class to perform the file search. @@ -619,7 +621,12 @@ class FileSearch { private final FileSize fileSize; FileSizeGroupKey(ResultFile file) { - fileSize = FileSize.fromSize(file.getFirstInstance().getSize()); + if (file.getFileType() == FileType.VIDEO) { + fileSize = FileSize.fromVideoSize(file.getFirstInstance().getSize()); + } + else { + fileSize = FileSize.fromImageSize(file.getFirstInstance().getSize()); + } } @Override @@ -1028,30 +1035,35 @@ class FileSearch { @Override void addAttributeToResultFiles(List files, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException { - if (centralRepoDb == null) { - throw new FileSearchException("Central Repository is not enabled - can not add frequency data"); // NON-NLS - } - - // Set frequency in batches - Set hashesToLookUp = new HashSet<>(); - List currentFiles = new ArrayList<>(); - for (ResultFile file : files) { - if (file.getFrequency() == Frequency.UNKNOWN - && file.getFirstInstance().getMd5Hash() != null - && !file.getFirstInstance().getMd5Hash().isEmpty()) { - hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); - currentFiles.add(file); + for (ResultFile file : files) { + if (file.getFrequency() == Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { + file.setFrequency(Frequency.KNOWN); + } } + } else { + // Set frequency in batches + List currentFiles = new ArrayList<>(); + Set hashesToLookUp = new HashSet<>(); + for (ResultFile file : files) { + if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { + file.setFrequency(Frequency.KNOWN); + } + if (file.getFrequency() == Frequency.UNKNOWN + && file.getFirstInstance().getMd5Hash() != null + && !file.getFirstInstance().getMd5Hash().isEmpty()) { + hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); + currentFiles.add(file); + } + if (hashesToLookUp.size() >= BATCH_SIZE) { + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - - hashesToLookUp.clear(); - currentFiles.clear(); + hashesToLookUp.clear(); + currentFiles.clear(); + } } + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); } - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); } } @@ -1815,5 +1827,14 @@ class FileSearch { AttributeType getAttributeType() { return attributeType; } + + /** + * Get the list of enums that are valid for grouping images. + * + * @return enums that can be used to group images + */ + static List getOptionsForGrouping() { + return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java index b0cc38fc52..1859a45126 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchData.java @@ -53,7 +53,8 @@ class FileSearchData { COUNT_50(4, 50, Bundle.FileSearchData_Frequency_count_50_displayName()), COUNT_100(5, 100, Bundle.FileSearchData_Frequency_count_100_displayName()), COMMON(6, 0, Bundle.FileSearchData_Frequency_common_displayName()), - UNKNOWN(7, 0, Bundle.FileSearchData_Frequency_unknown_displayName()); + KNOWN(7, 0, "Known (NSRL)"), + UNKNOWN(8, 0, Bundle.FileSearchData_Frequency_unknown_displayName()); private final int ranking; private final String displayName; @@ -82,56 +83,82 @@ class FileSearchData { * @return the corresponding enum */ static Frequency fromCount(long count) { - if (count <= UNIQUE.maxOccur) { + if (count <= UNIQUE.getMaxOccur()) { return UNIQUE; - } else if (count <= RARE.maxOccur) { + } else if (count <= RARE.getMaxOccur()) { return RARE; - } else if (count <= COUNT_10.maxOccur) { + } else if (count <= COUNT_10.getMaxOccur()) { return COUNT_10; - } else if (count <= COUNT_20.maxOccur) { + } else if (count <= COUNT_20.getMaxOccur()) { return COUNT_20; - } else if (count <= COUNT_50.maxOccur) { + } else if (count <= COUNT_50.getMaxOccur()) { return COUNT_50; - } else if (count <= COUNT_100.maxOccur) { + } else if (count <= COUNT_100.getMaxOccur()) { return COUNT_100; } return COMMON; } /** - * Get the list of enums that are valid for filtering. + * Get the list of enums that are valid for filtering when a CR is + * enabled. * - * @return enums that can be used to filter + * @return enums that can be used to filter with a CR. */ - static List getOptionsForFiltering() { - return Arrays.asList(UNIQUE, RARE, COUNT_10, COUNT_20, COUNT_50, COUNT_100, COMMON); + static List getOptionsForFilteringWithCr() { + return Arrays.asList(UNIQUE, RARE, COUNT_10, COUNT_20, COUNT_50, COUNT_100, COMMON, KNOWN); + } + + /** + * Get the list of enums that are valid for filtering when no CR is + * enabled. + * + * @return enums that can be used to filter without a CR. + */ + static List getOptionsForFilteringWithoutCr() { + return Arrays.asList(KNOWN, UNKNOWN); } @Override public String toString() { return displayName; } + + /** + * @return the maxOccur + */ + int getMaxOccur() { + return maxOccur; + } } /** * Enum representing the file size */ @NbBundle.Messages({ - "FileSearchData.FileSize.OVER_1GB.displayName=1 GB+", + "FileSearchData.FileSize.OVER_10GB.displayName=10 GB+", + "FileSearchData.FileSize.OVER_5GB.displayName=5 - 10 GB", + "FileSearchData.FileSize.OVER_1GB_VIDEO.displayName=1 - 5 GB", + "FileSearchData.FileSize.OVER_1GB_IMAGE.displayName=1 GB+", "FileSearchData.FileSize.OVER_200MB.displayName=200 MB - 1 GB", "FileSearchData.FileSize.OVER_50MB.displayName=50 - 200 MB", "FileSearchData.FileSize.OVER_1MB.displayName=1 - 50 MB", "FileSearchData.FileSize.OVER_100KB.displayName=100 KB - 1 MB", + "FileSearchData.FileSize.UNDER_100KB.displayName=Under 100 KB", "FileSearchData.FileSize.OVER_16KB.displayName=16 KB - 100 KB", "FileSearchData.FileSize.UNDER_16KB.displayName=Under 16 KB",}) enum FileSize { - OVER_1GB(0, 1000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_OVER_1GB_displayName()), - OVER_200MB(1, 200 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_200MB_displayName()), - OVER_50MB(2, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_50MB_displayName()), - OVER_1MB(3, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_1MB_displayName()), - OVER_100KB(4, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_100KB_displayName()), - OVER_16KB(5, 16000, 100000, Bundle.FileSearchData_FileSize_OVER_16KB_displayName()), - UNDER_16KB(6, 0, 16000, Bundle.FileSearchData_FileSize_UNDER_16KB_displayName()); + OVER_10GB(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_OVER_10GB_displayName()), + OVER_5GB(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_5GB_displayName()), + OVER_1GB_VIDEO(2, 1000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_OVER_1GB_VIDEO_displayName()), + OVER_1GB_IMAGE(3, 1000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_OVER_1GB_IMAGE_displayName()), + OVER_200MB(4, 200 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_200MB_displayName()), + OVER_50MB(5, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_50MB_displayName()), + OVER_1MB(6, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_1MB_displayName()), + OVER_100KB(7, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_OVER_100KB_displayName()), + UNDER_100KB(8, 0, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_UNDER_100KB_displayName()), + OVER_16KB(9, 16000, 100000, Bundle.FileSearchData_FileSize_OVER_16KB_displayName()), + UNDER_16KB(10, 0, 16000, Bundle.FileSearchData_FileSize_UNDER_16KB_displayName()); private final int ranking; // Must be unique for each value private final long minBytes; // Note that the size must be strictly greater than this to match @@ -151,31 +178,59 @@ class FileSearchData { } /** - * Get the enum corresponding to the given file size. The file size must - * be strictly greater than minBytes. + * Get the enum corresponding to the given file size for image files. + * The file size must be strictly greater than minBytes. * * @param size the file size * * @return the enum whose range contains the file size */ - static FileSize fromSize(long size) { - if (size > OVER_1GB.minBytes) { - return OVER_1GB; - } else if (size > OVER_200MB.minBytes) { + static FileSize fromImageSize(long size) { + if (size > OVER_1GB_IMAGE.getMinBytes()) { + return OVER_1GB_IMAGE; + } else if (size > OVER_200MB.getMinBytes()) { return OVER_200MB; - } else if (size > OVER_50MB.minBytes) { + } else if (size > OVER_50MB.getMinBytes()) { return OVER_50MB; - } else if (size > OVER_1MB.minBytes) { + } else if (size > OVER_1MB.getMinBytes()) { return OVER_1MB; - } else if (size > OVER_100KB.minBytes) { + } else if (size > OVER_100KB.getMinBytes()) { return OVER_100KB; - } else if (size > OVER_16KB.minBytes) { + } else if (size > OVER_16KB.getMinBytes()) { return OVER_16KB; } else { return UNDER_16KB; } } + /** + * Get the enum corresponding to the given file size for video files. + * The file size must be strictly greater than minBytes. + * + * @param size the file size + * + * @return the enum whose range contains the file size + */ + static FileSize fromVideoSize(long size) { + if (size > OVER_10GB.getMinBytes()) { + return OVER_10GB; + } else if (size > OVER_5GB.getMinBytes()) { + return OVER_5GB; + } else if (size > OVER_1GB_VIDEO.getMinBytes()) { + return OVER_1GB_VIDEO; + } else if (size > OVER_200MB.getMinBytes()) { + return OVER_200MB; + } else if (size > OVER_50MB.getMinBytes()) { + return OVER_50MB; + } else if (size > OVER_1MB.getMinBytes()) { + return OVER_1MB; + } else if (size > OVER_100KB.getMinBytes()) { + return OVER_100KB; + } else { + return UNDER_100KB; + } + } + /** * Get the upper limit of the range. * @@ -207,6 +262,24 @@ class FileSearchData { public String toString() { return displayName; } + + /** + * Get the list of enums that are valid for image sizes. + * + * @return enums that can be used to filter images by size. + */ + static List getOptionsForImages() { + return Arrays.asList(OVER_1GB_IMAGE, OVER_200MB, OVER_50MB, OVER_1MB, OVER_100KB, OVER_16KB, UNDER_16KB); + } + + /** + * Get the list of enums that are valid for video sizes. + * + * @return enums that can be used to filter videos by size. + */ + static List getOptionsForVideos() { + return Arrays.asList(OVER_10GB, OVER_5GB, OVER_1GB_VIDEO, OVER_200MB, OVER_50MB, OVER_1MB, OVER_100KB, UNDER_100KB); + } } /** @@ -273,7 +346,7 @@ class FileSearchData { */ static FileType fromMIMEtype(String mimeType) { for (FileType type : FileType.values()) { - if (type.mediaTypes.contains(mimeType)) { + if (type.getMediaTypes().contains(mimeType)) { return type; } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchDialog.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchDialog.java index 37e7912c4f..186111cef0 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchDialog.java @@ -185,7 +185,7 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe } else { int count = 0; DefaultListModel frequencyListModel = (DefaultListModel)freqList.getModel(); - for (Frequency freq : Frequency.getOptionsForFiltering()) { + for (Frequency freq : Frequency.getOptionsForFilteringWithCr()) { frequencyListModel.add(count, freq); } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java index 66676aa669..920f7983c1 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchFiltering.java @@ -262,15 +262,15 @@ class FileSearchFiltering { // TODO - these should really be prepared statements if (isIncluded()) { if (isFullPath()) { - return "parent_path=\'" + searchStr + "\'"; // NON-NLS + return "parent_path=\'" + getSearchStr() + "\'"; // NON-NLS } else { - return "parent_path LIKE \'%" + searchStr + "%\'"; // NON-NLS + return "parent_path LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS } } else { if (isFullPath()) { - return "parent_path!=\'" + searchStr + "\'"; // NON-NLS + return "parent_path!=\'" + getSearchStr() + "\'"; // NON-NLS } else { - return "parent_path NOT LIKE \'%" + searchStr + "%\'"; // NON-NLS + return "parent_path NOT LIKE \'%" + getSearchStr() + "%\'"; // NON-NLS } } } @@ -282,7 +282,7 @@ class FileSearchFiltering { "FileSearchFiltering.ParentSearchTerm.excludeString= (exclude)",}) @Override public String toString() { - String returnString = searchStr; + String returnString = getSearchStr(); if (isFullPath()) { returnString += Bundle.FileSearchFiltering_ParentSearchTerm_fullString(); } else { @@ -309,6 +309,13 @@ class FileSearchFiltering { boolean isIncluded() { return included; } + + /** + * @return the searchStr + */ + String getSearchStr() { + return searchStr; + } } /** @@ -371,9 +378,9 @@ class FileSearchFiltering { desc += Bundle.FileSearchFiltering_ParentFilter_or(); } if (searchTerm.isFullPath()) { - desc += searchTerm.searchStr + Bundle.FileSearchFiltering_ParentFilter_exact(); + desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_exact(); } else { - desc += searchTerm.searchStr + Bundle.FileSearchFiltering_ParentFilter_substring(); + desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_substring(); } } desc = Bundle.FileSearchFiltering_ParentFilter_desc(desc); @@ -559,10 +566,6 @@ class FileSearchFiltering { List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException { - if (centralRepoDb == null) { - throw new FileSearchException("Can not run Frequency filter with null Central Repository DB"); // NON-NLS - } - // We have to have run some kind of SQL filter before getting to this point, // and should have checked afterward to see if the results were empty. if (currentResults.isEmpty()) { diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form index 5f148e7227..ccfb608cd6 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.form @@ -3,6 +3,10 @@
+ + + + @@ -36,50 +40,45 @@ - - + - - - - - - - + + - - + + + + + + + + - + - - - - - - + + + - - - + + - - + @@ -161,7 +160,7 @@ - + @@ -176,7 +175,7 @@ - + @@ -219,7 +218,7 @@ - + @@ -235,7 +234,7 @@ - + @@ -245,7 +244,7 @@ - + @@ -270,7 +269,7 @@ - + @@ -295,7 +294,7 @@ - + @@ -357,7 +356,7 @@ - + @@ -385,7 +384,7 @@ - + @@ -395,7 +394,7 @@ - + @@ -429,7 +428,7 @@ - + @@ -439,7 +438,7 @@ - + @@ -470,7 +469,7 @@ - + @@ -485,7 +484,7 @@ - + @@ -500,7 +499,7 @@ - + @@ -515,7 +514,7 @@ - + @@ -527,7 +526,7 @@ - + @@ -539,7 +538,7 @@ - + @@ -549,7 +548,7 @@ - + @@ -575,7 +574,7 @@ - + @@ -601,7 +600,7 @@ - + @@ -627,7 +626,7 @@ - + @@ -660,7 +659,7 @@ - + @@ -676,7 +675,7 @@ - + @@ -691,7 +690,7 @@ - + @@ -699,13 +698,6 @@ - - - - - - - @@ -749,8 +741,8 @@ - - + + @@ -860,16 +852,6 @@ - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java index c2875ca0aa..0346916d1c 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchPanel.java @@ -22,14 +22,11 @@ import com.google.common.eventbus.Subscribe; import java.awt.Cursor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; -import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; @@ -38,7 +35,9 @@ import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.filequery.FileSearch.GroupingAttributeType; import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; @@ -50,7 +49,6 @@ import org.sleuthkit.autopsy.filequery.FileSorter.SortingMethod; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TagName; @@ -58,35 +56,481 @@ import org.sleuthkit.datamodel.TagName; * Dialog to allow the user to choose filtering and grouping options. */ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener { - + private static final long serialVersionUID = 1L; + private static final String[] DEFAULT_IGNORED_PATHS = {"Windows", "Program Files"}; private final static Logger logger = Logger.getLogger(FileSearchPanel.class.getName()); - + private FileType fileType = FileType.IMAGE; private DefaultListModel parentListModel; - private final SleuthkitCase caseDb; - private final EamDb centralRepoDb; private SearchWorker searchWorker = null; /** * Creates new form FileSearchDialog */ @NbBundle.Messages({"FileSearchPanel.dialogTitle.text=Test file search"}) - FileSearchPanel(SleuthkitCase caseDb, EamDb centralRepoDb) { - this.caseDb = caseDb; - this.centralRepoDb = centralRepoDb; + FileSearchPanel() { initComponents(); - customizeComponents(); + parentListModel = (DefaultListModel) parentList.getModel(); + for (String ignorePath : DEFAULT_IGNORED_PATHS) { + parentListModel.add(parentListModel.size(), new ParentSearchTerm(ignorePath, false, false)); + } } /** - * Set up all the UI components + * Setup the data source filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. */ - private void customizeComponents() { - + private void dataSourceFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + dataSourceCheckbox.setVisible(visible); + dataSourceScrollPane.setVisible(visible); + dataSourceList.setVisible(visible); + dataSourceCheckbox.setEnabled(enabled); + dataSourceCheckbox.setSelected(selected); + if (dataSourceCheckbox.isEnabled() && dataSourceCheckbox.isSelected()) { + dataSourceScrollPane.setEnabled(true); + dataSourceList.setEnabled(true); + if (indicesSelected != null) { + dataSourceList.setSelectedIndices(indicesSelected); + } + } else { + dataSourceScrollPane.setEnabled(false); + dataSourceList.setEnabled(false); + } + } + + /** + * Setup the file size filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void sizeFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + sizeCheckbox.setVisible(visible); + sizeScrollPane.setVisible(visible); + sizeList.setVisible(visible); + sizeCheckbox.setEnabled(enabled); + sizeCheckbox.setSelected(selected); + if (sizeCheckbox.isEnabled() && sizeCheckbox.isSelected()) { + sizeScrollPane.setEnabled(true); + sizeList.setEnabled(true); + if (indicesSelected != null) { + sizeList.setSelectedIndices(indicesSelected); + } + } else { + sizeScrollPane.setEnabled(false); + sizeList.setEnabled(false); + } + } + + /** + * Setup the central repository frequency filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void crFrequencyFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + crFrequencyCheckbox.setVisible(visible); + crFrequencyScrollPane.setVisible(visible); + crFrequencyList.setVisible(visible); + crFrequencyCheckbox.setEnabled(enabled); + crFrequencyCheckbox.setSelected(selected); + if (crFrequencyCheckbox.isEnabled() && crFrequencyCheckbox.isSelected()) { + crFrequencyScrollPane.setEnabled(true); + crFrequencyList.setEnabled(true); + if (indicesSelected != null) { + crFrequencyList.setSelectedIndices(indicesSelected); + } + } else { + crFrequencyScrollPane.setEnabled(false); + crFrequencyList.setEnabled(false); + } + } + + /** + * Setup the objects filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void objectsFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + objectsCheckbox.setVisible(visible); + objectsScrollPane.setVisible(visible); + objectsList.setVisible(visible); + objectsCheckbox.setEnabled(enabled); + objectsCheckbox.setSelected(selected); + if (objectsCheckbox.isEnabled() && objectsCheckbox.isSelected()) { + objectsScrollPane.setEnabled(true); + objectsList.setEnabled(true); + if (indicesSelected != null) { + objectsList.setSelectedIndices(indicesSelected); + } + } else { + objectsScrollPane.setEnabled(false); + objectsList.setEnabled(false); + } + } + + /** + * Setup the hash set filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void hashSetFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + hashSetCheckbox.setVisible(visible); + hashSetScrollPane.setVisible(visible); + hashSetList.setVisible(visible); + hashSetCheckbox.setEnabled(enabled); + hashSetCheckbox.setSelected(selected); + if (hashSetCheckbox.isEnabled() && hashSetCheckbox.isSelected()) { + hashSetScrollPane.setEnabled(true); + hashSetList.setEnabled(true); + if (indicesSelected != null) { + hashSetList.setSelectedIndices(indicesSelected); + } + } else { + hashSetScrollPane.setEnabled(false); + hashSetList.setEnabled(false); + } + } + + /** + * Setup the interesting items filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void interestingItemsFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + interestingItemsCheckbox.setVisible(visible); + interestingItemsScrollPane.setVisible(visible); + interestingItemsList.setVisible(visible); + interestingItemsCheckbox.setEnabled(enabled); + interestingItemsCheckbox.setSelected(selected); + if (interestingItemsCheckbox.isEnabled() && interestingItemsCheckbox.isSelected()) { + interestingItemsScrollPane.setEnabled(true); + interestingItemsList.setEnabled(true); + if (indicesSelected != null) { + interestingItemsList.setSelectedIndices(indicesSelected); + } + } else { + interestingItemsScrollPane.setEnabled(false); + interestingItemsList.setEnabled(false); + } + } + + /** + * Setup the score filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void scoreFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + scoreCheckbox.setVisible(visible); + scoreScrollPane.setVisible(visible); + scoreList.setVisible(visible); + scoreCheckbox.setEnabled(enabled); + scoreCheckbox.setSelected(selected); + if (scoreCheckbox.isEnabled() && scoreCheckbox.isSelected()) { + scoreScrollPane.setEnabled(true); + scoreList.setEnabled(true); + if (indicesSelected != null) { + scoreList.setSelectedIndices(indicesSelected); + } + } else { + scoreScrollPane.setEnabled(false); + scoreList.setEnabled(false); + } + } + + /** + * Setup the parent path filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void parentFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + parentCheckbox.setVisible(visible); + parentScrollPane.setVisible(visible); + parentList.setVisible(visible); + parentCheckbox.setEnabled(enabled); + parentCheckbox.setSelected(selected); + if (parentCheckbox.isEnabled() && parentCheckbox.isSelected()) { + parentScrollPane.setEnabled(true); + includeRadioButton.setEnabled(true); + excludeRadioButton.setEnabled(true); + fullRadioButton.setEnabled(true); + substringRadioButton.setEnabled(true); + addButton.setEnabled(true); + deleteButton.setEnabled(!parentListModel.isEmpty()); + parentList.setEnabled(true); + if (indicesSelected != null) { + parentList.setSelectedIndices(indicesSelected); + } + } else { + parentScrollPane.setEnabled(false); + parentList.setEnabled(false); + includeRadioButton.setEnabled(false); + excludeRadioButton.setEnabled(false); + fullRadioButton.setEnabled(false); + substringRadioButton.setEnabled(false); + addButton.setEnabled(false); + deleteButton.setEnabled(false); + + } + } + + /** + * Setup the tags filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void tagsFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + tagsCheckbox.setVisible(visible); + tagsScrollPane.setVisible(visible); + tagsList.setVisible(visible); + tagsCheckbox.setEnabled(enabled); + tagsCheckbox.setSelected(selected); + if (tagsCheckbox.isEnabled() && tagsCheckbox.isSelected()) { + tagsScrollPane.setEnabled(true); + tagsList.setEnabled(true); + if (indicesSelected != null) { + tagsList.setSelectedIndices(indicesSelected); + } + } else { + tagsScrollPane.setEnabled(false); + tagsList.setEnabled(false); + } + } + + /** + * Setup the keyword filter settings. + * + * @param visible Boolean indicating if the filter should be + * visible. + * @param enabled Boolean indicating if the filter should be + * enabled. + * @param selected Boolean indicating if the filter should be + * selected. + * @param indicesSelected Array of integers indicating which list items are + * selected, null to indicate leaving selected items + * unchanged. + */ + private void keywordFilterSettings(boolean visible, boolean enabled, boolean selected, int[] indicesSelected) { + keywordCheckbox.setVisible(visible); + keywordScrollPane.setVisible(visible); + keywordList.setVisible(visible); + keywordCheckbox.setEnabled(enabled); + keywordCheckbox.setSelected(selected); + if (keywordCheckbox.isEnabled() && keywordCheckbox.isSelected()) { + keywordScrollPane.setEnabled(true); + keywordList.setEnabled(true); + if (indicesSelected != null) { + keywordList.setSelectedIndices(indicesSelected); + } + } else { + keywordScrollPane.setEnabled(false); + keywordList.setEnabled(false); + } + } + + /** + * Setup the exif filter settings. + * + * @param visible Boolean indicating if the filter should be visible. + * @param enabled Boolean indicating if the filter should be enabled. + * @param selected Boolean indicating if the filter should be selected. + */ + private void exifFilterSettings(boolean visible, boolean enabled, boolean selected) { + exifCheckbox.setVisible(visible); + exifCheckbox.setEnabled(enabled); + exifCheckbox.setSelected(selected); + } + + /** + * Setup the known status filter settings. + * + * @param visible Boolean indicating if the filter should be visible. + * @param enabled Boolean indicating if the filter should be enabled. + * @param selected Boolean indicating if the filter should be selected. + */ + private void knownFilesFilterSettings(boolean visible, boolean enabled, boolean selected) { + knownFilesCheckbox.setVisible(visible); + knownFilesCheckbox.setEnabled(enabled); + knownFilesCheckbox.setSelected(selected); + } + + /** + * Setup the notable filter settings. + * + * @param visible Boolean indicating if the filter should be visible. + * @param enabled Boolean indicating if the filter should be enabled. + * @param selected Boolean indicating if the filter should be selected. + */ + private void notableFilterSettings(boolean visible, boolean enabled, boolean selected) { + notableCheckbox.setVisible(visible); + notableCheckbox.setEnabled(enabled); + notableCheckbox.setSelected(selected); + } + + /** + * Set the UI elements available to be the set of UI elements available when + * an Image search is being performed. + * + * @param enabled Boolean indicating if the filters present for images + * should be enabled. + * @param resetSelected Boolean indicating if selection of the filters + * present for images should be reset to their default + * status. + */ + private void imagesSelected(boolean enabled, boolean resetSelected) { + dataSourceFilterSettings(true, enabled, !resetSelected && dataSourceCheckbox.isSelected(), null); + int[] selectedSizeIndices = {1, 2, 3, 4, 5, 6}; + sizeFilterSettings(true, enabled, resetSelected || sizeCheckbox.isSelected(), resetSelected == true ? selectedSizeIndices : null); + int[] selectedFrequencyIndices; + if (!EamDb.isEnabled()) { + selectedFrequencyIndices = new int[]{0}; + } else { + selectedFrequencyIndices = new int[]{1, 2, 3, 4, 5, 6, 7}; + } + crFrequencyFilterSettings(true, enabled, resetSelected || crFrequencyCheckbox.isSelected(), resetSelected == true ? selectedFrequencyIndices : null); + exifFilterSettings(true, enabled, !resetSelected && exifCheckbox.isSelected()); + objectsFilterSettings(true, enabled, !resetSelected && objectsCheckbox.isSelected(), null); + hashSetFilterSettings(true, enabled, !resetSelected && hashSetCheckbox.isSelected(), null); + interestingItemsFilterSettings(true, enabled, !resetSelected && interestingItemsCheckbox.isSelected(), null); + parentFilterSettings(true, true, false, null); + scoreFilterSettings(false, false, false, null); + tagsFilterSettings(false, false, false, null); + keywordFilterSettings(false, false, false, null); + knownFilesFilterSettings(false, false, false); + notableFilterSettings(false, false, false); + } + + /** + * Set the UI elements available to be the set of UI elements available when + * a Video search is being performed. + * + * @param enabled Boolean indicating if the filters present for videos + * should be enabled. + * @param resetSelected Boolean indicating if selection of the filters + * present for videos should be reset to their default + * status. + */ + private void videosSelected(boolean enabled, boolean resetSelected) { + dataSourceFilterSettings(true, enabled, !resetSelected && dataSourceCheckbox.isSelected(), null); + sizeFilterSettings(true, enabled, !resetSelected && sizeCheckbox.isSelected(), null); + int[] selectedFrequencyIndices; + if (!EamDb.isEnabled()) { + selectedFrequencyIndices = new int[]{0}; + } else { + selectedFrequencyIndices = new int[]{1, 2, 3, 4, 5, 6, 7}; + } + crFrequencyFilterSettings(true, enabled, resetSelected || crFrequencyCheckbox.isSelected(), resetSelected == true ? selectedFrequencyIndices : null); + exifFilterSettings(true, enabled, !resetSelected && exifCheckbox.isSelected()); + objectsFilterSettings(true, enabled, !resetSelected && objectsCheckbox.isSelected(), null); + hashSetFilterSettings(true, enabled, !resetSelected && hashSetCheckbox.isSelected(), null); + interestingItemsFilterSettings(true, enabled, !resetSelected && interestingItemsCheckbox.isSelected(), null); + parentFilterSettings(true, true, false, null); + scoreFilterSettings(false, false, false, null); + tagsFilterSettings(false, false, false, null); + keywordFilterSettings(false, false, false, null); + knownFilesFilterSettings(false, false, false); + notableFilterSettings(false, false, false); + } + + /** + * Set the type of search to perform. + * + * @param type The type of File to be found by the search. + */ + void setSelectedType(FileType type) { + fileType = type; + setUpSizeFilter(); + if (fileType == FileType.IMAGE) { + imagesSelected(true, true); + } else if (fileType == FileType.VIDEO) { + videosSelected(true, true); + } + validateFields(); + } + + FileType getSelectedType(){ + return fileType; + } + + /** + * Reset the panel to its initial configuration. + */ + void resetPanel() { + searchButton.setEnabled(false); // Set up the filters - setUpFileTypeFilter(); setUpDataSourceFilter(); setUpFrequencyFilter(); setUpSizeFilter(); @@ -98,24 +542,27 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener setUpObjectFilter(); setUpScoreFilter(); + groupByCombobox.removeAllItems(); // Set up the grouping attributes - for (FileSearch.GroupingAttributeType type : FileSearch.GroupingAttributeType.values()) { + for (FileSearch.GroupingAttributeType type : FileSearch.GroupingAttributeType.getOptionsForGrouping()) { if (type != GroupingAttributeType.FREQUENCY || EamDb.isEnabled()) { groupByCombobox.addItem(type); } } - + orderByCombobox.removeAllItems(); // Set up the file order list - for (FileSorter.SortingMethod method : FileSorter.SortingMethod.values()) { + for (FileSorter.SortingMethod method : FileSorter.SortingMethod.getOptionsForOrdering()) { if (method != SortingMethod.BY_FREQUENCY || EamDb.isEnabled()) { orderByCombobox.addItem(method); } } + setSelectedType(FileType.IMAGE); validateFields(); } /** - * Add listeners to the checkbox/list set. Either can be null. + * Add listeners to the checkbox/list set if listeners have not already been + * added. Either can be null. * * @param checkBox * @param list @@ -128,28 +575,14 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent evt) { - validateFields(); + if (!evt.getValueIsAdjusting()) { + validateFields(); + } } }); } } - /** - * Initialize the file type filter - */ - private void setUpFileTypeFilter() { - DefaultComboBoxModel fileTypeComboBoxModel = (DefaultComboBoxModel) fileTypeComboBox.getModel(); - for (FileType type : FileType.getOptionsForFiltering()) { - fileTypeComboBoxModel.addElement(type); - } - fileTypeComboBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - validateFields(); - } - }); - } - /** * Initialize the data source filter */ @@ -157,7 +590,8 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener int count = 0; try { DefaultListModel dsListModel = (DefaultListModel) dataSourceList.getModel(); - for (DataSource ds : caseDb.getDataSources()) { + dsListModel.removeAllElements(); + for (DataSource ds : Case.getCurrentCase().getSleuthkitCase().getDataSources()) { dsListModel.add(count, new DataSourceItem(ds)); } } catch (TskCoreException ex) { @@ -172,13 +606,16 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * Initialize the frequency filter */ private void setUpFrequencyFilter() { - if (centralRepoDb == null) { - crFrequencyList.setEnabled(false); - crFrequencyCheckbox.setEnabled(false); + int count = 0; + DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); + frequencyListModel.removeAllElements(); + if (!EamDb.isEnabled()) { + for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { + frequencyListModel.add(count, freq); + } + } else { - int count = 0; - DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); - for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFiltering()) { + for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithCr()) { frequencyListModel.add(count, freq); } } @@ -191,8 +628,27 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener private void setUpSizeFilter() { int count = 0; DefaultListModel sizeListModel = (DefaultListModel) sizeList.getModel(); - for (FileSearchData.FileSize size : FileSearchData.FileSize.values()) { - sizeListModel.add(count, size); + sizeListModel.removeAllElements(); + if (null == fileType) { + for (FileSearchData.FileSize size : FileSearchData.FileSize.values()) { + sizeListModel.add(count, size); + } + } else { + List sizes; + switch (fileType) { + case VIDEO: + sizes = FileSearchData.FileSize.getOptionsForVideos(); + break; + case IMAGE: + sizes = FileSearchData.FileSize.getOptionsForImages(); + break; + default: + sizes = new ArrayList<>(); + break; + } + for (FileSearchData.FileSize size : sizes) { + sizeListModel.add(count, size); + } } addListeners(sizeCheckbox, sizeList); } @@ -204,7 +660,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener int count = 0; try { DefaultListModel kwListModel = (DefaultListModel) keywordList.getModel(); - + kwListModel.removeAllElements(); List setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME); for (String name : setNames) { @@ -225,7 +681,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener int count = 0; try { DefaultListModel hashListModel = (DefaultListModel) hashSetList.getModel(); - + hashListModel.removeAllElements(); List setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME); for (String name : setNames) { @@ -247,7 +703,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener int count = 0; try { DefaultListModel intListModel = (DefaultListModel) interestingItemsList.getModel(); - + intListModel.removeAllElements(); List setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME); for (String name : setNames) { @@ -269,8 +725,8 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener int count = 0; try { DefaultListModel tagsListModel = (DefaultListModel) tagsList.getModel(); - - List tagNames = caseDb.getTagNamesInUse(); + tagsListModel.removeAllElements(); + List tagNames = Case.getCurrentCase().getSleuthkitCase().getTagNamesInUse(); for (TagName name : tagNames) { tagsListModel.add(count, name); count++; @@ -288,9 +744,9 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * TagsListCellRenderer */ private class TagsListCellRenderer extends DefaultListCellRenderer { - + private static final long serialVersionUID = 1L; - + @Override public java.awt.Component getListCellRendererComponent( JList list, @@ -314,7 +770,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener int count = 0; try { DefaultListModel objListModel = (DefaultListModel) objectsList.getModel(); - + objListModel.removeAllElements(); List setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION); for (String name : setNames) { objListModel.add(count, name); @@ -332,9 +788,10 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * Initialize the score filter */ private void setUpScoreFilter() { - + int count = 0; DefaultListModel scoreListModel = (DefaultListModel) scoreList.getModel(); + scoreListModel.removeAllElements(); for (Score score : Score.getOptionsForFiltering()) { scoreListModel.add(count, score); } @@ -354,7 +811,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * @throws TskCoreException */ private List getSetNames(BlackboardArtifact.ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE setNameAttribute) throws TskCoreException { - List arts = caseDb.getBlackboardArtifacts(artifactType); + List arts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(artifactType); List setNames = new ArrayList<>(); for (BlackboardArtifact art : arts) { for (BlackboardAttribute attr : art.getAttributes()) { @@ -374,8 +831,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * Initialize the parent path filter */ private void setUpParentPathFilter() { - parentPathButtonGroup.add(fullRadioButton); - parentPathButtonGroup.add(substringRadioButton); fullRadioButton.setSelected(true); includeRadioButton.setSelected(true); parentListModel = (DefaultListModel) parentList.getModel(); @@ -389,65 +844,61 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener */ List getFilters() { List filters = new ArrayList<>(); - - // There will always be a file type selected - filters.add(new FileSearchFiltering.FileTypeFilter(fileTypeComboBox.getItemAt(fileTypeComboBox.getSelectedIndex()))); - + filters.add(new FileSearchFiltering.FileTypeFilter(fileType)); if (parentCheckbox.isSelected()) { // For the parent paths, everything in the box is used (not just the selected entries) filters.add(new FileSearchFiltering.ParentFilter(getParentPaths())); } - + if (dataSourceCheckbox.isSelected()) { List dataSources = dataSourceList.getSelectedValuesList().stream().map(t -> t.getDataSource()).collect(Collectors.toList()); filters.add(new FileSearchFiltering.DataSourceFilter(dataSources)); } - + if (crFrequencyCheckbox.isSelected()) { filters.add(new FileSearchFiltering.FrequencyFilter(crFrequencyList.getSelectedValuesList())); } - + if (sizeCheckbox.isSelected()) { filters.add(new FileSearchFiltering.SizeFilter(sizeList.getSelectedValuesList())); } - + if (keywordCheckbox.isSelected()) { filters.add(new FileSearchFiltering.KeywordListFilter(keywordList.getSelectedValuesList())); } - + if (hashSetCheckbox.isSelected()) { filters.add(new FileSearchFiltering.HashSetFilter(hashSetList.getSelectedValuesList())); } - + if (interestingItemsCheckbox.isSelected()) { filters.add(new FileSearchFiltering.InterestingFileSetFilter(interestingItemsList.getSelectedValuesList())); } - + if (objectsCheckbox.isSelected()) { filters.add(new FileSearchFiltering.ObjectDetectionFilter(objectsList.getSelectedValuesList())); } - + if (tagsCheckbox.isSelected()) { filters.add(new FileSearchFiltering.TagsFilter(tagsList.getSelectedValuesList())); } - + if (exifCheckbox.isSelected()) { filters.add(new FileSearchFiltering.ExifFilter()); } - + if (notableCheckbox.isSelected()) { filters.add(new FileSearchFiltering.NotableFilter()); } - - - if (knownFilesCheckbox.isSelected()){ + + if (knownFilesCheckbox.isSelected()) { filters.add(new FileSearchFiltering.KnownFilter()); } - + if (scoreCheckbox.isSelected()) { filters.add(new FileSearchFiltering.ScoreFilter(scoreList.getSelectedValuesList())); } - + return filters; } @@ -494,7 +945,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener FileSorter.SortingMethod getFileSortingMethod() { return (FileSorter.SortingMethod) orderByCombobox.getSelectedItem(); } - + @Override public void actionPerformed(ActionEvent e) { validateFields(); @@ -505,17 +956,17 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * name */ private class DataSourceItem { - + private final DataSource ds; - + DataSourceItem(DataSource ds) { this.ds = ds; } - + DataSource getDataSource() { return ds; } - + @Override public String toString() { return ds.getName() + " (ID: " + ds.getId() + ")"; @@ -527,8 +978,8 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener * use bundle messages. */ private void validateFields() { - // There must be at least one file type selected - if (fileTypeComboBox.getSelectedIndex() < 0) { + // There will be a file type selected. + if (fileType == null) { setInvalid("At least one file type must be selected"); return; } @@ -555,27 +1006,27 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener setInvalid("At least one parent path must be entered"); return; } - + if (hashSetCheckbox.isSelected() && hashSetList.getSelectedValuesList().isEmpty()) { setInvalid("At least one hash set name must be selected"); return; } - + if (interestingItemsCheckbox.isSelected() && interestingItemsList.getSelectedValuesList().isEmpty()) { setInvalid("At least one interesting file set name must be selected"); return; } - + if (objectsCheckbox.isSelected() && objectsList.getSelectedValuesList().isEmpty()) { setInvalid("At least one object type name must be selected"); return; } - + if (tagsCheckbox.isSelected() && tagsList.getSelectedValuesList().isEmpty()) { setInvalid("At least one tag name must be selected"); return; } - + if (scoreCheckbox.isSelected() && scoreList.getSelectedValuesList().isEmpty()) { setInvalid("At least one score must be selected"); return; @@ -612,7 +1063,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; - parentPathButtonGroup = new javax.swing.ButtonGroup(); + javax.swing.ButtonGroup parentPathButtonGroup = new javax.swing.ButtonGroup(); orderGroupsByButtonGroup = new javax.swing.ButtonGroup(); javax.swing.ButtonGroup parentIncludeButtonGroup = new javax.swing.ButtonGroup(); filtersScrollPane = new javax.swing.JScrollPane(); @@ -658,7 +1109,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener includeRadioButton = new javax.swing.JRadioButton(); excludeRadioButton = new javax.swing.JRadioButton(); knownFilesCheckbox = new javax.swing.JCheckBox(); - fileTypeLabel = new javax.swing.JLabel(); searchButton = new javax.swing.JButton(); sortingPanel = new javax.swing.JPanel(); groupByCombobox = new javax.swing.JComboBox<>(); @@ -668,7 +1118,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener groupSizeRadioButton = new javax.swing.JRadioButton(); orderByLabel = new javax.swing.JLabel(); groupByLabel = new javax.swing.JLabel(); - fileTypeComboBox = new javax.swing.JComboBox<>(); errorLabel = new javax.swing.JLabel(); cancelButton = new javax.swing.JButton(); @@ -727,7 +1176,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; + gridBagConstraints.gridy = 12; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(keywordCheckbox, gridBagConstraints); @@ -740,7 +1189,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 12; + gridBagConstraints.gridy = 7; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(parentCheckbox, gridBagConstraints); @@ -767,7 +1216,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener fullRadioButton.setEnabled(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 14; + gridBagConstraints.gridy = 9; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); filtersPanel.add(fullRadioButton, gridBagConstraints); @@ -777,7 +1226,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener substringRadioButton.setEnabled(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 14; + gridBagConstraints.gridy = 9; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 0.5; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); @@ -786,7 +1235,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener parentTextField.setEnabled(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 16; + gridBagConstraints.gridy = 11; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -806,7 +1255,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 16; + gridBagConstraints.gridy = 11; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END; gridBagConstraints.insets = new java.awt.Insets(0, 10, 6, 6); filtersPanel.add(addButton, gridBagConstraints); @@ -823,7 +1272,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 15; + gridBagConstraints.gridy = 10; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END; gridBagConstraints.insets = new java.awt.Insets(0, 10, 4, 6); filtersPanel.add(deleteButton, gridBagConstraints); @@ -865,7 +1314,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 3; + gridBagConstraints.gridy = 12; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -877,7 +1326,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener org.openide.awt.Mnemonics.setLocalizedText(parentLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.parentLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 13; + gridBagConstraints.gridy = 8; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weighty = 0.1; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); @@ -895,7 +1344,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 12; + gridBagConstraints.gridy = 7; gridBagConstraints.gridwidth = 3; gridBagConstraints.gridheight = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; @@ -913,7 +1362,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; + gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(hashSetCheckbox, gridBagConstraints); @@ -925,7 +1374,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 4; + gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -942,7 +1391,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; + gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(objectsCheckbox, gridBagConstraints); @@ -955,7 +1404,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 6; + gridBagConstraints.gridy = 13; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(tagsCheckbox, gridBagConstraints); @@ -968,7 +1417,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 7; + gridBagConstraints.gridy = 6; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(interestingItemsCheckbox, gridBagConstraints); @@ -981,7 +1430,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 8; + gridBagConstraints.gridy = 14; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 0); filtersPanel.add(scoreCheckbox, gridBagConstraints); @@ -989,7 +1438,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener org.openide.awt.Mnemonics.setLocalizedText(exifCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.exifCheckbox.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 9; + gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 6); @@ -998,7 +1447,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener org.openide.awt.Mnemonics.setLocalizedText(notableCheckbox, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.notableCheckbox.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 10; + gridBagConstraints.gridy = 15; gridBagConstraints.gridwidth = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 6); @@ -1011,7 +1460,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 5; + gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -1027,7 +1476,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 6; + gridBagConstraints.gridy = 13; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -1043,7 +1492,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 7; + gridBagConstraints.gridy = 6; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -1059,7 +1508,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 8; + gridBagConstraints.gridy = 14; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; @@ -1073,7 +1522,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener includeRadioButton.setEnabled(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 15; + gridBagConstraints.gridy = 10; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); filtersPanel.add(includeRadioButton, gridBagConstraints); @@ -1083,7 +1532,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener excludeRadioButton.setEnabled(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 15; + gridBagConstraints.gridy = 10; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 0.5; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); @@ -1093,7 +1542,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener knownFilesCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.knownFilesCheckbox.toolTipText")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 11; + gridBagConstraints.gridy = 16; gridBagConstraints.gridwidth = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 6, 4, 6); @@ -1101,8 +1550,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener filtersScrollPane.setViewportView(filtersPanel); - org.openide.awt.Mnemonics.setLocalizedText(fileTypeLabel, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.fileTypeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N searchButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -1144,8 +1591,8 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener .addComponent(groupByLabel))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(groupByCombobox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(orderByCombobox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(groupByCombobox, 0, 280, Short.MAX_VALUE) + .addComponent(orderByCombobox, 0, 1, Short.MAX_VALUE))) .addGroup(sortingPanelLayout.createSequentialGroup() .addGroup(sortingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(sortingPanelLayout.createSequentialGroup() @@ -1177,8 +1624,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener .addContainerGap()) ); - fileTypeComboBox.setModel(new DefaultComboBoxModel()); - errorLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.cancelButton.text")); // NOI18N @@ -1194,22 +1639,21 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(4, 4, 4) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(fileTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(fileTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap() + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 268, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(cancelButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(searchButton)) - .addComponent(sortingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(filtersScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(4, 4, 4)) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(filtersScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(sortingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGap(6, 6, 6)) ); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, searchButton}); @@ -1217,33 +1661,25 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(fileTypeLabel) - .addComponent(fileTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6) + .addComponent(filtersScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(sortingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filtersScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 290, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(errorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cancelButton) - .addComponent(searchButton)) - .addComponent(errorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + .addComponent(searchButton))) + .addGap(6, 6, 6)) ); }// //GEN-END:initComponents private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed - enableSearch(false); - - FileType searchType = fileTypeComboBox.getItemAt(fileTypeComboBox.getSelectedIndex()); - DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.SearchStartedEvent(searchType)); - // For testing, allow the user to run different searches in loop - // Get the selected filters List filters = getFilters(); + enableSearch(false); + DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.SearchStartedEvent(fileType)); // Get the grouping attribute and group sorting method FileSearch.AttributeType groupingAttr = getGroupingAttribute(); @@ -1251,6 +1687,15 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener // Get the file sorting method FileSorter.SortingMethod fileSort = getFileSortingMethod(); + EamDb centralRepoDb = null; + if (EamDb.isEnabled()) { + try { + centralRepoDb = EamDb.getInstance(); + } catch (EamDbException ex) { + centralRepoDb = null; + logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for File Discovery", ex); + } + } searchWorker = new SearchWorker(centralRepoDb, filters, groupingAttr, groupSortAlgorithm, fileSort); searchWorker.execute(); }//GEN-LAST:event_searchButtonActionPerformed @@ -1268,53 +1713,17 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener } else { DiscoveryTopComponent.getTopComponent().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } + if (fileType == FileType.IMAGE) { + imagesSelected(enabled, false); + } else if (fileType == FileType.VIDEO) { + videosSelected(enabled, false); + } searchButton.setEnabled(enabled); cancelButton.setEnabled(!enabled); - fileTypeComboBox.setEnabled(enabled); orderByCombobox.setEnabled(enabled); groupByCombobox.setEnabled(enabled); attributeRadioButton.setEnabled(enabled); groupSizeRadioButton.setEnabled(enabled); - sizeCheckbox.setEnabled(enabled); - sizeScrollPane.setEnabled(enabled && sizeCheckbox.isSelected()); - sizeList.setEnabled(enabled && sizeCheckbox.isSelected()); - dataSourceCheckbox.setEnabled(enabled); - dataSourceList.setEnabled(enabled && dataSourceCheckbox.isSelected()); - dataSourceScrollPane.setEnabled(enabled && dataSourceCheckbox.isSelected()); - crFrequencyCheckbox.setEnabled(enabled); - crFrequencyScrollPane.setEnabled(enabled && crFrequencyCheckbox.isSelected()); - crFrequencyList.setEnabled(enabled && crFrequencyCheckbox.isSelected()); - keywordCheckbox.setEnabled(enabled); - keywordList.setEnabled(enabled && keywordCheckbox.isSelected()); - keywordScrollPane.setEnabled(enabled && keywordCheckbox.isSelected()); - hashSetCheckbox.setEnabled(enabled); - hashSetScrollPane.setEnabled(enabled && hashSetCheckbox.isSelected()); - hashSetList.setEnabled(enabled && hashSetCheckbox.isSelected()); - objectsCheckbox.setEnabled(enabled); - objectsScrollPane.setEnabled(enabled && objectsCheckbox.isSelected()); - objectsList.setEnabled(enabled && objectsCheckbox.isSelected()); - tagsCheckbox.setEnabled(enabled); - tagsScrollPane.setEnabled(enabled && tagsCheckbox.isSelected()); - tagsList.setEnabled(enabled && tagsCheckbox.isSelected()); - interestingItemsCheckbox.setEnabled(enabled); - interestingItemsScrollPane.setEnabled(enabled && interestingItemsCheckbox.isSelected()); - interestingItemsList.setEnabled(enabled && interestingItemsCheckbox.isSelected()); - scoreCheckbox.setEnabled(enabled); - scoreScrollPane.setEnabled(enabled && scoreCheckbox.isSelected()); - scoreList.setEnabled(enabled && scoreCheckbox.isSelected()); - exifCheckbox.setEnabled(enabled); - notableCheckbox.setEnabled(enabled); - knownFilesCheckbox.setEnabled(enabled); - parentCheckbox.setEnabled(enabled); - parentScrollPane.setEnabled(enabled && parentCheckbox.isSelected()); - parentList.setEnabled(enabled && parentCheckbox.isSelected()); - parentTextField.setEnabled(enabled && parentCheckbox.isSelected()); - addButton.setEnabled(enabled && parentCheckbox.isSelected()); - deleteButton.setEnabled(enabled && parentCheckbox.isSelected() && !parentListModel.isEmpty()); - fullRadioButton.setEnabled(enabled && parentCheckbox.isSelected()); - substringRadioButton.setEnabled(enabled && parentCheckbox.isSelected()); - includeRadioButton.setEnabled(enabled && parentCheckbox.isSelected()); - excludeRadioButton.setEnabled(enabled && parentCheckbox.isSelected()); } /** @@ -1342,14 +1751,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener } private void parentCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_parentCheckboxActionPerformed - parentList.setEnabled(parentCheckbox.isSelected()); - fullRadioButton.setEnabled(parentCheckbox.isSelected()); - substringRadioButton.setEnabled(parentCheckbox.isSelected()); - includeRadioButton.setEnabled(parentCheckbox.isSelected()); - excludeRadioButton.setEnabled(parentCheckbox.isSelected()); - parentTextField.setEnabled(parentCheckbox.isSelected()); - addButton.setEnabled(parentCheckbox.isSelected()); - deleteButton.setEnabled(parentCheckbox.isSelected() && !parentListModel.isEmpty()); + parentFilterSettings(true, true, parentCheckbox.isSelected(), null); }//GEN-LAST:event_parentCheckboxActionPerformed private void keywordCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keywordCheckboxActionPerformed @@ -1442,8 +1844,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener private javax.swing.JLabel errorLabel; private javax.swing.JRadioButton excludeRadioButton; private javax.swing.JCheckBox exifCheckbox; - private javax.swing.JComboBox fileTypeComboBox; - private javax.swing.JLabel fileTypeLabel; private javax.swing.JPanel filtersPanel; private javax.swing.JScrollPane filtersScrollPane; private javax.swing.JRadioButton fullRadioButton; @@ -1472,7 +1872,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener private javax.swing.JCheckBox parentCheckbox; private javax.swing.JLabel parentLabel; private javax.swing.JList parentList; - private javax.swing.ButtonGroup parentPathButtonGroup; private javax.swing.JScrollPane parentScrollPane; private javax.swing.JTextField parentTextField; private javax.swing.JCheckBox scoreCheckbox; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java index db58b2889b..604daf2067 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSorter.java @@ -20,26 +20,28 @@ package org.sleuthkit.autopsy.filequery; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.List; import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.TskCoreException; /** * Class used to sort ResultFiles using the supplied method. */ class FileSorter implements Comparator { - + private final List> comparators = new ArrayList<>(); - + /** - * Set up the sorter using the supplied sorting method. - * The sorting is defined by a list of ResultFile comparators. These - * comparators will be run in order until one returns a non-zero result. - * + * Set up the sorter using the supplied sorting method. The sorting is + * defined by a list of ResultFile comparators. These comparators will be + * run in order until one returns a non-zero result. + * * @param method The method that should be used to sort the files */ FileSorter(SortingMethod method) { - + // Set up the primary comparators that should applied to the files switch (method) { case BY_DATA_SOURCE: @@ -58,7 +60,7 @@ class FileSorter implements Comparator { case BY_KEYWORD_LIST_NAMES: comparators.add(getKeywordListNameComparator()); break; - case BY_PARENT_PATH: + case BY_FULL_PATH: comparators.add(getParentPathComparator()); break; case BY_FILE_NAME: @@ -68,15 +70,15 @@ class FileSorter implements Comparator { // The default comparator will be added afterward break; } - + // Add the default comparator to the end. This will ensure a consistent sort // order regardless of the order the files were added to the list. comparators.add(getDefaultComparator()); } - + @Override public int compare(ResultFile file1, ResultFile file2) { - + int result = 0; for (Comparator comp : comparators) { result = comp.compare(file1, file2); @@ -84,35 +86,37 @@ class FileSorter implements Comparator { return result; } } - + // The files are the same return result; } - + /** * Compare files using data source ID. Will order smallest to largest. - * + * * @return -1 if file1 has the lower data source ID, 0 if equal, 1 otherwise */ private static Comparator getDataSourceComparator() { return (ResultFile file1, ResultFile file2) -> Long.compare(file1.getFirstInstance().getDataSourceObjectId(), file2.getFirstInstance().getDataSourceObjectId()); - } - + } + /** - * Compare files using their FileType enum. Orders based on the ranking - * in the FileType enum. - * + * Compare files using their FileType enum. Orders based on the ranking in + * the FileType enum. + * * @return -1 if file1 has the lower FileType value, 0 if equal, 1 otherwise */ private static Comparator getFileTypeComparator() { return (ResultFile file1, ResultFile file2) -> Integer.compare(file1.getFileType().getRanking(), file2.getFileType().getRanking()); - } - + } + /** - * Compare files using a concatenated version of keyword list names. Alphabetical by - * the list names with files with no keyword list hits going last. - * - * @return -1 if file1 has the earliest combined keyword list name, 0 if equal, 1 otherwise + * Compare files using a concatenated version of keyword list names. + * Alphabetical by the list names with files with no keyword list hits going + * last. + * + * @return -1 if file1 has the earliest combined keyword list name, 0 if + * equal, 1 otherwise */ private static Comparator getKeywordListNameComparator() { return (ResultFile file1, ResultFile file2) -> { @@ -125,66 +129,86 @@ class FileSorter implements Comparator { } else if (file2.getKeywordListNames().isEmpty()) { return -1; } - + String list1 = String.join(",", file1.getKeywordListNames()); String list2 = String.join(",", file2.getKeywordListNames()); return compareStrings(list1, list2); }; - } - + } + /** * Compare files based on parent path. Order alphabetically. - * - * @return -1 if file1's path comes first alphabetically, 0 if equal, 1 otherwise + * + * @return -1 if file1's path comes first alphabetically, 0 if equal, 1 + * otherwise */ private static Comparator getParentPathComparator() { - return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getParentPath(), file2.getFirstInstance().getParentPath()); - } - + + return new Comparator() { + @Override + public int compare(ResultFile file1, ResultFile file2) { + String file1ParentPath; + try { + file1ParentPath = file1.getFirstInstance().getParent().getUniquePath(); + } catch (TskCoreException ingored) { + file1ParentPath = file1.getFirstInstance().getParentPath(); + } + String file2ParentPath; + try { + file2ParentPath = file2.getFirstInstance().getParent().getUniquePath(); + } catch (TskCoreException ingored) { + file2ParentPath = file2.getFirstInstance().getParentPath(); + } + return compareStrings(file1ParentPath.toLowerCase(), file2ParentPath.toLowerCase()); + } + }; + } + /** * Compare files based on number of occurrences in the central repository. * Order from most rare to least rare Frequency enum. - * + * * @return -1 if file1's rarity is lower than file2, 0 if equal, 1 otherwise */ private static Comparator getFrequencyComparator() { return (ResultFile file1, ResultFile file2) -> Integer.compare(file1.getFrequency().getRanking(), file2.getFrequency().getRanking()); - } - + } + /** * Compare files based on MIME type. Order is alphabetical. - * - * @return -1 if file1's MIME type comes before file2's, 0 if equal, 1 otherwise + * + * @return -1 if file1's MIME type comes before file2's, 0 if equal, 1 + * otherwise */ private static Comparator getMIMETypeComparator() { return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getMIMEType(), file2.getFirstInstance().getMIMEType()); - } - + } + /** * Compare files based on size. Order large to small. - * + * * @return -1 if file1 is larger than file2, 0 if equal, 1 otherwise */ private static Comparator getFileSizeComparator() { return (ResultFile file1, ResultFile file2) -> -1 * Long.compare(file1.getFirstInstance().getSize(), file2.getFirstInstance().getSize()) // Sort large to small - ; + ; } - + /** * Compare files based on file name. Order alphabetically. - * + * * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise */ private static Comparator getFileNameComparator() { - return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getName(), file2.getFirstInstance().getName()); + return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getName().toLowerCase(), file2.getFirstInstance().getName().toLowerCase()); } - + /** - * A final default comparison between two ResultFile objects. - * Currently this is on file name and then object ID. It can be changed but - * should always include something like the object ID to ensure a - * consistent sorting when the rest of the compared fields are the same. - * + * A final default comparison between two ResultFile objects. Currently this + * is on file name and then object ID. It can be changed but should always + * include something like the object ID to ensure a consistent sorting when + * the rest of the compared fields are the same. + * * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise */ private static Comparator getDefaultComparator() { @@ -197,23 +221,19 @@ class FileSorter implements Comparator { return result; }; } - + /** * Compare two strings alphabetically. Nulls are allowed. - * + * * @param s1 * @param s2 - * - * @return -1 if s1 comes before s2, 0 if equal, 1 otherwise + * + * @return -1 if s1 comes before s2, 0 if equal, 1 otherwise */ private static int compareStrings(String s1, String s2) { - if (s1 == null) { - s1 = ""; - } - if (s2 == null) { - s2 = ""; - } - return s1.compareTo(s2); + String string1 = s1 == null ? "" : s1; + String string2 = s2 == null ? "" : s2; + return string1.compareTo(string2); } /** @@ -226,38 +246,47 @@ class FileSorter implements Comparator { "FileSorter.SortingMethod.filetype.displayName=By file type", "FileSorter.SortingMethod.frequency.displayName=By central repo frequency", "FileSorter.SortingMethod.keywordlist.displayName=By keyword list names", - "FileSorter.SortingMethod.parent.displayName=By parent path"}) + "FileSorter.SortingMethod.fullPath.displayName=By full path"}) enum SortingMethod { - BY_FILE_NAME(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name - BY_DATA_SOURCE(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_datasource_displayName()), // Sort in increasing order of data source ID - BY_FILE_SIZE(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_filesize_displayName()), // Sort in decreasing order of size - BY_FILE_TYPE(Arrays.asList(new FileSearch.FileTypeAttribute()), - Bundle.FileSorter_SortingMethod_filetype_displayName()), // Sort in order of file type (defined in FileType enum), with secondary sort on MIME type - BY_FREQUENCY(Arrays.asList(new FileSearch.FrequencyAttribute()), - Bundle.FileSorter_SortingMethod_frequency_displayName()), // Sort by decreasing rarity in the central repository - BY_KEYWORD_LIST_NAMES(Arrays.asList(new FileSearch.KeywordListAttribute()), - Bundle.FileSorter_SortingMethod_keywordlist_displayName()), // Sort alphabetically by list of keyword list names found - BY_PARENT_PATH(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_parent_displayName()); // Sort alphabetically by path - + BY_FILE_NAME(new ArrayList<>(), + Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name + BY_DATA_SOURCE(new ArrayList<>(), + Bundle.FileSorter_SortingMethod_datasource_displayName()), // Sort in increasing order of data source ID + BY_FILE_SIZE(new ArrayList<>(), + Bundle.FileSorter_SortingMethod_filesize_displayName()), // Sort in decreasing order of size + BY_FILE_TYPE(Arrays.asList(new FileSearch.FileTypeAttribute()), + Bundle.FileSorter_SortingMethod_filetype_displayName()), // Sort in order of file type (defined in FileType enum), with secondary sort on MIME type + BY_FREQUENCY(Arrays.asList(new FileSearch.FrequencyAttribute()), + Bundle.FileSorter_SortingMethod_frequency_displayName()), // Sort by decreasing rarity in the central repository + BY_KEYWORD_LIST_NAMES(Arrays.asList(new FileSearch.KeywordListAttribute()), + Bundle.FileSorter_SortingMethod_keywordlist_displayName()), // Sort alphabetically by list of keyword list names found + BY_FULL_PATH(new ArrayList<>(), + Bundle.FileSorter_SortingMethod_fullPath_displayName()); // Sort alphabetically by path + private final String displayName; private final List requiredAttributes; - + SortingMethod(List attributes, String displayName) { this.requiredAttributes = attributes; this.displayName = displayName; } - + @Override public String toString() { return displayName; } - + List getRequiredAttributes() { - return requiredAttributes; + return Collections.unmodifiableList(requiredAttributes); + } + + /** + * Get the list of enums that are valid for ordering images. + * + * @return enums that can be used to ordering images. + */ + static List getOptionsForOrdering() { + return Arrays.asList(BY_FILE_SIZE, BY_FULL_PATH, BY_FILE_NAME, BY_DATA_SOURCE); } } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form index c3500a7fa9..e774a0fac7 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form @@ -41,6 +41,13 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java index e16622388a..05e27cd462 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java @@ -90,6 +90,7 @@ class GroupListPanel extends javax.swing.JPanel { groupListScrollPane = new javax.swing.JScrollPane(); groupKeyList = new javax.swing.JList<>(); + groupKeyList.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(GroupListPanel.class, "GroupListPanel.groupKeyList.border.title"))); // NOI18N groupKeyList.setModel(new DefaultListModel()); groupKeyList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); groupKeyList.setCellRenderer(new GroupListRenderer()); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index 8fd3ded382..5f83505af8 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListModel; import javax.swing.JList; @@ -40,7 +41,9 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -57,6 +60,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class ResultsPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(ResultsPanel.class.getName()); private final VideoThumbnailViewer videoThumbnailViewer; private final ImageThumbnailViewer imageThumbnailViewer; private List searchFilters; @@ -67,7 +71,6 @@ public class ResultsPanel extends javax.swing.JPanel { private int currentPage = 0; private int previousPageSize = 10; private FileSearchData.FileType resultType; - private final EamDb centralRepo; private int groupSize = 0; private PageWorker pageWorker; private final List> thumbnailWorkers = new ArrayList<>(); @@ -78,9 +81,8 @@ public class ResultsPanel extends javax.swing.JPanel { */ @Messages({"ResultsPanel.viewFileInDir.name=View File in Directory", "ResultsPanel.openInExternalViewer.name=Open in External Viewer"}) - public ResultsPanel(EamDb centralRepo) { + public ResultsPanel() { initComponents(); - this.centralRepo = centralRepo; imageThumbnailViewer = new ImageThumbnailViewer(); videoThumbnailViewer = new VideoThumbnailViewer(); videoThumbnailViewer.addListSelectionListener((e) -> { @@ -299,6 +301,15 @@ public class ResultsPanel extends javax.swing.JPanel { if (pageWorker != null && !pageWorker.isDone()) { pageWorker.cancel(true); } + EamDb centralRepo = null; + if (EamDb.isEnabled()) { + try { + centralRepo = EamDb.getInstance(); + } catch (EamDbException ex) { + centralRepo = null; + logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for File Discovery", ex); + } + } pageWorker = new PageWorker(searchFilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, startingEntry, pageSize, resultType, centralRepo); pageWorker.execute(); } diff --git a/Core/src/org/sleuthkit/autopsy/images/pictures-icon.png b/Core/src/org/sleuthkit/autopsy/images/pictures-icon.png new file mode 100644 index 0000000000..b706ce3d22 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/pictures-icon.png differ diff --git a/Core/src/org/sleuthkit/autopsy/images/video-icon.png b/Core/src/org/sleuthkit/autopsy/images/video-icon.png new file mode 100644 index 0000000000..67b2f87549 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/video-icon.png differ diff --git a/ruleset.xml b/ruleset.xml index 5e8d384232..468f95087e 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -140,7 +140,6 @@ -