superior error state management

This commit is contained in:
Brian Sweeney 2018-08-21 12:37:22 -06:00
parent addb312dc0
commit 0946d96b94
5 changed files with 77 additions and 161 deletions

View File

@ -11,9 +11,6 @@
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 375]"/> <Dimension value="[412, 375]"/>
</Property> </Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[412, 375]"/>
</Property>
<Property name="resizable" type="boolean" value="false"/> <Property name="resizable" type="boolean" value="false"/>
</Properties> </Properties>
<SyntheticProperties> <SyntheticProperties>

View File

@ -52,19 +52,19 @@ import org.sleuthkit.datamodel.TskCoreException;
* logic. Nested within CommonFilesDialog. * logic. Nested within CommonFilesDialog.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class CommonAttributePanel extends javax.swing.JDialog { public final class CommonAttributePanel extends javax.swing.JDialog {
private static final Logger LOGGER = Logger.getLogger(CommonAttributePanel.class.getName()); private static final Logger LOGGER = Logger.getLogger(CommonAttributePanel.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Long NO_DATA_SOURCE_SELECTED = -1L; private static final Long NO_DATA_SOURCE_SELECTED = -1L;
private final UserInputErrorManager errorManager; private final UserInputErrorManager errorManager;
private boolean pictureViewCheckboxState; private boolean pictureViewCheckboxState;
private boolean documentsCheckboxState; private boolean documentsCheckboxState;
private int percentageThresholdValue = 20; private int percentageThresholdValue = 20;
/** /**
@ -90,18 +90,18 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
this.disableIntercaseSearch(); this.disableIntercaseSearch();
this.disablePercentageOptions(); this.disablePercentageOptions();
} }
this.errorManager = new UserInputErrorManager(); this.errorManager = new UserInputErrorManager();
} }
private static boolean isEamDbAvailable() { private static boolean isEamDbAvailable() {
try { try {
return EamDb.isEnabled() && return EamDb.isEnabled()
EamDb.getInstance() != null && && EamDb.getInstance() != null
EamDb.getInstance().getCases().size() > 1 && && EamDb.getInstance().getCases().size() > 1
Case.isCaseOpen() && && Case.isCaseOpen()
Case.getCurrentCase() != null && && Case.getCurrentCase() != null
EamDb.getInstance().getCase(Case.getCurrentCase()) != null; && EamDb.getInstance().getCase(Case.getCurrentCase()) != null;
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while checking for EamDB enabled.", ex); LOGGER.log(Level.SEVERE, "Unexpected exception while checking for EamDB enabled.", ex);
} }
@ -166,9 +166,10 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
filterByDocuments = true; filterByDocuments = true;
} }
} }
int percentageThreshold = CommonAttributePanel.this.percentageThresholdValue;
int percentageThreshold = 0; if (CommonAttributePanel.this.percentageThresholdCheck.isSelected()) {
if(CommonAttributePanel.this.percentageThresholdCheck.isSelected()){
String percentageThresholdAsString = CommonAttributePanel.this.percentageThreshold.getText(); String percentageThresholdAsString = CommonAttributePanel.this.percentageThreshold.getText();
percentageThreshold = Integer.parseInt(percentageThresholdAsString); percentageThreshold = Integer.parseInt(percentageThresholdAsString);
} }
@ -245,7 +246,6 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
}.execute(); }.execute();
} }
/** /**
* Sets up the data sources dropdown and returns the data sources map for * Sets up the data sources dropdown and returns the data sources map for
* future usage. * future usage.
@ -278,8 +278,7 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
boolean multipleDataSources = this.caseHasMultipleSources(); boolean multipleDataSources = this.caseHasMultipleSources();
CommonAttributePanel.this.intraCasePanel.rigForMultipleDataSources(multipleDataSources); CommonAttributePanel.this.intraCasePanel.rigForMultipleDataSources(multipleDataSources);
//TODO this should be attached to the intra/inter radio buttons CommonAttributePanel.this.updateErrorTextAndSearchBox();
CommonAttributePanel.this.setSearchButtonEnabled(true);
} }
} }
@ -625,41 +624,27 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
}//GEN-LAST:event_cancelButtonActionPerformed }//GEN-LAST:event_cancelButtonActionPerformed
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
this.manageFileTypeCheckBoxState(); this.handleFileTypeCheckBoxState();
this.updateErrorTextAndSearchBox();
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed }//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
this.manageFileTypeCheckBoxState(); this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed }//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
this.updateErrorTextAndSearchBox(); this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed }//GEN-LAST:event_pictureVideoCheckboxActionPerformed
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
this.updateErrorTextAndSearchBox(); this.handleFileTypeCheckBoxState();
}//GEN-LAST:event_documentsCheckboxActionPerformed }//GEN-LAST:event_documentsCheckboxActionPerformed
private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_intraCaseRadioActionPerformed private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_intraCaseRadioActionPerformed
((java.awt.CardLayout) this.layoutPanel.getLayout()).first(this.layoutPanel); ((java.awt.CardLayout) this.layoutPanel.getLayout()).first(this.layoutPanel);
handleIntraCaseSearchCriteriaChanged();
}//GEN-LAST:event_intraCaseRadioActionPerformed }//GEN-LAST:event_intraCaseRadioActionPerformed
public void handleIntraCaseSearchCriteriaChanged() {
if (this.areIntraCaseSearchCriteriaMet()) {
this.searchButton.setEnabled(true);
this.hideErrorMessages();
} else {
this.searchButton.setEnabled(false);
this.hideErrorMessages();
this.showIntraCaseErrorMessage();
}
}
private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interCaseRadioActionPerformed private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interCaseRadioActionPerformed
((java.awt.CardLayout) this.layoutPanel.getLayout()).last(this.layoutPanel); ((java.awt.CardLayout) this.layoutPanel.getLayout()).last(this.layoutPanel);
handleInterCaseSearchCriteriaChanged();
}//GEN-LAST:event_interCaseRadioActionPerformed }//GEN-LAST:event_interCaseRadioActionPerformed
private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
@ -667,47 +652,35 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
}//GEN-LAST:event_formWindowClosed }//GEN-LAST:event_formWindowClosed
private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_percentageThresholdCheckActionPerformed private void percentageThresholdCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_percentageThresholdCheckActionPerformed
if(this.percentageThresholdCheck.isSelected()){ if (this.percentageThresholdCheck.isSelected()) {
this.percentageThreshold.setEnabled(true); this.percentageThreshold.setEnabled(true);
} else { } else {
this.percentageThreshold.setEnabled(false); this.percentageThreshold.setEnabled(false);
} }
this.handleFrequencyPercentageCriteriaMet(); this.handleFrequencyPercentageState();
}//GEN-LAST:event_percentageThresholdCheckActionPerformed }//GEN-LAST:event_percentageThresholdCheckActionPerformed
private void percentageThresholdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_percentageThresholdActionPerformed private void percentageThresholdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_percentageThresholdActionPerformed
String percentageString = this.percentageThreshold.getText(); String percentageString = this.percentageThreshold.getText();
Integer percentage = null; Integer percentage = null;
try{ try {
percentage = Integer.parseInt(percentageString); percentage = Integer.parseInt(percentageString);
this.percentageThresholdValue = percentage; this.percentageThresholdValue = percentage;
} catch(Exception e){ } catch (Exception e) {
this.percentageThresholdValue = -1; this.percentageThresholdValue = -1;
} }
this.percentageThresholdValue = percentage.intValue(); this.percentageThresholdValue = percentage.intValue();
this.handleFrequencyPercentageCriteriaMet(); this.handleFrequencyPercentageState();
}//GEN-LAST:event_percentageThresholdActionPerformed }//GEN-LAST:event_percentageThresholdActionPerformed
public void handleInterCaseSearchCriteriaChanged() {
if (this.areInterCaseSearchCriteriaMet()) {
this.searchButton.setEnabled(true);
this.hideErrorMessages();
} else {
this.searchButton.setEnabled(false);
this.hideErrorMessages();
this.showInterCaseErrorMessage();
}
}
private void updateErrorTextAndSearchBox() { private void updateErrorTextAndSearchBox() {
if(this.errorManager.anyErrors()){ if (this.errorManager.anyErrors()) {
this.searchButton.setEnabled(false); this.searchButton.setEnabled(false);
//grab the first error error and show it //grab the first error error and show it
this.errorText.setText(this.errorManager.getErrors().get(0)); this.errorText.setText(this.errorManager.getErrors().get(0));
@ -716,17 +689,21 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
this.searchButton.setEnabled(true); this.searchButton.setEnabled(true);
this.errorText.setVisible(false); this.errorText.setVisible(false);
} }
if (!this.pictureVideoCheckbox.isSelected() && !this.documentsCheckbox.isSelected() && !this.allFileCategoriesRadioButton.isSelected()) {
this.searchButton.setEnabled(false);
this.errorText.setVisible(true);
} else {
this.searchButton.setEnabled(true);
this.errorText.setVisible(false);
}
} }
private void manageFileTypeCheckBoxState() { private void enablePercentageOptions() {
this.percentageThreshold.setEnabled(true);
this.percentageThresholdCheck.setEnabled(true);
this.percentageThresholdCheck.setSelected(true);
}
private void disablePercentageOptions() {
this.percentageThreshold.setEnabled(false);
this.percentageThresholdCheck.setEnabled(false);
this.percentageThresholdCheck.setSelected(false);
}
private void handleFileTypeCheckBoxState() {
this.pictureViewCheckboxState = this.pictureVideoCheckbox.isSelected(); this.pictureViewCheckboxState = this.pictureVideoCheckbox.isSelected();
this.documentsCheckboxState = this.documentsCheckbox.isSelected(); this.documentsCheckboxState = this.documentsCheckbox.isSelected();
@ -734,6 +711,8 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
if (this.allFileCategoriesRadioButton.isSelected()) { if (this.allFileCategoriesRadioButton.isSelected()) {
this.pictureVideoCheckbox.setEnabled(false); this.pictureVideoCheckbox.setEnabled(false);
this.documentsCheckbox.setEnabled(false); this.documentsCheckbox.setEnabled(false);
this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY, false);
} }
if (this.selectedFileCategoriesButton.isSelected()) { if (this.selectedFileCategoriesButton.isSelected()) {
@ -744,8 +723,24 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
this.pictureVideoCheckbox.setEnabled(true); this.pictureVideoCheckbox.setEnabled(true);
this.documentsCheckbox.setEnabled(true); this.documentsCheckbox.setEnabled(true);
this.updateErrorTextAndSearchBox(); if (!this.pictureVideoCheckbox.isSelected() && !this.documentsCheckbox.isSelected() && !this.allFileCategoriesRadioButton.isSelected()) {
this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY, true);
} else {
this.errorManager.setError(UserInputErrorManager.NO_FILE_CATEGORIES_SELECTED_KEY, false);
}
} }
this.updateErrorTextAndSearchBox();
}
private void handleFrequencyPercentageState() {
if (this.percentageThresholdValue > 0 && this.percentageThresholdValue <= 100) {
this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, false);
} else {
this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, true);
}
this.updateErrorTextAndSearchBox();
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
@ -771,50 +766,4 @@ public final class CommonAttributePanel extends javax.swing.JDialog {
private javax.swing.JButton searchButton; private javax.swing.JButton searchButton;
private javax.swing.JRadioButton selectedFileCategoriesButton; private javax.swing.JRadioButton selectedFileCategoriesButton;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
void setSearchButtonEnabled(boolean enabled) {
this.searchButton.setEnabled(enabled);
}
private boolean areIntraCaseSearchCriteriaMet() {
return this.intraCasePanel.areSearchCriteriaMet();
}
private boolean areInterCaseSearchCriteriaMet() {
return this.interCasePanel.areSearchCriteriaMet();
}
private void hideErrorMessages() {
this.errorText.setVisible(false);
}
private void showIntraCaseErrorMessage() {
this.errorText.setText(this.intraCasePanel.getErrorMessage());
this.errorText.setVisible(true);
}
private void showInterCaseErrorMessage() {
this.errorText.setText(this.interCasePanel.getErrorMessage());
this.errorText.setVisible(true);
}
private void enablePercentageOptions() {
this.percentageThreshold.setEnabled(true);
this.percentageThresholdCheck.setEnabled(true);
this.percentageThresholdCheck.setSelected(true);
}
private void disablePercentageOptions() {
this.percentageThreshold.setEnabled(false);
this.percentageThresholdCheck.setEnabled(false);
this.percentageThresholdCheck.setSelected(false);
}
private void handleFrequencyPercentageCriteriaMet() {
if(this.percentageThresholdValue > 0 && this.percentageThresholdValue<= 100){
this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, false);
} else {
this.errorManager.setError(UserInputErrorManager.FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, true);
}
}
} }

View File

@ -24,7 +24,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.swing.ComboBoxModel; import javax.swing.ComboBoxModel;
import org.openide.util.NbBundle;
/** /**
* UI controls for Common Files Search scenario where the user intends to find * UI controls for Common Files Search scenario where the user intends to find
@ -39,9 +38,7 @@ public class InterCasePanel extends javax.swing.JPanel {
private ComboBoxModel<String> casesList = new DataSourceComboBoxModel(); private ComboBoxModel<String> casesList = new DataSourceComboBoxModel();
private final Map<Integer, String> caseMap; private final Map<Integer, String> caseMap;
private String errorMessage;
//True if we are looking in any or all cases, //True if we are looking in any or all cases,
// false if we must find matches in a given case plus the current case // false if we must find matches in a given case plus the current case
private boolean anyCase; private boolean anyCase;
@ -51,7 +48,6 @@ public class InterCasePanel extends javax.swing.JPanel {
*/ */
public InterCasePanel() { public InterCasePanel() {
initComponents(); initComponents();
this.errorMessage = "";
this.caseMap = new HashMap<>(); this.caseMap = new HashMap<>();
this.anyCase = true; this.anyCase = true;
} }
@ -64,10 +60,6 @@ public class InterCasePanel extends javax.swing.JPanel {
} }
} }
String getErrorMessage(){
return this.errorMessage;
}
/** /**
* This method is called from within the constructor to initialize the form. * This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always * WARNING: Do NOT modify this code. The content of this method is always
@ -189,16 +181,4 @@ public class InterCasePanel extends javax.swing.JPanel {
return InterCasePanel.NO_CASE_SELECTED; return InterCasePanel.NO_CASE_SELECTED;
} }
@NbBundle.Messages({
"InterCasePanel.showInterCaseErrorMessage.message=Cannot run intercase correlation search: no cases in Central Repository."
})
boolean areSearchCriteriaMet() {
if(this.caseMap.isEmpty()){
this.errorMessage = Bundle.InterCasePanel_showInterCaseErrorMessage_message();
return false;
} else {
return true;
}
}
} }

View File

@ -24,8 +24,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.swing.ComboBoxModel; import javax.swing.ComboBoxModel;
import org.openide.util.NbBundle;
/** /**
* UI controls for Common Files Search scenario where the user intends to find * UI controls for Common Files Search scenario where the user intends to find
* common files between datasources. It is an inner panel which provides the ability * common files between datasources. It is an inner panel which provides the ability
@ -40,15 +38,12 @@ public class IntraCasePanel extends javax.swing.JPanel {
private boolean singleDataSource; private boolean singleDataSource;
private ComboBoxModel<String> dataSourcesList = new DataSourceComboBoxModel(); private ComboBoxModel<String> dataSourcesList = new DataSourceComboBoxModel();
private final Map<Long, String> dataSourceMap; private final Map<Long, String> dataSourceMap;
private String errorMessage;
/** /**
* Creates new form IntraCasePanel * Creates new form IntraCasePanel
*/ */
public IntraCasePanel() { public IntraCasePanel() {
initComponents(); initComponents();
this.errorMessage = "";
this.dataSourceMap = new HashMap<>(); this.dataSourceMap = new HashMap<>();
this.singleDataSource = true; this.singleDataSource = true;
} }
@ -175,20 +170,4 @@ public class IntraCasePanel extends javax.swing.JPanel {
this.dataSourceMap.clear(); this.dataSourceMap.clear();
this.dataSourceMap.putAll(dataSourceMap); this.dataSourceMap.putAll(dataSourceMap);
} }
@NbBundle.Messages({
"IntraCasePanel.areSearchCriteriaMet.message=Cannot run intra-case correlation search."
})
boolean areSearchCriteriaMet() {
if(this.dataSourceMap.isEmpty()){
this.errorMessage = Bundle.IntraCasePanel_areSearchCriteriaMet_message();
return false;
} else {
return true;
}
}
String getErrorMessage() {
return this.errorMessage;
}
} }

View File

@ -29,13 +29,24 @@ import java.util.stream.Collectors;
*/ */
class UserInputErrorManager { class UserInputErrorManager {
static final int FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY = 1; static final int FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY = 1;
static final int NO_FILE_CATEGORIES_SELECTED_KEY = 2;
private final Map<Integer, ErrorMessage> currentErrors; private final Map<Integer, ErrorMessage> currentErrors;
/**
* Construct a new ErrorManager which can be used to track the status
* of all known error states, retrieve error messages, and determine if
* anything is in an error state.
*/
UserInputErrorManager (){ UserInputErrorManager (){
//when new errors are needed for the dialog, define a key and a value
// and add them to the map.
this.currentErrors = new HashMap<>(); this.currentErrors = new HashMap<>();
this.currentErrors.put(FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, new ErrorMessage("Frequency percentage must be greater than zero and less than or equal to 100.")); this.currentErrors.put(FREQUENCY_PERCENTAGE_OUT_OF_RANGE_KEY, new ErrorMessage("Frequency percentage must be greater than zero and less than or equal to 100."));
this.currentErrors.put(NO_FILE_CATEGORIES_SELECTED_KEY, new ErrorMessage("No file categories are included in the search."));
} }
/** /**