7802 improve search in progress indicator and cancellation support

This commit is contained in:
William Schaefer 2021-07-30 16:36:09 -04:00
parent 6ffbf7841e
commit 0e5598f461
2 changed files with 41 additions and 22 deletions

View File

@ -1,7 +1,10 @@
DataSourceFilter.errorMessage.emptyDataSource=At least one data source must be selected. DataSourceFilter.errorMessage.emptyDataSource=At least one data source must be selected.
DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date. DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date.
DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected. DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected.
FileSearchPanel.cancelledSearch.text=Search Was Cancelled
FileSearchPanel.emptyNode.display.text=No results found. FileSearchPanel.emptyNode.display.text=No results found.
FileSearchPanel.searchingNode.display.text=Performing file search by attributes. Please wait.
FileSearchPanel.searchingPath.text=File Search In Progress
HashSearchFilter.errorMessage.emptyHash=Hash data is empty. HashSearchFilter.errorMessage.emptyHash=Hash data is empty.
HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters. HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters.
# {0} - hash data length # {0} - hash data length

View File

@ -65,7 +65,7 @@ class FileSearchPanel extends javax.swing.JPanel {
private final List<FileSearchFilter> filters = new ArrayList<>(); private final List<FileSearchFilter> filters = new ArrayList<>();
private static int resultWindowCount = 0; //keep track of result windows so they get unique names private static int resultWindowCount = 0; //keep track of result windows so they get unique names
private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text"); private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text");
private static SwingWorker<Void, Void> searchWorker = null; private static SwingWorker<TableFilterNode, Void> searchWorker = null;
enum EVENT { enum EVENT {
CHECKED CHECKED
@ -175,23 +175,30 @@ class FileSearchPanel extends javax.swing.JPanel {
* Action when the "Search" button is pressed. * Action when the "Search" button is pressed.
* *
*/ */
@NbBundle.Messages("FileSearchPanel.emptyNode.display.text=No results found.") @NbBundle.Messages({"FileSearchPanel.emptyNode.display.text=No results found.",
"FileSearchPanel.searchingNode.display.text=Performing file search by attributes. Please wait.",
"FileSearchPanel.searchingPath.text=File Search In Progress",
"FileSearchPanel.cancelledSearch.text=Search Was Cancelled"})
private void search() { private void search() {
if (searchWorker != null && searchWorker.isDone()) { if (searchWorker != null && searchWorker.isDone()) {
searchWorker.cancel(true); searchWorker.cancel(true);
} }
try { try {
if (this.isValidSearch()) { if (this.isValidSearch()) {
// change the cursor to "waiting cursor" for this operation
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// try to get the number of matches first // try to get the number of matches first
Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case
searchWorker = new SwingWorker<Void, Void>() { Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount);
String pathText = Bundle.FileSearchPanel_searchingPath_text();
final DataResultTopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
emptyNode, 0);
searchResultWin.requestActive(); // make it the active top component
searchResultWin.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
searchWorker = new SwingWorker<TableFilterNode, Void>() {
List<AbstractFile> contentList = null; List<AbstractFile> contentList = null;
TableFilterNode tableFilterNode = null;
@Override @Override
protected Void doInBackground() throws Exception { protected TableFilterNode doInBackground() throws Exception {
try { try {
SleuthkitCase tskDb = currentCase.getSleuthkitCase(); SleuthkitCase tskDb = currentCase.getSleuthkitCase();
contentList = tskDb.findAllFilesWhere(getQuery()); contentList = tskDb.findAllFilesWhere(getQuery());
@ -203,27 +210,23 @@ class FileSearchPanel extends javax.swing.JPanel {
if (contentList == null) { if (contentList == null) {
contentList = Collections.<AbstractFile>emptyList(); contentList = Collections.<AbstractFile>emptyList();
} }
if (contentList.isEmpty()) {
return new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
}
SearchNode sn = new SearchNode(contentList); SearchNode sn = new SearchNode(contentList);
tableFilterNode = new TableFilterNode(sn, true, sn.getName()); return new TableFilterNode(sn, true, sn.getName());
return null;
} }
@Override @Override
protected void done() { protected void done() {
String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText");
try { try {
get(); TableFilterNode tableFilterNode = get();
String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount); if (tableFilterNode == null) { //just incase this get() gets modified to return null or somehow can return null
String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText"); tableFilterNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
final TopComponent searchResultWin;
if (contentList.isEmpty() || tableFilterNode == null) {
Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
searchResultWin = DataResultTopComponent.createInstance(title, pathText,
emptyNode, 0);
} else {
searchResultWin = DataResultTopComponent.createInstance(title, pathText,
tableFilterNode, contentList.size());
} }
searchResultWin.setNode(tableFilterNode);
searchResultWin.requestActive(); // make it the active top component searchResultWin.requestActive(); // make it the active top component
/** /**
@ -241,12 +244,25 @@ class FileSearchPanel extends javax.swing.JPanel {
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, "Error while performing file search by attributes", ex); logger.log(Level.SEVERE, "Error while performing file search by attributes", ex);
} catch (CancellationException ex) { } catch (CancellationException ex) {
Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_cancelledSearch_text()), true);
searchResultWin.setNode(emptyNode);
pathText = Bundle.FileSearchPanel_cancelledSearch_text();
logger.log(Level.INFO, "File search by attributes was cancelled", ex); logger.log(Level.INFO, "File search by attributes was cancelled", ex);
} finally { } finally {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); searchResultWin.setPath(pathText);
searchResultWin.requestActive(); // make it the active top component
searchResultWin.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
} }
} }
}; };
searchResultWin.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("tcClosed") && !searchWorker.isDone() && evt.getOldValue() == null) {
searchWorker.cancel(true);
}
}
});
searchWorker.execute(); searchWorker.execute();
} else { } else {
throw new FilterValidationException( throw new FilterValidationException(