From 84e947bcf2dcd3cb09b3d8da41ceef27ac318aaa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 17 Oct 2019 17:44:08 -0400 Subject: [PATCH] 5368 change group list to use group keys instead of strings --- .../filequery/Bundle.properties-MERGED | 1 - .../autopsy/filequery/DiscoveryEvents.java | 26 +-- .../autopsy/filequery/FileGroup.java | 21 +- .../autopsy/filequery/FileSearch.java | 61 +++--- .../filequery/FileSearchTestAction.java | 180 ------------------ .../autopsy/filequery/GroupListPanel.form | 11 +- .../autopsy/filequery/GroupListPanel.java | 67 +++++-- .../autopsy/filequery/PageWorker.java | 12 +- .../autopsy/filequery/ResultsPanel.java | 7 +- .../autopsy/filequery/SearchResults.java | 7 +- .../autopsy/filequery/SearchWorker.java | 3 +- 11 files changed, 140 insertions(+), 256 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/filequery/FileSearchTestAction.java diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED index af49cf14a4..9d482a0f24 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED @@ -1,5 +1,4 @@ CTL_FileDiscoveryTestAction=Test file discovery -CTL_FileSearchTestAction=Test file search # {0} - Data source name # {1} - Data source ID FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEvents.java b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEvents.java index 48fe0cc41d..73473b0234 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEvents.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DiscoveryEvents.java @@ -22,6 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; import java.util.Map; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; /** @@ -74,7 +75,7 @@ final class DiscoveryEvents { */ static final class SearchCompleteEvent { - private final Map groupMap; + private final Map groupMap; private final List searchFilters; private final FileSearch.AttributeType groupingAttribute; private final FileGroup.GroupSortingAlgorithm groupSort; @@ -91,7 +92,7 @@ final class DiscoveryEvents { * @param groupSort The sorting algorithm used for groups. * @param fileSortMethod The sorting method used for files. */ - SearchCompleteEvent(Map groupMap, List searchfilters, + SearchCompleteEvent(Map groupMap, List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; @@ -106,7 +107,7 @@ final class DiscoveryEvents { * * @return The map of groups which were found by the search. */ - Map getGroupMap() { + Map getGroupMap() { return Collections.unmodifiableMap(groupMap); } @@ -218,7 +219,7 @@ final class DiscoveryEvents { static final class GroupSelectedEvent { private final FileType resultType; - private final String groupName; + private final GroupKey groupKey; private final int groupSize; private final List searchfilters; private final FileSearch.AttributeType groupingAttribute; @@ -233,19 +234,20 @@ final class DiscoveryEvents { * @param groupingAttribute The grouping attribute used by the search. * @param groupSort The sorting algorithm used for groups. * @param fileSortMethod The sorting method used for files. - * @param groupName The name of the group which was selected. + * @param groupKey The key associated with the group which was + * selected. * @param groupSize The number of files in the group which was * selected. * @param resultType The type of files which exist in the group. */ GroupSelectedEvent(List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, - FileSorter.SortingMethod fileSortMethod, String groupName, int groupSize, FileType resultType) { + FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, FileType resultType) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; this.fileSortMethod = fileSortMethod; - this.groupName = groupName; + this.groupKey = groupKey; this.groupSize = groupSize; this.resultType = resultType; } @@ -260,12 +262,14 @@ final class DiscoveryEvents { } /** - * Get the name of the group which was selected. + * Get the group key which is used to uniquely identify the group + * selected. * - * @return The name of the group which was selected. + * @return The group key which is used to uniquely identify the group + * selected. */ - String getGroupName() { - return groupName; + GroupKey getGroupKey() { + return groupKey; } /** diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java b/Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java index ad0878424c..3fead9ffcd 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileGroup.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.filequery; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; /** * Class for storing files that belong to a particular group. @@ -28,7 +29,7 @@ import java.util.List; class FileGroup implements Comparable { private final FileGroup.GroupSortingAlgorithm groupSortingType; - private final FileSearch.GroupKey groupKey; + private final GroupKey groupKey; private final List files; private final String displayName; @@ -38,7 +39,7 @@ class FileGroup implements Comparable { * @param groupSortingType The method for sorting the group * @param groupKey The GroupKey for this group */ - FileGroup(FileGroup.GroupSortingAlgorithm groupSortingType, FileSearch.GroupKey groupKey) { + FileGroup(FileGroup.GroupSortingAlgorithm groupSortingType, GroupKey groupKey) { this.groupSortingType = groupSortingType; this.groupKey = groupKey; files = new ArrayList<>(); @@ -54,21 +55,29 @@ class FileGroup implements Comparable { if (files.contains(file)) { ResultFile existingCopy = files.get(files.indexOf(file)); //get the copy of this which exists in the list existingCopy.addDuplicate(file.getFirstInstance()); - } - else { + } else { files.add(file); } } /** - * Get the display name for this group. This must be unique for each group. + * Get the display name for this group. * - * @return the display name + * @return The display name of the group. */ String getDisplayName() { return displayName; // NON-NLS } + /** + * Get the key which uniquely identifies each group. + * + * @return The unique key for the group. + */ + GroupKey getGroupKey() { + return groupKey; + } + /** * Pull the AbstractFile objects out of the ResultFile objects. * diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index c61521ebdf..930e67fad2 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -69,7 +69,7 @@ import org.sleuthkit.datamodel.TskCoreException; class FileSearch { private final static Logger logger = Logger.getLogger(FileSearch.class.getName()); - private static final Cache> groupCache = CacheBuilder.newBuilder().build(); + private static final Cache> groupCache = CacheBuilder.newBuilder().build(); /** * Run the file search and returns the SearchResults object for debugging. @@ -116,15 +116,15 @@ class FileSearch { // Sort and group the results searchResults.sortGroupsAndFiles(); - Map> resultHashMap = searchResults.toLinkedHashMap(); - for (String groupName : resultHashMap.keySet()) { - groupCache.put(groupName, resultHashMap.get(groupName)); + Map> resultHashMap = searchResults.toLinkedHashMap(); + for (GroupKey groupKey : resultHashMap.keySet()) { + groupCache.put(groupKey, resultHashMap.get(groupKey)); } return searchResults; } /** - * Run the file search to get the group names and sizes. Clears cache of + * Run the file search to get the group keys and sizes. Clears cache of * search results, caching new results for access at later time. * * @param filters The filters to apply @@ -140,17 +140,17 @@ class FileSearch { * * @throws FileSearchException */ - static LinkedHashMap getGroupSizes( + static LinkedHashMap getGroupSizes( List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException { - Map> searchResults = runFileSearch(filters, + Map> searchResults = runFileSearch(filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); - LinkedHashMap groupSizes = new LinkedHashMap<>(); - for (String groupName : searchResults.keySet()) { - groupSizes.put(groupName, searchResults.get(groupName).size()); + LinkedHashMap groupSizes = new LinkedHashMap<>(); + for (GroupKey groupKey : searchResults.keySet()) { + groupSizes.put(groupKey, searchResults.get(groupKey).size()); } return groupSizes; } @@ -164,7 +164,8 @@ class FileSearch { * @param groupSortingType The method to use to sort the groups * @param fileSortingMethod The method to use to sort the files within the * groups - * @param groupName Name of the group to get entries from + * @param groupKey The key which uniquely identifies the group to + * get entries from * @param startingEntry The first entry to return * @param numberOfEntries The number of entries to return * @param caseDb The case database @@ -180,19 +181,19 @@ class FileSearch { AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, - String groupName, + GroupKey groupKey, int startingEntry, int numberOfEntries, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException { //the group should be in the cache at this point - List filesInGroup = groupCache.getIfPresent(groupName); + List filesInGroup = groupCache.getIfPresent(groupKey); List page = new ArrayList<>(); if (filesInGroup == null) { - logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupName); + logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupKey); runFileSearch(filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); - filesInGroup = groupCache.getIfPresent(groupName); + filesInGroup = groupCache.getIfPresent(groupKey); if (filesInGroup == null) { - logger.log(Level.WARNING, "Group {0} did not exist in cache or new search results", groupName); + logger.log(Level.WARNING, "Group {0} did not exist in cache or new search results", groupKey); return page; //group does not exist } } @@ -226,7 +227,7 @@ class FileSearch { * * @throws FileSearchException */ - private synchronized static Map> runFileSearch( + private synchronized static Map> runFileSearch( List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, @@ -251,9 +252,9 @@ class FileSearch { // Collect everything in the search results SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); searchResults.add(resultFiles); - Map> resultHashMap = searchResults.toLinkedHashMap(); - for (String groupName : resultHashMap.keySet()) { - groupCache.put(groupName, resultHashMap.get(groupName)); + Map> resultHashMap = searchResults.toLinkedHashMap(); + for (GroupKey groupKey : resultHashMap.keySet()) { + groupCache.put(groupKey, resultHashMap.get(groupKey)); } // Return a version of the results in general Java objects return resultHashMap; @@ -581,6 +582,11 @@ class FileSearch { int compareClassNames(GroupKey otherGroupKey) { return this.getClass().getName().compareTo(otherGroupKey.getClass().getName()); } + + @Override + public String toString() { + return getDisplayName(); + } } /** @@ -657,12 +663,14 @@ class FileSearch { private static class ParentPathGroupKey extends GroupKey { private String parentPath; + private Long parentID = -1L; ParentPathGroupKey(ResultFile file) { if (file.getFirstInstance().getParentPath() != null) { try { parentPath = file.getFirstInstance().getParent().getUniquePath(); + parentID = file.getFirstInstance().getParent().getId(); } catch (TskCoreException ingored) { parentPath = file.getFirstInstance().getParentPath(); } @@ -680,7 +688,11 @@ class FileSearch { public int compareTo(GroupKey otherGroupKey) { if (otherGroupKey instanceof ParentPathGroupKey) { ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherGroupKey; - return parentPath.compareTo(otherParentPathGroupKey.parentPath); + int comparisonResult = parentPath.compareTo(otherParentPathGroupKey.parentPath); + if (comparisonResult == 0) { + comparisonResult = parentID.compareTo(otherParentPathGroupKey.parentID); + } + return comparisonResult; } else { return compareClassNames(otherGroupKey); } @@ -697,12 +709,15 @@ class FileSearch { } ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherKey; - return parentPath.equals(otherParentPathGroupKey.parentPath); + return parentPath.equals(otherParentPathGroupKey.parentPath) && parentID.equals(otherParentPathGroupKey.parentID); } @Override public int hashCode() { - return Objects.hash(parentPath); + int hashCode = 11; + hashCode = 61 * hashCode + Objects.hash(parentPath); + hashCode = 61 * hashCode + Objects.hash(parentID); + return hashCode; } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchTestAction.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearchTestAction.java deleted file mode 100644 index feffb2c677..0000000000 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearchTestAction.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2018 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.filequery; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.logging.Level; -import org.apache.commons.lang.exception.ExceptionUtils; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.openide.awt.ActionID; -import org.openide.awt.ActionReference; -import org.openide.awt.ActionRegistration; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * Class to test the file search API. Allows the user to run searches and see results. - */ -@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.newpackage.FileSearchTestAction") -@ActionReference(path = "Menu/Tools", position = 1852, separatorBefore = 1851) -@ActionRegistration(displayName = "#CTL_FileSearchTestAction", lazy = false) -@NbBundle.Messages({"CTL_FileSearchTestAction=Test file search"}) -public final class FileSearchTestAction extends CallableSystemAction { - - private final static Logger logger = Logger.getLogger(FileSearchTestAction.class.getName()); - private static final String DISPLAY_NAME = "Test file search"; - - @Override - public boolean isEnabled() { - return Case.isCaseOpen(); - } - - @Override - @SuppressWarnings("fallthrough") - public void performAction() { - - // Load the central repository database. - EamDb crDb = null; - if (EamDb.isEnabled()) { - try { - crDb = EamDb.getInstance(); - } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error loading central repository database", ex); - return; - } - } - - FileSearchDialog dialog = new FileSearchDialog(null, true, Case.getCurrentCase().getSleuthkitCase(), crDb); - - // For testing, allow the user to run different searches in loop - while (true) { - - // Display the dialog - dialog.display(); - - if (dialog.searchCancelled()) { - return; - } - - // Get the selected filters - List filters = dialog.getFilters(); - - // Get the grouping attribute and group sorting method - FileSearch.AttributeType groupingAttr = dialog.getGroupingAttribute(); - FileGroup.GroupSortingAlgorithm groupSortAlgorithm = dialog.getGroupSortingMethod(); - - // Get the file sorting method - FileSorter.SortingMethod fileSort = dialog.getFileSortingMethod(); - - try { - - // Test getting the groups - LinkedHashMap groups = FileSearch.getGroupSizes(filters, - groupingAttr, - groupSortAlgorithm, - fileSort, - Case.getCurrentCase().getSleuthkitCase(), crDb); - - System.out.println("Groups: "); - for (String name : groups.keySet()) { - System.out.println(" " + name + " : " + groups.get(name)); - } - - if (! groups.isEmpty()) { - String firstGroupName = groups.keySet().iterator().next(); - - List entries0to5 = FileSearch.getFilesInGroup(filters, - groupingAttr, - groupSortAlgorithm, - fileSort, - firstGroupName, - 0, - 5, - Case.getCurrentCase().getSleuthkitCase(), crDb); - System.out.println("First five " + firstGroupName + " : "); - for (ResultFile f : entries0to5) { - System.out.println(" " + f.getFirstInstance().getName()); - } - - List entries6to106 = FileSearch.getFilesInGroup(filters, - groupingAttr, - groupSortAlgorithm, - fileSort, - firstGroupName, - 5, - 100, - Case.getCurrentCase().getSleuthkitCase(), crDb); - System.out.println(firstGroupName + " 6 to 106: "); - for (ResultFile f : entries6to106) { - System.out.println(" " + f.getFirstInstance().getName()); - } - } - - - ///////////////// - // Run the search - SearchResults results = FileSearch.runFileSearchDebug(filters, - groupingAttr, - groupSortAlgorithm, - fileSort, - Case.getCurrentCase().getSleuthkitCase(), crDb); - - // Display the results - ResultsDialog resultsDialog = new ResultsDialog(null, true, results.toString()); - resultsDialog.display(); - - if ( ! resultsDialog.shouldRunAnotherSearch()) { - return; - } - - } catch (FileSearchException ex) { - logger.log(Level.SEVERE, "Error running file search test", ex); - - // Display the exception in the UI for easier debugging - String message = ex.toString() + "\n" + ExceptionUtils.getStackTrace(ex); - ResultsDialog resultsDialog = new ResultsDialog(null, true, message); - resultsDialog.display(); - if (! resultsDialog.runAnotherSearch) { - return; - } - } - - } - } - - @Override - public String getName() { - return DISPLAY_NAME; - } - - @Override - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - - @Override - public boolean asynchronous() { - return false; // run on edt - } -} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form index f04c493133..c3500a7fa9 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.form @@ -39,18 +39,21 @@ - + - - + + + + + - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java index 136b8604c4..787a0fc21b 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/GroupListPanel.java @@ -21,7 +21,10 @@ package org.sleuthkit.autopsy.filequery; import com.google.common.eventbus.Subscribe; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; /** @@ -31,12 +34,12 @@ class GroupListPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private FileType resultType = null; - private Map groupMap = null; + private Map groupMap = null; private List searchfilters; private FileSearch.AttributeType groupingAttribute; private FileGroup.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; - private String selectedGroupName; + private GroupKey selectedGroupKey; /** * Creates new form GroupListPanel @@ -53,7 +56,7 @@ class GroupListPanel extends javax.swing.JPanel { @Subscribe void handleSearchStartedEvent(DiscoveryEvents.SearchStartedEvent searchStartedEvent) { resultType = searchStartedEvent.getType(); - groupDisplayNameList.setListData(new String[0]); + groupKeyList.setListData(new GroupKey[0]); } /** @@ -69,10 +72,9 @@ class GroupListPanel extends javax.swing.JPanel { groupingAttribute = searchCompleteEvent.getGroupingAttr(); groupSort = searchCompleteEvent.getGroupSort(); fileSortMethod = searchCompleteEvent.getFileSort(); - List groupNames = groupMap.entrySet().stream().map(e -> e.getKey() + " (" + e.getValue() + ")").collect(Collectors.toList()); - groupDisplayNameList.setListData(groupNames.toArray(new String[groupNames.size()])); - if (groupDisplayNameList.getModel().getSize() > 0) { - groupDisplayNameList.setSelectedIndex(0); + groupKeyList.setListData(groupMap.keySet().toArray(new GroupKey[groupMap.keySet().size()])); + if (groupKeyList.getModel().getSize() > 0) { + groupKeyList.setSelectedIndex(0); } } @@ -86,15 +88,17 @@ class GroupListPanel extends javax.swing.JPanel { private void initComponents() { groupListScrollPane = new javax.swing.JScrollPane(); - groupDisplayNameList = new javax.swing.JList<>(); + groupKeyList = new javax.swing.JList<>(); - groupDisplayNameList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - groupDisplayNameList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { + groupKeyList.setModel(new DefaultListModel()); + groupKeyList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + groupKeyList.setCellRenderer(new GroupListRenderer()); + groupKeyList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { public void valueChanged(javax.swing.event.ListSelectionEvent evt) { groupSelected(evt); } }); - groupListScrollPane.setViewportView(groupDisplayNameList); + groupListScrollPane.setViewportView(groupKeyList); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -119,13 +123,13 @@ class GroupListPanel extends javax.swing.JPanel { */ private void groupSelected(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_groupSelected if (!evt.getValueIsAdjusting()) { - if (groupDisplayNameList.getSelectedValue() != null) { - String selectedGroup = groupDisplayNameList.getSelectedValue().replaceAll(" \\([0-9]+\\)$", ""); - for (String groupName : groupMap.keySet()) { - if (selectedGroup.equalsIgnoreCase(groupName)) { - selectedGroupName = groupName; + if (groupKeyList.getSelectedValue() != null) { + GroupKey selectedGroup = groupKeyList.getSelectedValue(); + for (GroupKey groupKey : groupMap.keySet()) { + if (selectedGroup.equals(groupKey)) { + selectedGroupKey = groupKey; DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.GroupSelectedEvent( - searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupName, groupMap.get(selectedGroupName), resultType)); + searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), resultType)); break; } } @@ -136,7 +140,32 @@ class GroupListPanel extends javax.swing.JPanel { }//GEN-LAST:event_groupSelected // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList groupDisplayNameList; + private javax.swing.JList groupKeyList; private javax.swing.JScrollPane groupListScrollPane; // End of variables declaration//GEN-END:variables + + /** + * GroupListCellRenderer displays GroupKeys as their String value followed + * by the number of items in the group. + */ + private class GroupListRenderer extends DefaultListCellRenderer { + + private static final long serialVersionUID = 1L; + + @Override + public java.awt.Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + Object newValue = value; + if (newValue instanceof GroupKey) { + newValue = newValue.toString() + " (" + groupMap.get(newValue) + ")"; + } + super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); + return this; + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java b/Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java index 08a68cf953..e65916008a 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/PageWorker.java @@ -24,6 +24,7 @@ import javax.swing.SwingWorker; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; /** * SwingWorker to retrieve the contents of a page. @@ -35,7 +36,7 @@ final class PageWorker extends SwingWorker { private final FileSearch.AttributeType groupingAttribute; private final FileGroup.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; - private final String groupName; + private final GroupKey groupKey; private final int startingEntry; private final int pageSize; private final FileSearchData.FileType resultType; @@ -49,7 +50,8 @@ final class PageWorker extends SwingWorker { * @param groupingAttribute The grouping attribute used by the search. * @param groupSort The sorting algorithm used for groups. * @param fileSortMethod The sorting method used for files. - * @param groupName The name of the group which was selected. + * @param groupKey The key which uniquely identifies the group + * which was selected. * @param startingEntry The first entry in the group to include in this * page. * @param pageSize The number of files to include in this page. @@ -57,13 +59,13 @@ final class PageWorker extends SwingWorker { * @param centralRepo The central repository to be used. */ PageWorker(List searchfilters, FileSearch.AttributeType groupingAttribute, - FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, String groupName, + FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int startingEntry, int pageSize, FileSearchData.FileType resultType, EamDb centralRepo) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; this.fileSortMethod = fileSortMethod; - this.groupName = groupName; + this.groupKey = groupKey; this.startingEntry = startingEntry; this.pageSize = pageSize; this.resultType = resultType; @@ -78,7 +80,7 @@ final class PageWorker extends SwingWorker { List results = FileSearch.getFilesInGroup(searchfilters, groupingAttribute, groupSort, - fileSortMethod, groupName, startingEntry, pageSize, + fileSortMethod, groupKey, startingEntry, pageSize, Case.getCurrentCase().getSleuthkitCase(), centralRepo); int currentPage = startingEntry / pageSize; //integer division should round down to get page number correctly DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.PageRetrievedEvent(resultType, currentPage, results)); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index 5809eb6051..41467235da 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -40,6 +40,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -57,7 +58,7 @@ public class ResultsPanel extends javax.swing.JPanel { private FileSearch.AttributeType groupingAttribute; private FileGroup.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; - private String selectedGroupName; + private GroupKey selectedGroupKey; private int currentPage = 0; private int previousPageSize = 10; private FileSearchData.FileType resultType; @@ -241,7 +242,7 @@ public class ResultsPanel extends javax.swing.JPanel { groupingAttribute = groupSelectedEvent.getGroupingAttr(); groupSort = groupSelectedEvent.getGroupSort(); fileSortMethod = groupSelectedEvent.getFileSort(); - selectedGroupName = groupSelectedEvent.getGroupName(); + selectedGroupKey = groupSelectedEvent.getGroupKey(); resultType = groupSelectedEvent.getResultType(); groupSize = groupSelectedEvent.getGroupSize(); setPage(0); @@ -274,7 +275,7 @@ public class ResultsPanel extends javax.swing.JPanel { if (pageWorker != null && !pageWorker.isDone()) { pageWorker.cancel(true); } - pageWorker = new PageWorker(searchFilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupName, startingEntry, pageSize, resultType, centralRepo); + pageWorker = new PageWorker(searchFilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, startingEntry, pageSize, resultType, centralRepo); pageWorker.execute(); } } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java b/Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java index f48cd4d1f8..1c8311cdca 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/SearchResults.java @@ -25,6 +25,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; /** * Class to hold the results of the filtering/grouping/sorting operations @@ -150,15 +151,15 @@ class SearchResults { * * @return the grouped and sorted results */ - Map> toLinkedHashMap() throws FileSearchException { - Map> map = new LinkedHashMap<>(); + Map> toLinkedHashMap() throws FileSearchException { + Map> map = new LinkedHashMap<>(); // Sort the groups and files sortGroupsAndFiles(); // groupList is sorted and a LinkedHashMap will preserve that order. for (FileGroup group : groupList) { - map.put(group.getDisplayName(), group.getAbstractFiles()); + map.put(group.getGroupKey(), group.getAbstractFiles()); } return map; diff --git a/Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java index 734b49d04e..913760c493 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/SearchWorker.java @@ -26,6 +26,7 @@ import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.filequery.FileSearch.GroupKey; /** * SwingWorker to perform search on a background thread @@ -65,7 +66,7 @@ final class SearchWorker extends SwingWorker { try { // Run the search - LinkedHashMap results = FileSearch.getGroupSizes(filters, + LinkedHashMap results = FileSearch.getGroupSizes(filters, groupingAttr, groupSortAlgorithm, fileSort,