5114 Clean up and add comments for file discovery ui

This commit is contained in:
William Schaefer 2019-07-17 11:09:48 -04:00
parent 2680b9d9f4
commit 99fe56539f
7 changed files with 116 additions and 47 deletions

View File

@ -21,14 +21,21 @@ package org.sleuthkit.autopsy.filequery;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/**
* Class to handle envent bus and events for file discovery tool
*/
final class DiscoveryEvents { final class DiscoveryEvents {
private final static EventBus discoveryEventBus = new EventBus(); private final static EventBus discoveryEventBus = new EventBus();
/**
* Get the file discovery event bus
*
* @return the file discovery event bus
*/
static EventBus getDiscoveryEventBus() { static EventBus getDiscoveryEventBus() {
return discoveryEventBus; return discoveryEventBus;
} }
@ -36,53 +43,92 @@ final class DiscoveryEvents {
private DiscoveryEvents() { private DiscoveryEvents() {
} }
/**
* Event to signal the start of a search being performed
*/
static final class SearchStartedEvent { static final class SearchStartedEvent {
private final FileType fileType; private final FileType fileType;
/**
* Construct a new SearchStartedEvent
*
* @param type the type of file the search event is for
*/
SearchStartedEvent(FileType type) { SearchStartedEvent(FileType type) {
this.fileType = type; this.fileType = type;
} }
/**
* Get the type of file the search is being performed for
*
* @return the type of files being searched for
*/
FileType getType() { FileType getType() {
return fileType; return fileType;
} }
} }
/**
* Event to signal the completion of a search being performed
*/
static final class SearchCompleteEvent { static final class SearchCompleteEvent {
private final SearchResults results; private final SearchResults results;
private final FileType fileType;
SearchCompleteEvent(FileType type, SearchResults results) { /**
this.fileType = type; * Construct a new SearchCompleteEvent
*
* @param results the results which were found by the search
*/
SearchCompleteEvent(SearchResults results) {
this.results = results; this.results = results;
} }
/**
* Get the results of the search
*
* @return the results of the search
*/
SearchResults getSearchResults() { SearchResults getSearchResults() {
return results; return results;
} }
FileType getType() {
return fileType;
}
} }
/**
* Event to signal the the selection of a group from the search results
*/
static final class GroupSelectedEvent { static final class GroupSelectedEvent {
private final List<AbstractFile> files; private final List<AbstractFile> files;
private final FileType type; private final FileType type;
/**
* Construct a new GroupSelectedEvent
*
* @param type the type of files which exist in the group
* @param files the files in the group
*/
GroupSelectedEvent(FileType type, List<AbstractFile> files) { GroupSelectedEvent(FileType type, List<AbstractFile> files) {
this.type = type; this.type = type;
this.files = files; this.files = files;
} }
/**
* Get the type of files which exist in the group
*
* @return the type of files in the group
*/
FileType getType() { FileType getType() {
return type; return type;
} }
/**
* Get the files in the group selected
*
* @return the list of AbstractFiles in the group selected
*/
List<AbstractFile> getFiles() { List<AbstractFile> getFiles() {
if (files != null && !files.isEmpty()) { if (files != null && !files.isEmpty()) {
return files; return files;

View File

@ -31,18 +31,18 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
public class DiscoveryThumbnailChild extends Children.Keys<AbstractFile> { /**
* Create a node containing the children for the to display in the
* DataResultViewerThumbnail
*/
class DiscoveryThumbnailChildren extends Children.Keys<AbstractFile> {
private final List<AbstractFile> files; private final List<AbstractFile> files;
/* /*
* Creates the list of thumbnails from the given list of * Creates the list of thumbnails from the given list of AbstractFiles.
* BlackboardArtifacts.
*
* The thumbnails will be initialls sorted by size, then name so that they
* appear sorted by size by default.
*/ */
DiscoveryThumbnailChild(List<AbstractFile> files) { DiscoveryThumbnailChildren(List<AbstractFile> files) {
super(false); super(false);
this.files = files; this.files = files;
@ -51,7 +51,7 @@ public class DiscoveryThumbnailChild extends Children.Keys<AbstractFile> {
@Override @Override
protected Node[] createNodes(AbstractFile t) { protected Node[] createNodes(AbstractFile t) {
return new Node[]{new AttachementNode(t)}; return new Node[]{new ThumbnailNode(t)};
} }
@Override @Override
@ -73,9 +73,9 @@ public class DiscoveryThumbnailChild extends Children.Keys<AbstractFile> {
/** /**
* A node for representing a thumbnail. * A node for representing a thumbnail.
*/ */
static class AttachementNode extends FileNode { static class ThumbnailNode extends FileNode {
AttachementNode(AbstractFile file) { ThumbnailNode(AbstractFile file) {
super(file, false); super(file, false);
} }

View File

@ -33,6 +33,9 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
/**
* Create a dialog for displaying the file discovery tool
*/
class FileDiscoveryDialog extends javax.swing.JDialog { class FileDiscoveryDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -50,7 +53,6 @@ class FileDiscoveryDialog extends javax.swing.JDialog {
super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.FileSearchPanel_dialogTitle_text(), modal); super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.FileSearchPanel_dialogTitle_text(), modal);
initComponents(); initComponents();
explorerManager = new ExplorerManager(); explorerManager = new ExplorerManager();
//create results callback and pass it into the search panel
fileSearchPanel = new FileSearchPanel(caseDb, centralRepoDb); fileSearchPanel = new FileSearchPanel(caseDb, centralRepoDb);
groupListPanel = new GroupListPanel(); groupListPanel = new GroupListPanel();
DiscoveryEvents.getDiscoveryEventBus().register(groupListPanel); DiscoveryEvents.getDiscoveryEventBus().register(groupListPanel);
@ -86,17 +88,21 @@ class FileDiscoveryDialog extends javax.swing.JDialog {
*/ */
void display() { void display() {
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
// runAnotherSearch = false;
setVisible(true); setVisible(true);
} }
/**
* Subscribe to GroupSelectedEvents and respond to them
*
* @param groupSelectedEvent the GroupSelectedEvent received
*/
@Subscribe @Subscribe
void handleGroupSelectedEvent(DiscoveryEvents.GroupSelectedEvent groupSelectedEvent) { void handleGroupSelectedEvent(DiscoveryEvents.GroupSelectedEvent groupSelectedEvent) {
thumbnailViewer.resetComponent(); thumbnailViewer.resetComponent();
if (groupSelectedEvent.getType() == FileType.IMAGE || groupSelectedEvent.getType() == FileType.VIDEO) { if (groupSelectedEvent.getType() == FileType.IMAGE || groupSelectedEvent.getType() == FileType.VIDEO) {
rightSplitPane.setTopComponent(thumbnailViewer); rightSplitPane.setTopComponent(thumbnailViewer);
if (groupSelectedEvent.getFiles().size() > 0) { if (groupSelectedEvent.getFiles().size() > 0) {
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new DiscoveryThumbnailChild(groupSelectedEvent.getFiles()))), true)); thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new DiscoveryThumbnailChildren(groupSelectedEvent.getFiles()))), true));
} else { } else {
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(Node.EMPTY), true)); thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(Node.EMPTY), true));
} }

View File

@ -66,6 +66,7 @@ public final class FileDiscoveryTestAction extends CallableSystemAction {
} }
FileDiscoveryDialog dialog = new FileDiscoveryDialog(WindowManager.getDefault().getMainWindow(), false, Case.getCurrentCase().getSleuthkitCase(), crDb); FileDiscoveryDialog dialog = new FileDiscoveryDialog(WindowManager.getDefault().getMainWindow(), false, Case.getCurrentCase().getSleuthkitCase(), crDb);
//register the dialog with the event bus
DiscoveryEvents.getDiscoveryEventBus().register(dialog); DiscoveryEvents.getDiscoveryEventBus().register(dialog);
// Display the dialog // Display the dialog
dialog.display(); dialog.display();

View File

@ -808,7 +808,7 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener
// Get the file sorting method // Get the file sorting method
FileSorter.SortingMethod fileSort = getFileSortingMethod(); FileSorter.SortingMethod fileSort = getFileSortingMethod();
SearchWorker searchWorker = new SearchWorker(centralRepoDb, searchButton, searchType, filters, groupingAttr, groupSortAlgorithm, fileSort); SearchWorker searchWorker = new SearchWorker(centralRepoDb, searchButton, filters, groupingAttr, groupSortAlgorithm, fileSort);
searchWorker.execute(); searchWorker.execute();
}//GEN-LAST:event_searchButtonActionPerformed }//GEN-LAST:event_searchButtonActionPerformed

View File

@ -22,12 +22,17 @@ import com.google.common.eventbus.Subscribe;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.openide.util.Exceptions; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType; import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/**
* Panel to display the list of groups which are provided by a search
*/
class GroupListPanel extends javax.swing.JPanel { class GroupListPanel extends javax.swing.JPanel {
private final static Logger logger = Logger.getLogger(GroupListPanel.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private LinkedHashMap<String, List<AbstractFile>> results = null; private LinkedHashMap<String, List<AbstractFile>> results = null;
private FileType resultType = null; private FileType resultType = null;
@ -39,6 +44,11 @@ class GroupListPanel extends javax.swing.JPanel {
initComponents(); initComponents();
} }
/**
* Subscribe to and reset the panel in response to SearchStartedEvents
*
* @param searchStartedEvent the SearchStartedEvent which was received
*/
@Subscribe @Subscribe
void handleSearchStartedEvent(DiscoveryEvents.SearchStartedEvent searchStartedEvent) { void handleSearchStartedEvent(DiscoveryEvents.SearchStartedEvent searchStartedEvent) {
resultType = searchStartedEvent.getType(); resultType = searchStartedEvent.getType();
@ -46,10 +56,15 @@ class GroupListPanel extends javax.swing.JPanel {
groupList.setListData(new String[0]); groupList.setListData(new String[0]);
} }
/**
* Subscribe to and update list of groups in response to
* SearchCompleteEvents
*
* @param searchCompleteEvent the SearchCompleteEvent which was recieved
*/
@Subscribe @Subscribe
void handleSearchCompleteEvent(DiscoveryEvents.SearchCompleteEvent searchCompleteEvent) { void handleSearchCompleteEvent(DiscoveryEvents.SearchCompleteEvent searchCompleteEvent) {
try { try {
resultType = searchCompleteEvent.getType();
results = searchCompleteEvent.getSearchResults().toLinkedHashMap(); results = searchCompleteEvent.getSearchResults().toLinkedHashMap();
Set<String> resultsKeySet = results.keySet(); Set<String> resultsKeySet = results.keySet();
groupList.setListData(resultsKeySet.toArray(new String[results.size()])); groupList.setListData(resultsKeySet.toArray(new String[results.size()]));
@ -59,7 +74,7 @@ class GroupListPanel extends javax.swing.JPanel {
validate(); validate();
repaint(); repaint();
} catch (FileSearchException ex) { } catch (FileSearchException ex) {
Exceptions.printStackTrace(ex); logger.log(Level.WARNING, "Error handling completed search results for file discovery, no results displayed", ex);
groupList.setListData(new String[0]); groupList.setListData(new String[0]);
} }
} }
@ -100,6 +115,11 @@ class GroupListPanel extends javax.swing.JPanel {
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
/**
* Respond to a group being selected by sending a GroupSelectedEvent
*
* @param evt the event which indicates a selection occurs in the list
*/
private void groupSelected(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_groupSelected private void groupSelected(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_groupSelected
if (!evt.getValueIsAdjusting() && results != null) { if (!evt.getValueIsAdjusting() && results != null) {
DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.GroupSelectedEvent(resultType, results.get(groupList.getSelectedValue()))); DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.GroupSelectedEvent(resultType, results.get(groupList.getSelectedValue())));

View File

@ -26,24 +26,34 @@ import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
/**
* SwingWorker to perform search on a background thread
*/
final class SearchWorker extends SwingWorker<Void, Void> { final class SearchWorker extends SwingWorker<Void, Void> {
private final static Logger logger = Logger.getLogger(SearchWorker.class.getName()); private final static Logger logger = Logger.getLogger(SearchWorker.class.getName());
private boolean runAnotherSearch = false;
private final JButton searchButtonToEnable; private final JButton searchButtonToEnable;
private final List<FileSearchFiltering.FileFilter> filters; private final List<FileSearchFiltering.FileFilter> filters;
private final FileSearch.AttributeType groupingAttr; private final FileSearch.AttributeType groupingAttr;
private final FileSorter.SortingMethod fileSort; private final FileSorter.SortingMethod fileSort;
private final FileGroup.GroupSortingAlgorithm groupSortAlgorithm; private final FileGroup.GroupSortingAlgorithm groupSortAlgorithm;
private final EamDb centralRepoDb; private final EamDb centralRepoDb;
private final FileType fileType;
SearchWorker(EamDb centralRepo, JButton searchButton, FileType type, List<FileSearchFiltering.FileFilter> searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { /**
* Create a SwingWorker which performs a search
*
* @param centralRepo the central repository being used for the search
* @param searchButton the search button to renable when the search is
* complete
* @param searchfilters the FileFilters to use for the search
* @param groupingAttribute the AttributeType to group by
* @param groupSort the Algorithm to sort groups by
* @param fileSortMethod the SortingMethod to use for files
*/
SearchWorker(EamDb centralRepo, JButton searchButton, List<FileSearchFiltering.FileFilter> searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) {
centralRepoDb = centralRepo; centralRepoDb = centralRepo;
searchButtonToEnable = searchButton; searchButtonToEnable = searchButton;
fileType = type;
filters = searchfilters; filters = searchfilters;
groupingAttr = groupingAttribute; groupingAttr = groupingAttribute;
groupSortAlgorithm = groupSort; groupSortAlgorithm = groupSort;
@ -52,11 +62,6 @@ final class SearchWorker extends SwingWorker<Void, Void> {
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
runAnotherSearch = true;
// For testing, allow the user to run different searches in loop
if (searchCancelled()) {
return null;
}
try { try {
// Make a list of attributes that we want to add values for. This ensures the // Make a list of attributes that we want to add values for. This ensures the
@ -74,7 +79,7 @@ final class SearchWorker extends SwingWorker<Void, Void> {
fileSort, fileSort,
attrsForGroupingAndSorting, attrsForGroupingAndSorting,
Case.getCurrentCase().getSleuthkitCase(), centralRepoDb); Case.getCurrentCase().getSleuthkitCase(), centralRepoDb);
DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.SearchCompleteEvent(fileType, results)); DiscoveryEvents.getDiscoveryEventBus().post(new DiscoveryEvents.SearchCompleteEvent(results));
} catch (FileSearchException ex) { } catch (FileSearchException ex) {
logger.log(Level.SEVERE, "Error running file search test", ex); logger.log(Level.SEVERE, "Error running file search test", ex);
} }
@ -83,18 +88,9 @@ final class SearchWorker extends SwingWorker<Void, Void> {
@Override @Override
protected void done() { protected void done() {
//If a search button was provided re-enable it
if (searchButtonToEnable != null) { if (searchButtonToEnable != null) {
searchButtonToEnable.setEnabled(true); searchButtonToEnable.setEnabled(true);
} }
} }
/**
* Check whether the user chose to run the search or cancel
*
* @return true if the search was cancelled, false otherwise
*/
boolean searchCancelled() {
return (!runAnotherSearch);
}
} }