From 9a537d1e39886689a253bb32ba25e2dd1a1bd6d3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 11 Jan 2017 13:18:50 -0500 Subject: [PATCH 01/73] 2197-basic profiles option panel added --- .../corecomponents/AutopsyOptionsPanel.form | 114 +------- .../corecomponents/AutopsyOptionsPanel.java | 183 +----------- .../autopsy/corecomponents/Bundle.properties | 8 +- .../corecomponents/Bundle_ja.properties | 4 - .../MultiUserSettingsPanelController.java | 2 +- .../autopsy/ingest/Bundle.properties | 8 + .../autopsy/ingest/Bundle_ja.properties | 4 + .../autopsy/ingest/IngestOptionsPanel.form | 40 +++ .../autopsy/ingest/IngestOptionsPanel.java | 117 ++++++++ .../ingest/IngestOptionsPanelController.java | 113 ++++++++ .../autopsy/ingest/IngestSettingsPanel.form | 176 ++++++++++++ .../autopsy/ingest/IngestSettingsPanel.java | 272 ++++++++++++++++++ ...ngestFilterDefsOptionsPanelController.java | 8 - .../interestingitems/FilesSetDefsPanel.java | 6 +- 14 files changed, 745 insertions(+), 310 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form index 5a169b7329..5484d65080 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form @@ -51,36 +51,16 @@ + - - - - - - - - - - - - - - - - - - - - - - + + - - + @@ -142,24 +122,7 @@ - - - - - - - - - - - - - - - - - - + @@ -264,73 +227,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index de9a6e5429..7a0d9c6569 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -18,13 +18,7 @@ */ package org.sleuthkit.autopsy.corecomponents; -import java.text.NumberFormat; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JFormattedTextField; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.NbBundle; import org.sleuthkit.autopsy.core.UserPreferences; /** @@ -34,65 +28,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { AutopsyOptionsPanel() { initComponents(); - int availableProcessors = Runtime.getRuntime().availableProcessors(); - Integer fileIngestThreadCountChoices[]; - int recommendedFileIngestThreadCount; - if (availableProcessors >= 16) { - fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6, 8, 12, 16}; - if (availableProcessors >= 18) { - recommendedFileIngestThreadCount = 16; - } else { - recommendedFileIngestThreadCount = 12; - } - } else if (availableProcessors >= 12 && availableProcessors <= 15) { - fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6, 8, 12}; - if (availableProcessors >= 14) { - recommendedFileIngestThreadCount = 12; - } else { - recommendedFileIngestThreadCount = 8; - } - } else if (availableProcessors >= 8 && availableProcessors <= 11) { - fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6, 8}; - if (availableProcessors >= 10) { - recommendedFileIngestThreadCount = 8; - } else { - recommendedFileIngestThreadCount = 6; - } - } else if (availableProcessors >= 6 && availableProcessors <= 7) { - fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6}; - recommendedFileIngestThreadCount = 4; - } else if (availableProcessors >= 4 && availableProcessors <= 5) { - fileIngestThreadCountChoices = new Integer[]{1, 2, 4}; - recommendedFileIngestThreadCount = 2; - } else if (availableProcessors >= 2 && availableProcessors <= 3) { - fileIngestThreadCountChoices = new Integer[]{1, 2}; - recommendedFileIngestThreadCount = 1; - } else { - fileIngestThreadCountChoices = new Integer[]{1}; - recommendedFileIngestThreadCount = 1; - } - numberOfFileIngestThreadsComboBox.setModel(new DefaultComboBoxModel<>(fileIngestThreadCountChoices)); - restartRequiredLabel.setText(NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.restartRequiredLabel.text", recommendedFileIngestThreadCount)); - // TODO listen to changes in form fields and call controller.changed() - DocumentListener docListener = new DocumentListener() { - - @Override - public void insertUpdate(DocumentEvent e) { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - - @Override - public void removeUpdate(DocumentEvent e) { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - - @Override - public void changedUpdate(DocumentEvent e) { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - }; - this.jFormattedTextFieldProcTimeOutHrs.getDocument().addDocumentListener(docListener); - } void load() { @@ -106,20 +41,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { boolean useLocalTime = UserPreferences.displayTimesInLocalTime(); useLocalTimeRB.setSelected(useLocalTime); useGMTTimeRB.setSelected(!useLocalTime); - numberOfFileIngestThreadsComboBox.setSelectedItem(UserPreferences.numberOfFileIngestThreads()); - if (UserPreferences.getIsTimeOutEnabled()) { - // user specified time out - jCheckBoxEnableProcTimeout.setSelected(true); - jFormattedTextFieldProcTimeOutHrs.setEditable(true); - int timeOutHrs = UserPreferences.getProcessTimeOutHrs(); - jFormattedTextFieldProcTimeOutHrs.setValue((long) timeOutHrs); - } else { - // never time out - jCheckBoxEnableProcTimeout.setSelected(false); - jFormattedTextFieldProcTimeOutHrs.setEditable(false); - int timeOutHrs = UserPreferences.getProcessTimeOutHrs(); - jFormattedTextFieldProcTimeOutHrs.setValue((long) timeOutHrs); - } } void store() { @@ -129,14 +50,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected()); UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected()); UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected()); - UserPreferences.setNumberOfFileIngestThreads((Integer) numberOfFileIngestThreadsComboBox.getSelectedItem()); - - UserPreferences.setIsTimeOutEnabled(jCheckBoxEnableProcTimeout.isSelected()); - if (jCheckBoxEnableProcTimeout.isSelected()) { - // only store time out if it is enabled - long timeOutHrs = (long) jFormattedTextFieldProcTimeOutHrs.getValue(); - UserPreferences.setProcessTimeOutHrs((int) timeOutHrs); - } } boolean valid() { @@ -164,13 +77,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { jLabelHideKnownFiles = new javax.swing.JLabel(); dataSourcesHideKnownCB = new javax.swing.JCheckBox(); viewsHideKnownCB = new javax.swing.JCheckBox(); - jLabelNumThreads = new javax.swing.JLabel(); - numberOfFileIngestThreadsComboBox = new javax.swing.JComboBox<>(); - restartRequiredLabel = new javax.swing.JLabel(); - jLabelSetProcessTimeOut = new javax.swing.JLabel(); - jCheckBoxEnableProcTimeout = new javax.swing.JCheckBox(); - jLabelProcessTimeOutUnits = new javax.swing.JLabel(); - jFormattedTextFieldProcTimeOutHrs = new JFormattedTextField(NumberFormat.getIntegerInstance()); dataSourcesHideSlackCB = new javax.swing.JCheckBox(); viewsHideSlackCB = new javax.swing.JCheckBox(); jLabelHideSlackFiles = new javax.swing.JLabel(); @@ -231,35 +137,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabelNumThreads, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelNumThreads.text")); // NOI18N - - numberOfFileIngestThreadsComboBox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - numberOfFileIngestThreadsComboBoxActionPerformed(evt); - } - }); - - restartRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(restartRequiredLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.restartRequiredLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSetProcessTimeOut, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSetProcessTimeOut.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jCheckBoxEnableProcTimeout, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jCheckBoxEnableProcTimeout.text")); // NOI18N - jCheckBoxEnableProcTimeout.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jCheckBoxEnableProcTimeoutActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelProcessTimeOutUnits, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelProcessTimeOutUnits.text")); // NOI18N - - jFormattedTextFieldProcTimeOutHrs.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jFormattedTextFieldProcTimeOutHrs.text")); // NOI18N - jFormattedTextFieldProcTimeOutHrs.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jFormattedTextFieldProcTimeOutHrsActionPerformed(evt); - } - }); - org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -285,29 +162,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabelTimeDisplay) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(restartRequiredLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelTimeDisplay) - .addComponent(jLabelNumThreads) - .addComponent(jLabelSetProcessTimeOut) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(useLocalTimeRB) - .addComponent(useGMTTimeRB) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jCheckBoxEnableProcTimeout) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabelProcessTimeOutUnits))))) - .addGap(213, 213, 213))) - .addContainerGap()) + .addComponent(useLocalTimeRB) + .addComponent(useGMTTimeRB)))) + .addContainerGap(512, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabelHideKnownFiles) @@ -357,21 +218,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { .addComponent(useLocalTimeRB) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(useGMTTimeRB) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabelNumThreads) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(restartRequiredLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabelSetProcessTimeOut) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jCheckBoxEnableProcTimeout) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabelProcessTimeOutUnits))) - .addContainerGap(49, Short.MAX_VALUE)) + .addContainerGap(148, Short.MAX_VALUE)) ); jScrollPane1.setViewportView(jPanel1); @@ -388,11 +235,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents - private void jCheckBoxEnableProcTimeoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxEnableProcTimeoutActionPerformed - jFormattedTextFieldProcTimeOutHrs.setEditable(jCheckBoxEnableProcTimeout.isSelected()); - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_jCheckBoxEnableProcTimeoutActionPerformed - private void useBestViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useBestViewerRBActionPerformed firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_useBestViewerRBActionPerformed @@ -417,14 +259,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_useGMTTimeRBActionPerformed - private void numberOfFileIngestThreadsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numberOfFileIngestThreadsComboBoxActionPerformed - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_numberOfFileIngestThreadsComboBoxActionPerformed - - private void jFormattedTextFieldProcTimeOutHrsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed - private void dataSourcesHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideSlackCBActionPerformed firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_dataSourcesHideSlackCBActionPerformed @@ -438,20 +272,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { private javax.swing.ButtonGroup buttonGroup3; private javax.swing.JCheckBox dataSourcesHideKnownCB; private javax.swing.JCheckBox dataSourcesHideSlackCB; - private javax.swing.JCheckBox jCheckBoxEnableProcTimeout; - private javax.swing.JFormattedTextField jFormattedTextFieldProcTimeOutHrs; private javax.swing.JLabel jLabelHideKnownFiles; private javax.swing.JLabel jLabelHideSlackFiles; - private javax.swing.JLabel jLabelNumThreads; - private javax.swing.JLabel jLabelProcessTimeOutUnits; private javax.swing.JLabel jLabelSelectFile; - private javax.swing.JLabel jLabelSetProcessTimeOut; private javax.swing.JLabel jLabelTimeDisplay; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JRadioButton keepCurrentViewerRB; - private javax.swing.JComboBox numberOfFileIngestThreadsComboBox; - private javax.swing.JLabel restartRequiredLabel; private javax.swing.JRadioButton useBestViewerRB; private javax.swing.JRadioButton useGMTTimeRB; private javax.swing.JRadioButton useLocalTimeRB; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 7f5cde3851..b7a7349148 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -27,7 +27,7 @@ Format_OperatingSystem_Value={0} version {1} running on {2} LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2016.
URL_ON_IMG=http://www.sleuthkit.org/ -URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.3/ +URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.2/ FILE_FOR_LOCAL_HELP=file:/// INDEX_FOR_LOCAL_HELP=/docs/index.html @@ -139,11 +139,9 @@ AutopsyOptionsPanel.useGMTTimeRB.text=Use GMT AutopsyOptionsPanel.useLocalTimeRB.text=Use local time zone AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=For example, stay in Hex view when a JPEG is selected. AutopsyOptionsPanel.keepCurrentViewerRB.text=Stay on the same file viewer -AutopsyOptionsPanel.restartRequiredLabel.text=For this computer, a maximum of {0} file ingest threads should be used. Application restart required to take effect. AutopsyOptionsPanel.jLabelSelectFile.text=When selecting a file: AutopsyOptionsPanel.jLabelHideKnownFiles.text=Hide known files (i.e. those in the NIST NSRL) in the: AutopsyOptionsPanel.jLabelTimeDisplay.text=When displaying times: -AutopsyOptionsPanel.jLabelNumThreads.text=Number of threads to use for file ingest: FXVideoPanel.progress.bufferingCancelled=media buffering was canceled FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk @@ -158,10 +156,6 @@ MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database por MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort=Invalid message service port number MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number MultiUserSettingsPanel.validationErrMsg.invalidMessgeServiceURI=Message service host and/or port not valid -AutopsyOptionsPanel.jCheckBoxEnableProcTimeout.text= -AutopsyOptionsPanel.jFormattedTextFieldProcTimeOutHrs.text=60 -AutopsyOptionsPanel.jLabelProcessTimeOutUnits.text=hour(s) -AutopsyOptionsPanel.jLabelSetProcessTimeOut.text=Enable timeout to allow modules to automatically terminate after a set amount of time\: DataContentViewerHex.goToOffsetLabel.text=Jump to Offset DataContentViewerHex.goToOffsetTextField.text= DataContentViewerHex.goToOffsetTextField.msgDlg=Invalid Offset\: {0} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties index b5977466ba..abb22c4ce8 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties @@ -116,11 +116,9 @@ AutopsyOptionsPanel.useGMTTimeRB.text=GMT\u3092\u4f7f\u7528 AutopsyOptionsPanel.useLocalTimeRB.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528 AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002 AutopsyOptionsPanel.keepCurrentViewerRB.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528 -AutopsyOptionsPanel.restartRequiredLabel.text=\u3053\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u3067\u306f\u6700\u5927{0}\u306e\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u7528\u3059\u3079\u304d\u3067\u3059\u3002\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u518d\u8d77\u52d5\u304c\u5fc5\u8981\u3067\u3059\u3002 AutopsyOptionsPanel.jLabelSelectFile.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a AutopsyOptionsPanel.jLabelHideKnownFiles.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NIST NSRL\u5185\u306e\uff09\u3092\u6b21\u306b\u96a0\u3059\uff1a AutopsyOptionsPanel.jLabelTimeDisplay.text=\u6642\u9593\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a -AutopsyOptionsPanel.jLabelNumThreads.text=\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306b\u4f7f\u7528\u3059\u308b\u30b9\u30ec\u30c3\u30c9\u6570\uff1a FXVideoPanel.progress.bufferingCancelled=\u30e1\u30c7\u30a3\u30a2\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u304c\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f FXVideoPanel.progress.bufferingInterrupted=\u30e1\u30c7\u30a3\u30a2\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3057\u305f FXVideoPanel.progress.errorWritingVideoToDisk=\u30d3\u30c7\u30aa\u3092\u30c7\u30a3\u30b9\u30af\u3078\u66f8\u304d\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f @@ -135,8 +133,6 @@ MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=\u7121\u52b9\u306a\u MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort=\u7121\u52b9\u306a\u30e1\u30c3\u30bb\u30fc\u30b8\u30b5\u30fc\u30d3\u30b9\u30dd\u30fc\u30c8\u756a\u53f7 MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort=\u7121\u52b9\u306aSolr\u30b5\u30fc\u30d0\u30fc\u30dd\u30fc\u30c8\u756a\u53f7 MultiUserSettingsPanel.validationErrMsg.invalidMessgeServiceURI=\u7121\u52b9\u306a\u30e1\u30c3\u30bb\u30fc\u30b8\u30b5\u30fc\u30d3\u30b9\u30db\u30b9\u30c8\u3084\u30dd\u30fc\u30c8\u756a\u53f7 -AutopsyOptionsPanel.jLabelProcessTimeOutUnits.text=\u6642\u9593 -AutopsyOptionsPanel.jLabelSetProcessTimeOut.text=\u4e00\u5b9a\u306e\u6642\u9593\u304c\u904e\u304e\u305f\u5f8c\u306b\u81ea\u52d5\u7684\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u505c\u6b62\u3067\u304d\u308b\u3088\u3046\u306b\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u3092\u6709\u52b9\u5316\uff1a DataContentViewerHex.goToOffsetLabel.text=\u30aa\u30d5\u30bb\u30c3\u30c8\u306b\u30b8\u30e3\u30f3\u30d7 DataContentViewerHex.goToOffsetTextField.msgDlg=\u7121\u52b9\u306a\u30aa\u30d5\u30bb\u30c3\u30c8\uff1a{0} DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue=\u8a08\u7b97\u3055\u308c\u305f\u30aa\u30d5\u30bb\u30c3\u30c8\u306b\u30b8\u30e3\u30f3\u30d7\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanelController.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanelController.java index 80b3f9bb58..c98c4e0459 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MultiUserSettingsPanelController.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Multi_User_Settings", iconBase = "org/sleuthkit/autopsy/images/User-Group-icon-green32.png", - position = 2, + position = 3, keywords = "#OptionsCategory_Keywords_Multi_User_Options", keywordsCategory = "Multi-user") public final class MultiUserSettingsPanelController extends OptionsPanelController { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 1a58c266b2..9e512e392c 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -114,3 +114,11 @@ IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings IngestJobSettingsPanel.pastJobsButton.text=History IngestJobSettingsPanel.fileIngestFilterLabel.text=Run ingest modules on: +OptionsCategory_Name_IngestOptions=Ingest Options +OptionsCategory_Keywords_IngestOptions=IngestOptions +IngestSettingsPanel.jLabelProcessTimeOutUnits.text=hour(s) +IngestSettingsPanel.jFormattedTextFieldProcTimeOutHrs.text=60 +IngestSettingsPanel.jCheckBoxEnableProcTimeout.text= +IngestSettingsPanel.jLabelSetProcessTimeOut.text=Enable timeout to allow modules to automatically terminate after a set amount of time: +IngestSettingsPanel.restartRequiredLabel.text=For this computer, a maximum of {0} file ingest threads should be used. Application restart required to take effect. +IngestSettingsPanel.jLabelNumThreads.text=Number of threads to use for file ingest: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index 6ecb763bc2..eb2713faa1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -111,3 +111,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=\u30c7\u30a3\u30b9\u30af\u30b9\u30da\ IngestJob.cancelReason.caseClosed.text=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u307e\u3057\u305f IngestJobSettingsPanel.globalSettingsButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 IngestJobSettingsPanel.globalSettingsButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 +IngestSettingsPanel.jLabelNumThreads.text=\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306b\u4f7f\u7528\u3059\u308b\u30b9\u30ec\u30c3\u30c9\u6570\uff1a +IngestSettingsPanel.jLabelProcessTimeOutUnits.text=\u6642\u9593 +IngestSettingsPanel.jLabelSetProcessTimeOut.text=\u4e00\u5b9a\u306e\u6642\u9593\u304c\u904e\u304e\u305f\u5f8c\u306b\u81ea\u52d5\u7684\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u505c\u6b62\u3067\u304d\u308b\u3088\u3046\u306b\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u3092\u6709\u52b9\u5316\uff1a +IngestSettingsPanel.restartRequiredLabel.text=\u3053\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u3067\u306f\u6700\u5927{0}\u306e\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u7528\u3059\u3079\u304d\u3067\u3059\u3002\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u518d\u8d77\u52d5\u304c\u5fc5\u8981\u3067\u3059\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.form new file mode 100644 index 0000000000..b8ae7ca14a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.form @@ -0,0 +1,40 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java new file mode 100644 index 0000000000..b3ff6aff36 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -0,0 +1,117 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 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.ingest; + +import java.beans.PropertyChangeListener; +import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TYPE; + +/** + * Global options panel for keyword searching. + */ +class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { + + private FilesSetDefsPanel filterPanel; + private IngestSettingsPanel settingsPanel; + + + IngestOptionsPanel() { + initComponents(); + customizeComponents(); + } + + private void customizeComponents() { + setName("Temporary Name"); + filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); + settingsPanel = new IngestSettingsPanel(); + tabbedPane.insertTab("Settings", null, + settingsPanel, "Tootip 1", 0); + tabbedPane.insertTab("Filters", null, + filterPanel, "Tooltip 2", 1); + + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener l) { + filterPanel.addPropertyChangeListener(l); + settingsPanel.addPropertyChangeListener(l); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + filterPanel.removePropertyChangeListener(l); + settingsPanel.removePropertyChangeListener(l); + } + + @Override + public void saveSettings() { + filterPanel.store(); + settingsPanel.store(); + } + + @Override + public void store() { + saveSettings(); + } + + @Override + public void load() { + filterPanel.load(); + settingsPanel.load(); + } + + boolean valid() { + return true; + } + + public void cancel() { + + } + + /** + * 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 + * regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + tabbedPane = new javax.swing.JTabbedPane(); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 824, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 543, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTabbedPane tabbedPane; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java new file mode 100644 index 0000000000..a0c2a39de1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java @@ -0,0 +1,113 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2016 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.ingest; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javax.swing.JComponent; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; + +@OptionsPanelController.TopLevelRegistration( + categoryName = "#OptionsCategory_Name_IngestOptions", + iconBase = "org/sleuthkit/autopsy/images/file_ingest_filter32x32.png", + position = 2, + keywords = "#OptionsCategory_Keywords_IngestOptions", + keywordsCategory = "IngestOptions") + +public class IngestOptionsPanelController extends OptionsPanelController { + + private IngestOptionsPanel panel; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private boolean changed; + + @Override + public void update() { + getPanel().load(); + changed = false; + } + + private IngestOptionsPanel getPanel() { + if (panel == null) { + panel = new IngestOptionsPanel(); + panel.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) { + changed(); + } + } + }); + } + return panel; + } + + @Override + public void applyChanges() { + if (changed) { + getPanel().store(); + changed = false; + } + } + + @Override + public void cancel() { + getPanel().cancel(); + } + + @Override + public boolean isValid() { + return getPanel().valid(); + } + + @Override + public boolean isChanged() { + return changed; + } + + @Override + public JComponent getComponent(Lookup lkp) { + return getPanel(); + } + + @Override + public HelpCtx getHelpCtx() { + return null; + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener pl) { + pcs.addPropertyChangeListener(pl); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener pl) { + pcs.removePropertyChangeListener(pl); + } + + void changed() { + if (!changed) { + changed = true; + pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true); + } + pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form new file mode 100644 index 0000000000..a483a0cdb1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form @@ -0,0 +1,176 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java new file mode 100644 index 0000000000..93f39dfb25 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -0,0 +1,272 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013-2014 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.ingest; + +import java.text.NumberFormat; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JFormattedTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.core.UserPreferences; + +/** + * Options panel that allow users to set application preferences. + */ +final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { + + IngestSettingsPanel() { + initComponents(); + int availableProcessors = Runtime.getRuntime().availableProcessors(); + Integer fileIngestThreadCountChoices[]; + int recommendedFileIngestThreadCount; + if (availableProcessors >= 16) { + fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6, 8, 12, 16}; + if (availableProcessors >= 18) { + recommendedFileIngestThreadCount = 16; + } else { + recommendedFileIngestThreadCount = 12; + } + } else if (availableProcessors >= 12 && availableProcessors <= 15) { + fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6, 8, 12}; + if (availableProcessors >= 14) { + recommendedFileIngestThreadCount = 12; + } else { + recommendedFileIngestThreadCount = 8; + } + } else if (availableProcessors >= 8 && availableProcessors <= 11) { + fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6, 8}; + if (availableProcessors >= 10) { + recommendedFileIngestThreadCount = 8; + } else { + recommendedFileIngestThreadCount = 6; + } + } else if (availableProcessors >= 6 && availableProcessors <= 7) { + fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6}; + recommendedFileIngestThreadCount = 4; + } else if (availableProcessors >= 4 && availableProcessors <= 5) { + fileIngestThreadCountChoices = new Integer[]{1, 2, 4}; + recommendedFileIngestThreadCount = 2; + } else if (availableProcessors >= 2 && availableProcessors <= 3) { + fileIngestThreadCountChoices = new Integer[]{1, 2}; + recommendedFileIngestThreadCount = 1; + } else { + fileIngestThreadCountChoices = new Integer[]{1}; + recommendedFileIngestThreadCount = 1; + } + numberOfFileIngestThreadsComboBox.setModel(new DefaultComboBoxModel<>(fileIngestThreadCountChoices)); + restartRequiredLabel.setText(NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.restartRequiredLabel.text", recommendedFileIngestThreadCount)); + // TODO listen to changes in form fields and call controller.changed() + DocumentListener docListener = new DocumentListener() { + + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + }; + this.jFormattedTextFieldProcTimeOutHrs.getDocument().addDocumentListener(docListener); + + } + + void load() { + numberOfFileIngestThreadsComboBox.setSelectedItem(UserPreferences.numberOfFileIngestThreads()); + if (UserPreferences.getIsTimeOutEnabled()) { + // user specified time out + jCheckBoxEnableProcTimeout.setSelected(true); + jFormattedTextFieldProcTimeOutHrs.setEditable(true); + int timeOutHrs = UserPreferences.getProcessTimeOutHrs(); + jFormattedTextFieldProcTimeOutHrs.setValue((long) timeOutHrs); + } else { + // never time out + jCheckBoxEnableProcTimeout.setSelected(false); + jFormattedTextFieldProcTimeOutHrs.setEditable(false); + int timeOutHrs = UserPreferences.getProcessTimeOutHrs(); + jFormattedTextFieldProcTimeOutHrs.setValue((long) timeOutHrs); + } + } + + void store() { + UserPreferences.setNumberOfFileIngestThreads((Integer) numberOfFileIngestThreadsComboBox.getSelectedItem()); + + UserPreferences.setIsTimeOutEnabled(jCheckBoxEnableProcTimeout.isSelected()); + if (jCheckBoxEnableProcTimeout.isSelected()) { + // only store time out if it is enabled + long timeOutHrs = (long) jFormattedTextFieldProcTimeOutHrs.getValue(); + UserPreferences.setProcessTimeOutHrs((int) timeOutHrs); + } + } + + boolean valid() { + return true; + } + + /** + * 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 + * regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonGroup1 = new javax.swing.ButtonGroup(); + buttonGroup3 = new javax.swing.ButtonGroup(); + jScrollPane1 = new javax.swing.JScrollPane(); + jPanel1 = new javax.swing.JPanel(); + jLabelNumThreads = new javax.swing.JLabel(); + numberOfFileIngestThreadsComboBox = new javax.swing.JComboBox<>(); + restartRequiredLabel = new javax.swing.JLabel(); + jLabelSetProcessTimeOut = new javax.swing.JLabel(); + jCheckBoxEnableProcTimeout = new javax.swing.JCheckBox(); + jFormattedTextFieldProcTimeOutHrs = new JFormattedTextField(NumberFormat.getIntegerInstance()); + jLabelProcessTimeOutUnits = new javax.swing.JLabel(); + + jScrollPane1.setBorder(null); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelNumThreads, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jLabelNumThreads.text")); // NOI18N + + numberOfFileIngestThreadsComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + numberOfFileIngestThreadsComboBoxActionPerformed(evt); + } + }); + + restartRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(restartRequiredLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.restartRequiredLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSetProcessTimeOut, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jLabelSetProcessTimeOut.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jCheckBoxEnableProcTimeout, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jCheckBoxEnableProcTimeout.text")); // NOI18N + jCheckBoxEnableProcTimeout.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jCheckBoxEnableProcTimeoutActionPerformed(evt); + } + }); + + jFormattedTextFieldProcTimeOutHrs.setText(org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jFormattedTextFieldProcTimeOutHrs.text")); // NOI18N + jFormattedTextFieldProcTimeOutHrs.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jFormattedTextFieldProcTimeOutHrsActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelProcessTimeOutUnits, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jLabelProcessTimeOutUnits.text")); // NOI18N + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(restartRequiredLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabelNumThreads) + .addComponent(jLabelSetProcessTimeOut) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(jCheckBoxEnableProcTimeout) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabelProcessTimeOutUnits))) + .addGap(213, 213, 213))) + .addGap(215, 215, 215)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(30, 30, 30) + .addComponent(jLabelNumThreads) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(restartRequiredLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabelSetProcessTimeOut) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jCheckBoxEnableProcTimeout) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelProcessTimeOutUnits))) + .addContainerGap(298, Short.MAX_VALUE)) + ); + + jScrollPane1.setViewportView(jPanel1); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + ); + }// //GEN-END:initComponents + + private void numberOfFileIngestThreadsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numberOfFileIngestThreadsComboBoxActionPerformed + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_numberOfFileIngestThreadsComboBoxActionPerformed + + private void jCheckBoxEnableProcTimeoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxEnableProcTimeoutActionPerformed + jFormattedTextFieldProcTimeOutHrs.setEditable(jCheckBoxEnableProcTimeout.isSelected()); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_jCheckBoxEnableProcTimeoutActionPerformed + + private void jFormattedTextFieldProcTimeOutHrsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.ButtonGroup buttonGroup3; + private javax.swing.JCheckBox jCheckBoxEnableProcTimeout; + private javax.swing.JFormattedTextField jFormattedTextFieldProcTimeOutHrs; + private javax.swing.JLabel jLabelNumThreads; + private javax.swing.JLabel jLabelProcessTimeOutUnits; + private javax.swing.JLabel jLabelSetProcessTimeOut; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JComboBox numberOfFileIngestThreadsComboBox; + private javax.swing.JLabel restartRequiredLabel; + // End of variables declaration//GEN-END:variables + + @Override + public void saveSettings() { + this.store(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java index 25cae770d1..8601c51877 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java @@ -30,14 +30,6 @@ import org.openide.util.Lookup; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestJobSettings; -@OptionsPanelController.TopLevelRegistration( - categoryName = "#OptionsCategory_Name_FileIngestFilterDefinitions", - iconBase = "org/sleuthkit/autopsy/images/file_ingest_filter32x32.png", - keywords = "#OptionsCategory_Keywords_FileIngestFilterDefinitions", - keywordsCategory = "FileIngestFilterDefinitions", - position = 7 -) - /** * Class for creating an FilesSetDefsPanel which will be used for configuring * the FileIngestFilter. diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 1c8bee77e6..e940020492 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; /** * A panel that allows a user to make interesting item definitions. */ -final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { +public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { @NbBundle.Messages({ "FilesSetDefsPanel.bytes=Bytes", @@ -53,7 +53,7 @@ final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel implements "FilesSetDefsPanel.loadError=Error loading interesting files sets from file.", "FilesSetDefsPanel.saveError=Error saving interesting files sets to file." }) - static enum PANEL_TYPE { + public static enum PANEL_TYPE { FILE_INGEST_FILTERS, INTERESTING_FILE_SETS @@ -78,7 +78,7 @@ final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel implements /** * Constructs an interesting item definitions panel. */ - FilesSetDefsPanel(PANEL_TYPE panelType) { + public FilesSetDefsPanel(PANEL_TYPE panelType) { this.panelType = panelType; this.initComponents(); this.customInit(); From f052539e21e56c509585830a8f546d16716963e0 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 11 Jan 2017 13:32:00 -0500 Subject: [PATCH 02/73] 2197-renumbered Option panel position to account for new panel --- .../autopsy/casemodule/services/TagsOptionsPanelController.java | 2 +- .../directorytree/ExternalViewerOptionsPanelController.java | 2 +- .../fileextmismatch/FileExtMismatchOptionsPanelController.java | 2 +- .../modules/filetypeid/FileTypeIdOptionsPanelController.java | 2 +- .../hashdatabase/HashDatabaseOptionsPanelController.java | 2 +- .../InterestingItemDefsOptionsPanelController.java | 2 +- .../configuration/AutoIngestSettingsPanelController.java | 2 +- .../imagegallery/ImageGalleryOptionsPanelController.java | 2 +- .../keywordsearch/KeywordSearchOptionsPanelController.java | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java index 3d36e8ae00..2ee820433b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java @@ -31,7 +31,7 @@ import org.openide.util.Lookup; iconBase = "org/sleuthkit/autopsy/casemodule/services/tag-options-panel-icon.png", keywords = "#OptionsCategory_TagNames", keywordsCategory = "CustomTagNames", - position = 8 + position = 10 ) public final class TagsOptionsPanelController extends OptionsPanelController { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java index b351192af3..5df5b89e56 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java @@ -34,7 +34,7 @@ import org.openide.util.Lookup; iconBase = "org/sleuthkit/autopsy/directorytree/external-viewer-rules-32x32.png", keywords = "#OptionsCategory_Keywords_ExternalViewer", keywordsCategory = "ExternalViewer", - position = 9 + position = 11 ) public final class ExternalViewerOptionsPanelController extends OptionsPanelController { diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java index 013c8f65a4..93eef3c0a0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java @@ -16,7 +16,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @OptionsPanelController.TopLevelRegistration( categoryName = "#OptionsCategory_Name_FileExtMismatchOptions", iconBase = "org/sleuthkit/autopsy/modules/fileextmismatch/options-icon.png", - position = 5, + position = 7, keywords = "#OptionsCategory_FileExtMismatch", keywordsCategory = "KeywordSearchOptions") public final class FileExtMismatchOptionsPanelController extends OptionsPanelController { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java index cea2f62de1..434e17d463 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -18,7 +18,7 @@ import org.openide.util.Lookup; iconBase = "org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png", keywords = "#OptionsCategory_Keywords_FileTypeId", keywordsCategory = "FileTypeId", - position = 6 + position = 8 ) public final class FileTypeIdOptionsPanelController extends OptionsPanelController { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java index 75e6f26e16..c2c52a4097 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java @@ -30,7 +30,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @OptionsPanelController.TopLevelRegistration( categoryName = "#OptionsCategory_Name_HashDatabase", iconBase = "org/sleuthkit/autopsy/modules/hashdatabase/options_icon.png", - position = 4, + position = 6, keywords = "#OptionsCategory_Keywords_HashDatabase", keywordsCategory = "HashDatabase", id = "HashDatabase") diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java index 609fc937ac..7280f3b7ab 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java @@ -32,7 +32,7 @@ import org.openide.util.Lookup; iconBase = "org/sleuthkit/autopsy/images/interesting_item_32x32.png", keywords = "#OptionsCategory_Keywords_InterestingItemDefinitions", keywordsCategory = "InterestingItemDefinitions", - position = 7 + position = 9 ) public final class InterestingItemDefsOptionsPanelController extends OptionsPanelController { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanelController.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanelController.java index 36b6050cf8..470c69076b 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanelController.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanelController.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Auto_Ingest", iconBase = "org/sleuthkit/autopsy/experimental/images/autoIngest32.png", - position = 3, + position = 4, keywords = "#OptionsCategory_Keywords_Auto_Ingest_Settings", keywordsCategory = "Auto Ingest") public final class AutoIngestSettingsPanelController extends OptionsPanelController { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanelController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanelController.java index 3d893fa88a..44b4eade1b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanelController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanelController.java @@ -34,7 +34,7 @@ import org.openide.util.Lookup; iconBase = "org/sleuthkit/autopsy/imagegallery/images/btn_icon_image_gallery_32.png", keywords = "#OptionsCategory_Keywords_Options", keywordsCategory = "Options", - position = 10 + position = 12 ) @org.openide.util.NbBundle.Messages({"OptionsCategory_Name_Options=Image / Video Gallery", "OptionsCategory_Keywords_Options=image video gallery category "}) public final class ImageGalleryOptionsPanelController extends OptionsPanelController { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchOptionsPanelController.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchOptionsPanelController.java index 04e37afca4..91f5b504d4 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchOptionsPanelController.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchOptionsPanelController.java @@ -30,7 +30,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @OptionsPanelController.TopLevelRegistration( categoryName = "#OptionsCategory_Name_KeywordSearchOptions", iconBase = "org/sleuthkit/autopsy/keywordsearch/options-icon.png", - position = 3, + position = 5, keywords = "#OptionsCategory_Keywords_KeywordSearchOptions", keywordsCategory = "KeywordSearchOptions") public final class KeywordSearchOptionsPanelController extends OptionsPanelController { From decccc38f69381ea9eaf077949874abb2c6986af Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 11 Jan 2017 14:39:10 -0500 Subject: [PATCH 03/73] 2197-Empty ProfileSettingsPanel added for 3rd tab --- .../autopsy/ingest/IngestOptionsPanel.java | 10 +++- .../autopsy/ingest/ProfileSettingsPanel.form | 28 +++++++++ .../autopsy/ingest/ProfileSettingsPanel.java | 59 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index b3ff6aff36..cb7599369f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -30,6 +30,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti private FilesSetDefsPanel filterPanel; private IngestSettingsPanel settingsPanel; + private ProfileSettingsPanel profilePanel; IngestOptionsPanel() { @@ -41,10 +42,13 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti setName("Temporary Name"); filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); settingsPanel = new IngestSettingsPanel(); + profilePanel = new ProfileSettingsPanel(); tabbedPane.insertTab("Settings", null, settingsPanel, "Tootip 1", 0); - tabbedPane.insertTab("Filters", null, + tabbedPane.insertTab("File Filters", null, filterPanel, "Tooltip 2", 1); + tabbedPane.insertTab("Profiles", null, + profilePanel, "Tooltip 3", 2); } @@ -52,18 +56,21 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti public void addPropertyChangeListener(PropertyChangeListener l) { filterPanel.addPropertyChangeListener(l); settingsPanel.addPropertyChangeListener(l); + profilePanel.addPropertyChangeListener(l); } @Override public void removePropertyChangeListener(PropertyChangeListener l) { filterPanel.removePropertyChangeListener(l); settingsPanel.removePropertyChangeListener(l); + profilePanel.removePropertyChangeListener(l); } @Override public void saveSettings() { filterPanel.store(); settingsPanel.store(); + profilePanel.store(); } @Override @@ -75,6 +82,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti public void load() { filterPanel.load(); settingsPanel.load(); + profilePanel.load(); } boolean valid() { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form new file mode 100644 index 0000000000..4f9abb50dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -0,0 +1,28 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java new file mode 100644 index 0000000000..93f39178df --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -0,0 +1,59 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest; + +import org.sleuthkit.autopsy.corecomponents.OptionsPanel; + + +public class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { + + /** + * Creates new form ProfileOptionsPanel + */ + public ProfileSettingsPanel() { + initComponents(); + } + + /** + * 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 + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + @Override + public void saveSettings() { + + } + + @Override + public void store() { + + } + + @Override + public void load() { + + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} From 1faaf5c95455abed0034525d6bcd76b0271726de Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 11 Jan 2017 14:49:14 -0500 Subject: [PATCH 04/73] 2197-access level modified for new class --- .../autopsy/ingest/ProfileSettingsPanel.form | 2 +- .../autopsy/ingest/ProfileSettingsPanel.java | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 4f9abb50dc..5f3eab1a5f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -1,6 +1,6 @@ -
+ diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 93f39178df..58f9a571fc 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -5,15 +5,13 @@ */ package org.sleuthkit.autopsy.ingest; -import org.sleuthkit.autopsy.corecomponents.OptionsPanel; - -public class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { +class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { /** * Creates new form ProfileOptionsPanel */ - public ProfileSettingsPanel() { + ProfileSettingsPanel() { initComponents(); } @@ -43,17 +41,14 @@ public class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implem } - @Override - public void store() { + void store() { } - @Override - public void load() { + void load() { } - // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } From 8baf5e635c7373615fe7129d20ca194cc2981fda Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 12 Jan 2017 12:37:28 -0500 Subject: [PATCH 05/73] 2197-Profile tab refined --- .../autopsy/ingest/Bundle.properties | 10 + .../autopsy/ingest/IngestProfile.java | 15 + .../autopsy/ingest/ProfileSettingsPanel.form | 285 +++++++++++++++++- .../autopsy/ingest/ProfileSettingsPanel.java | 179 ++++++++++- 4 files changed, 480 insertions(+), 9 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 9e512e392c..82e16e831f 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -122,3 +122,13 @@ IngestSettingsPanel.jCheckBoxEnableProcTimeout.text= IngestSettingsPanel.jLabelSetProcessTimeOut.text=Enable timeout to allow modules to automatically terminate after a set amount of time: IngestSettingsPanel.restartRequiredLabel.text=For this computer, a maximum of {0} file ingest threads should be used. Application restart required to take effect. IngestSettingsPanel.jLabelNumThreads.text=Number of threads to use for file ingest: +ProfileSettingsPanel.newProfileButton.text=New Profile +ProfileSettingsPanel.editProfileButton.text=Edit Profile +ProfileSettingsPanel.deleteProfileButton.text=Delete Profile +ProfileSettingsPanel.profileListLabel.text=Profiles: +ProfileSettingsPanel.profileDescArea.AccessibleContext.accessibleName= +ProfileSettingsPanel.profileDescLabel.text=Profile Description: +ProfileSettingsPanel.filterNameLabel.text=Filter: +ProfileSettingsPanel.filterNameText.text=filter name here +ProfileSettingsPanel.fitlerDescLabel.text=Filter Description: +ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java new file mode 100644 index 0000000000..44f065adcd --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java @@ -0,0 +1,15 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest; + + +class IngestProfile { + String name; + String description; + String ingestContext; //WJS-TODO replace with A list of selected/unselected ingest modules and runtime settings for the modules. + + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 5f3eab1a5f..6eed5e5c35 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -1,6 +1,13 @@ + + + + + + + @@ -16,13 +23,287 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 58f9a571fc..6e48436205 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -5,8 +5,8 @@ */ package org.sleuthkit.autopsy.ingest; - -class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { +//WJS-TODO hook up all labels and fields to bundle properties instead of plain text +class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { /** * Creates new form ProfileOptionsPanel @@ -24,31 +24,196 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { // //GEN-BEGIN:initComponents private void initComponents() { + profileListPane = new javax.swing.JScrollPane(); + profileList = new javax.swing.JList<>(); + profileListLabel = new javax.swing.JLabel(); + jSeparator1 = new javax.swing.JSeparator(); + newProfileButton = new javax.swing.JButton(); + editProfileButton = new javax.swing.JButton(); + deleteProfileButton = new javax.swing.JButton(); + profileDescPane = new javax.swing.JScrollPane(); + profileDescArea = new javax.swing.JTextArea(); + profileDescLabel = new javax.swing.JLabel(); + filterNameLabel = new javax.swing.JLabel(); + filterNameText = new javax.swing.JLabel(); + fitlerDescLabel = new javax.swing.JLabel(); + filterDescPane = new javax.swing.JScrollPane(); + filterDescArea = new javax.swing.JTextArea(); + selectedModulesPane = new javax.swing.JScrollPane(); + selectedModulesArea = new javax.swing.JTextArea(); + selectedModulesLabel = new javax.swing.JLabel(); + + setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + profileList.setModel(new javax.swing.AbstractListModel() { + String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; + public int getSize() { return strings.length; } + public String getElementAt(int i) { return strings[i]; } + }); + profileListPane.setViewportView(profileList); + + org.openide.awt.Mnemonics.setLocalizedText(profileListLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileListLabel.text")); // NOI18N + + jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + + org.openide.awt.Mnemonics.setLocalizedText(newProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.newProfileButton.text")); // NOI18N + newProfileButton.setMaximumSize(new java.awt.Dimension(97, 23)); + newProfileButton.setMinimumSize(new java.awt.Dimension(97, 23)); + newProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); + + org.openide.awt.Mnemonics.setLocalizedText(editProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.editProfileButton.text")); // NOI18N + editProfileButton.setMaximumSize(new java.awt.Dimension(97, 23)); + editProfileButton.setMinimumSize(new java.awt.Dimension(97, 23)); + editProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); + + org.openide.awt.Mnemonics.setLocalizedText(deleteProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.deleteProfileButton.text")); // NOI18N + + profileDescArea.setEditable(false); + profileDescArea.setBackground(new java.awt.Color(240, 240, 240)); + profileDescArea.setColumns(20); + profileDescArea.setLineWrap(true); + profileDescArea.setRows(5); + profileDescArea.setWrapStyleWord(true); + profileDescArea.setMinimumSize(new java.awt.Dimension(10, 22)); + profileDescArea.setName(""); // NOI18N + profileDescArea.setPreferredSize(new java.awt.Dimension(14, 40)); + profileDescPane.setViewportView(profileDescArea); + profileDescArea.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileDescArea.AccessibleContext.accessibleName")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(profileDescLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileDescLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(filterNameLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.filterNameLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(filterNameText, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.filterNameText.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(fitlerDescLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.fitlerDescLabel.text")); // NOI18N + + filterDescArea.setBackground(new java.awt.Color(240, 240, 240)); + filterDescArea.setColumns(20); + filterDescArea.setRows(5); + filterDescArea.setMinimumSize(new java.awt.Dimension(10, 40)); + filterDescArea.setPreferredSize(new java.awt.Dimension(14, 42)); + filterDescPane.setViewportView(filterDescArea); + + selectedModulesArea.setBackground(new java.awt.Color(240, 240, 240)); + selectedModulesArea.setColumns(20); + selectedModulesArea.setRows(5); + selectedModulesPane.setViewportView(selectedModulesArea); + + org.openide.awt.Mnemonics.setLocalizedText(selectedModulesLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.selectedModulesLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(profileListLabel)) + .addGroup(layout.createSequentialGroup() + .addGap(20, 20, 20) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(profileListPane) + .addGroup(layout.createSequentialGroup() + .addComponent(newProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(filterDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 527, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 527, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 527, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(fitlerDescLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 208, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(selectedModulesLabel) + .addComponent(profileDescLabel)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(330, Short.MAX_VALUE) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(564, Short.MAX_VALUE))) ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {filterDescPane, profileDescPane, selectedModulesPane}); + layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(profileListLabel) + .addComponent(profileDescLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(profileDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(filterNameLabel) + .addComponent(filterNameText)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(fitlerDescLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(selectedModulesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(selectedModulesPane)) + .addComponent(profileListPane, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE)) + .addGap(4, 4, 4) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteProfileButton)) + .addContainerGap()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 477, Short.MAX_VALUE))) ); }// //GEN-END:initComponents @Override public void saveSettings() { - + } void store() { - + } void load() { - + } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton deleteProfileButton; + private javax.swing.JButton editProfileButton; + private javax.swing.JTextArea filterDescArea; + private javax.swing.JScrollPane filterDescPane; + private javax.swing.JLabel filterNameLabel; + private javax.swing.JLabel filterNameText; + private javax.swing.JLabel fitlerDescLabel; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JButton newProfileButton; + private javax.swing.JTextArea profileDescArea; + private javax.swing.JLabel profileDescLabel; + private javax.swing.JScrollPane profileDescPane; + private javax.swing.JList profileList; + private javax.swing.JLabel profileListLabel; + private javax.swing.JScrollPane profileListPane; + private javax.swing.JTextArea selectedModulesArea; + private javax.swing.JLabel selectedModulesLabel; + private javax.swing.JScrollPane selectedModulesPane; // End of variables declaration//GEN-END:variables } From 6bbd3c820be2e93ec1067a01916dba7aaeeb1b5f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 12 Jan 2017 13:02:33 -0500 Subject: [PATCH 06/73] 2197 fixed bug with merge --- Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java index 77ce317856..63143d5174 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -38,7 +38,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { Integer fileIngestThreadCountChoices[]; int recommendedFileIngestThreadCount; - if (availableProcessors >= 6 && availableProcessors <= 7) { + if (availableProcessors >= 6) { fileIngestThreadCountChoices = new Integer[]{1, 2, 4, 6}; recommendedFileIngestThreadCount = 4; } else if (availableProcessors >= 4 && availableProcessors <= 5) { From cc5347eccdb6593192e38b52f653b8c31eab050a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 18 Jan 2017 15:31:59 -0500 Subject: [PATCH 07/73] 2197-Mostly working profile creating, editing, and deleting --- .../autopsy/ingest/Bundle.properties | 3 + .../autopsy/ingest/IngestJobSettings.java | 21 +- .../autopsy/ingest/IngestOptionsPanel.java | 8 +- .../ingest/IngestOptionsPanelController.java | 11 +- .../autopsy/ingest/IngestProfile.java | 15 -- .../autopsy/ingest/IngestProfileList.java | 198 ++++++++++++++++++ .../autopsy/ingest/ProfilePanel.form | 114 ++++++++++ .../autopsy/ingest/ProfilePanel.java | 150 +++++++++++++ .../autopsy/ingest/ProfileSettingsPanel.form | 32 +-- .../autopsy/ingest/ProfileSettingsPanel.java | 155 ++++++++++++-- 10 files changed, 653 insertions(+), 54 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 82e16e831f..4bcde5e112 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -132,3 +132,6 @@ ProfileSettingsPanel.filterNameLabel.text=Filter: ProfileSettingsPanel.filterNameText.text=filter name here ProfileSettingsPanel.fitlerDescLabel.text=Filter Description: ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules: +ProfilePanel.profileDescLabel.text=Profile Description: +ProfilePanel.profileNameLabel.text=Profile Name: +ProfilePanel.profileNameField.text= diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index f858555d91..a1e8e5c38f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -52,7 +52,7 @@ public class IngestJobSettings { private static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS private static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS - private static final String LAST_FILE_INGEST_FILTER_KEY = "Last File Ingest Filter Used"; + private static final String LAST_FILE_INGEST_FILTER_KEY = "Last_File_Ingest_Filter"; //NON-NLS private static final String MODULE_SETTINGS_FOLDER = "IngestModuleSettings"; //NON-NLS private static final String MODULE_SETTINGS_FOLDER_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), IngestJobSettings.MODULE_SETTINGS_FOLDER).toAbsolutePath().toString(); private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS @@ -60,7 +60,7 @@ public class IngestJobSettings { private static FilesSet ALL_FILES_INGEST_FILTER = new FilesSet("All Files", "All Files", false, true, Collections.emptyMap()); //NON-NLS private static FilesSet ALL_AND_UNALLOC_FILES_INGEST_FILTER = new FilesSet("All Files and Unallocated Space", "All Files and Unallocated Space", false, false, Collections.emptyMap()); //NON-NLS private FilesSet fileIngestFilter; - private final String executionContext; + private String executionContext; private final IngestType ingestType; private String moduleSettingsFolderPath; private static final CharSequence pythonModuleSettingsPrefixCS = "org.python.proxies.".subSequence(0, "org.python.proxies.".length() - 1); //NON-NLS @@ -164,6 +164,11 @@ public class IngestJobSettings { this.store(); } + public void saveAs(String executionContext) { + this.executionContext = executionContext; + this.store(); + } + /** * Gets the ingest execution context identifier. Examples of execution * contexts include the add data source wizard and the run ingest modules @@ -249,6 +254,16 @@ public class IngestJobSettings { return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, executionContext); } + /** + * Returns the path to the ingest module settings folder from a static manner. + * + * @param context specify the context of the folder you wish to get + * @return path to the module settings folder + */ + static Path getSavedModuleSettingsFolder(String context) { + return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, context); + } + /** * Creates the folder for saving the individual ingest module settings part * of these ingest job settings. @@ -371,7 +386,7 @@ public class IngestJobSettings { * * @return The list of module names associated with the key. */ - private HashSet getModulesNamesFromSetting(String key, String defaultSetting) { + HashSet getModulesNamesFromSetting(String key, String defaultSetting) { if (ModuleSettings.settingExists(this.executionContext, key) == false) { ModuleSettings.setConfigSetting(this.executionContext, key, defaultSetting); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index cb7599369f..52f6fb713c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -32,7 +32,6 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti private IngestSettingsPanel settingsPanel; private ProfileSettingsPanel profilePanel; - IngestOptionsPanel() { initComponents(); customizeComponents(); @@ -50,6 +49,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti tabbedPane.insertTab("Profiles", null, profilePanel, "Tooltip 3", 2); + } @Override @@ -81,16 +81,16 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti @Override public void load() { filterPanel.load(); - settingsPanel.load(); + settingsPanel.load(); profilePanel.load(); - } + } boolean valid() { return true; } public void cancel() { - + saveSettings(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java index a0c2a39de1..a683261fde 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java @@ -22,6 +22,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import javax.swing.JComponent; +import javax.swing.SwingUtilities; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.HelpCtx; import org.openide.util.Lookup; @@ -63,10 +64,16 @@ public class IngestOptionsPanelController extends OptionsPanelController { @Override public void applyChanges() { if (changed) { - getPanel().store(); - changed = false; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + getPanel().store(); + changed = false; + } + }); } } + @Override public void cancel() { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java deleted file mode 100644 index 44f065adcd..0000000000 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfile.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.ingest; - - -class IngestProfile { - String name; - String description; - String ingestContext; //WJS-TODO replace with A list of selected/unselected ingest modules and runtime settings for the modules. - - -} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java new file mode 100644 index 0000000000..e6e9d678aa --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java @@ -0,0 +1,198 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import org.apache.commons.io.FileUtils; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; + +public class IngestProfileList { + + private static final String PROFILE_FOLDER = "profiles"; + private static final String PROFILE_NAME_KEY = "Profile_Name"; + private static final String PROFILE_DESC_KEY = "Profile_Description"; + private static final String PROFILE_SELECTED_KEY = "Profile_Selected"; + List profileList = null; + List nameList = null; + private IngestProfile lastUsedProfile = null; + + List getIngestProfileList() { + if (profileList == null) { + loadProfileList(); + } + return profileList; + } + + void readFilesFromDirectory() { + + File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); + System.out.println(dir.toString()); //WJS-TODO remove sout + File[] directoryListing = dir.listFiles(); + + if (directoryListing != null) { + profileList = new ArrayList<>(); + nameList = new ArrayList<>(); + for (File child : directoryListing) { + String name = child.getName().split("\\.")[0]; + String context = PROFILE_FOLDER + File.separator + name; + // name = ModuleSettings.getConfigSetting(context, PROFILE_NAME_KEY); + System.out.println("-=-=-=-=-=-" + name); + nameList.add(name); + String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); + System.out.println(desc); + String selected = ModuleSettings.getConfigSetting(context, PROFILE_SELECTED_KEY); + profileList.add(new IngestProfile(name, desc, selected)); + } + } else { + profileList = Collections.emptyList(); + } + } + + void loadProfileList() { + readFilesFromDirectory(); + lastUsedProfile = new IngestProfile("lastProfileUsed", "last used description here soon", "lastProfileUsed"); + //WJS-TODO add saved profile list items to list; + + } + + IngestProfile getLastUsedProfile() { + return lastUsedProfile; + } + + void saveProfileList() { + //save last used profile + for (IngestProfile profile : getIngestProfileList()) { + IngestProfile.saveProfile(profile); + } + } + + static class IngestProfile { + + static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS + static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS + private final String name; + private final String description; + private final String fileIngestFilter; //can this just be the name? //WJS-TODO replace with A list of selected/unselected ingest modules and runtime settings for the modules. + + IngestProfile(String name, String desc, String selected) { + this.name = name; + this.description = desc; + this.fileIngestFilter = selected; + } + + @Override + public String toString() { + return getName(); + } + + /** + * @return the name + */ + String getName() { + return name; + } + + /** + * @return the description + */ + String getDescription() { + return description; + } + + /** + * @return the fileIngestFilter + */ + String getFileIngestFilter() { + return fileIngestFilter; + } + + static void deleteProfile(IngestProfile selectedProfile) { + try { + Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, selectedProfile.getName() + ".properties")); + Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), selectedProfile.getName() + ".properties")); + FileUtils.deleteDirectory(IngestJobSettings.getSavedModuleSettingsFolder(selectedProfile.getName() + File.separator).toFile()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + } + + static void renameProfile(String oldName, String newName) { + if (!oldName.equals(newName)) { //if renameProfile was called with the new name being the same as the old name, it is complete already + File oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, oldName + ".properties").toFile(); + File newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, newName + ".properties").toFile(); + oldFile.renameTo(newFile); + oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), oldName + ".properties").toFile(); + newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), newName + ".properties").toFile(); + oldFile.renameTo(newFile); + oldFile = IngestJobSettings.getSavedModuleSettingsFolder(oldName + File.separator).toFile(); + newFile = IngestJobSettings.getSavedModuleSettingsFolder(newName + File.separator).toFile(); + oldFile.renameTo(newFile); + } + + } + + HashSet getModuleNames(String key) { + if (ModuleSettings.settingExists(this.getName(), key) == false) { + ModuleSettings.setConfigSetting(this.getName(), key, ""); + } + HashSet moduleNames = new HashSet<>(); + String modulesSetting = ModuleSettings.getConfigSetting(this.getName(), key); + if (!modulesSetting.isEmpty()) { + String[] settingNames = modulesSetting.split(", "); + for (String name : settingNames) { + // Map some old core module names to the current core module names. + switch (name) { + case "Thunderbird Parser": //NON-NLS + case "MBox Parser": //NON-NLS + moduleNames.add("Email Parser"); //NON-NLS + break; + case "File Extension Mismatch Detection": //NON-NLS + moduleNames.add("Extension Mismatch Detector"); //NON-NLS + break; + case "EWF Verify": //NON-NLS + case "E01 Verify": //NON-NLS + moduleNames.add("E01 Verifier"); //NON-NLS + break; + case "Archive Extractor": //NON-NLS + moduleNames.add("Embedded File Extractor"); //NON-NLS + break; + default: + moduleNames.add(name); + } + } + } + return moduleNames; + } + +// FilesSet getFileIngestFilter() { +// if (ModuleSettings.settingExists(this.name, key) == false) { +// ModuleSettings.setConfigSetting(this.name, key, ""); +// } +// HashSet moduleNames = new HashSet<>(); +// String modulesSetting = ModuleSettings.getConfigSetting(this.name, key); +// +// } + static void saveProfile(IngestProfile profile) { + System.out.println("==============PNAME===========" + profile.getName()); + String context = PROFILE_FOLDER + File.separator + profile.getName(); + + ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName());//WJS-TODO write name, desc, context + ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription());//WJS-TODO write name, desc, context + ModuleSettings.setConfigSetting(context, PROFILE_SELECTED_KEY, profile.getFileIngestFilter());//WJS-TODO write name, desc, context + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form new file mode 100644 index 0000000000..b898a39e88 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form @@ -0,0 +1,114 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java new file mode 100644 index 0000000000..ecd3a04144 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -0,0 +1,150 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest; + +import java.beans.PropertyChangeListener; +import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; + +/** + * + * @author wschaefer + */ +public class ProfilePanel extends IngestModuleGlobalSettingsPanel { + + IngestJobSettingsPanel ingestSettingsPanel; + IngestJobSettings tempSettings; + IngestProfile profile; + final static String NEW_PROFILE_NAME = "TemporaryNewProfile"; + + /** + * Creates new form ProfilePanel + */ + public ProfilePanel() { + initComponents(); + tempSettings = new IngestJobSettings(NEW_PROFILE_NAME); + ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); + jPanel1.add(ingestSettingsPanel, 0); + + } + + public ProfilePanel(IngestProfile selectedProfile) { + initComponents(); + profile = selectedProfile; + profileDescArea.setText(profile.getDescription()); + profileNameField.setText(profile.getName()); + tempSettings = new IngestJobSettings(selectedProfile.getName()); + ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); + jPanel1.add(ingestSettingsPanel, 0); + } + + /** + * 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 + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + profileDescPane = new javax.swing.JScrollPane(); + profileDescArea = new javax.swing.JTextArea(); + profileDescLabel = new javax.swing.JLabel(); + profileNameLabel = new javax.swing.JLabel(); + profileNameField = new javax.swing.JTextField(); + jPanel1 = new javax.swing.JPanel(); + + profileDescArea.setColumns(20); + profileDescArea.setLineWrap(true); + profileDescArea.setRows(5); + profileDescArea.setWrapStyleWord(true); + profileDescArea.setMinimumSize(new java.awt.Dimension(10, 22)); + profileDescArea.setName(""); // NOI18N + profileDescArea.setPreferredSize(new java.awt.Dimension(14, 40)); + profileDescPane.setViewportView(profileDescArea); + + org.openide.awt.Mnemonics.setLocalizedText(profileDescLabel, org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.profileDescLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(profileNameLabel, org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.profileNameLabel.text")); // NOI18N + + profileNameField.setText(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.profileNameField.text")); // NOI18N + + jPanel1.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(profileDescLabel) + .addComponent(profileNameLabel)) + .addContainerGap(366, Short.MAX_VALUE)))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(profileNameField)) + .addGap(6, 6, 6)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(profileNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(profileNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(profileDescLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(profileDescPane) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(21, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + ingestSettingsPanel.removePropertyChangeListener(l); + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener l) { + ingestSettingsPanel.addPropertyChangeListener(l); + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel jPanel1; + private javax.swing.JTextArea profileDescArea; + private javax.swing.JLabel profileDescLabel; + private javax.swing.JScrollPane profileDescPane; + private javax.swing.JTextField profileNameField; + private javax.swing.JLabel profileNameLabel; + // End of variables declaration//GEN-END:variables + + @Override + public void saveSettings() { + if (profile == null) { + IngestProfile.renameProfile(tempSettings.getExecutionContext(), profileNameField.getText()); + } else if (!profile.getName().equals(profileNameField.getText())) { + IngestProfile.renameProfile(profile.getName(), profileNameField.getText()); + } + profile = new IngestProfile(profileNameField.getText(), profileDescArea.getText(), profileNameField.getText()); + IngestProfile.saveProfile(profile); + ingestSettingsPanel.getSettings().saveAs(profileNameField.getText()); + } + + public void store() { + saveSettings(); + } + + public void load() { + } +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 6eed5e5c35..0da9a58764 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -38,7 +38,7 @@ - +
@@ -48,9 +48,9 @@ - - - + + + @@ -62,7 +62,7 @@ - + @@ -129,17 +129,12 @@ - - - - - - - + + - + @@ -171,6 +166,9 @@ + + + @@ -187,6 +185,9 @@ + + + @@ -194,6 +195,9 @@ + + + @@ -265,6 +269,7 @@ + @@ -289,6 +294,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 6e48436205..39b0aac169 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -6,13 +6,25 @@ package org.sleuthkit.autopsy.ingest; //WJS-TODO hook up all labels and fields to bundle properties instead of plain text -class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { +import javax.swing.DefaultListModel; +import javax.swing.JOptionPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import org.netbeans.spi.options.OptionsPanelController; +import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; + +class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { + + private final DefaultListModel profilesListModel = new DefaultListModel<>(); /** * Creates new form ProfileOptionsPanel */ ProfileSettingsPanel() { initComponents(); + this.profileList.setModel(profilesListModel); + this.profileList.addListSelectionListener(new ProfileSettingsPanel.ProfileListSelectionListener()); } /** @@ -45,11 +57,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { setBorder(javax.swing.BorderFactory.createEtchedBorder()); - profileList.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; - public int getSize() { return strings.length; } - public String getElementAt(int i) { return strings[i]; } - }); + profileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); profileListPane.setViewportView(profileList); org.openide.awt.Mnemonics.setLocalizedText(profileListLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileListLabel.text")); // NOI18N @@ -60,13 +68,28 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { newProfileButton.setMaximumSize(new java.awt.Dimension(97, 23)); newProfileButton.setMinimumSize(new java.awt.Dimension(97, 23)); newProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); + newProfileButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + newProfileButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(editProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.editProfileButton.text")); // NOI18N editProfileButton.setMaximumSize(new java.awt.Dimension(97, 23)); editProfileButton.setMinimumSize(new java.awt.Dimension(97, 23)); editProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); + editProfileButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + editProfileButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(deleteProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.deleteProfileButton.text")); // NOI18N + deleteProfileButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteProfileButtonActionPerformed(evt); + } + }); profileDescArea.setEditable(false); profileDescArea.setBackground(new java.awt.Color(240, 240, 240)); @@ -88,6 +111,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { org.openide.awt.Mnemonics.setLocalizedText(fitlerDescLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.fitlerDescLabel.text")); // NOI18N + filterDescArea.setEditable(false); filterDescArea.setBackground(new java.awt.Color(240, 240, 240)); filterDescArea.setColumns(20); filterDescArea.setRows(5); @@ -95,6 +119,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { filterDescArea.setPreferredSize(new java.awt.Dimension(14, 42)); filterDescPane.setViewportView(filterDescArea); + selectedModulesArea.setEditable(false); selectedModulesArea.setBackground(new java.awt.Color(240, 240, 240)); selectedModulesArea.setColumns(20); selectedModulesArea.setRows(5); @@ -120,15 +145,15 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(editProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) + .addComponent(deleteProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE))))) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filterDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 527, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 527, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 527, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) + .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING))) .addComponent(fitlerDescLabel) .addGroup(layout.createSequentialGroup() .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -136,16 +161,13 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { .addComponent(filterNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 208, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(selectedModulesLabel) .addComponent(profileDescLabel)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(14, 14, 14)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap(330, Short.MAX_VALUE) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap(564, Short.MAX_VALUE))) ); - - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {filterDescPane, profileDescPane, selectedModulesPane}); - layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() @@ -183,16 +205,115 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { ); }// //GEN-END:initComponents + private void newProfileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newProfileButtonActionPerformed + doProfileDialog(null); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_newProfileButtonActionPerformed + + private void deleteProfileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteProfileButtonActionPerformed + IngestProfile selectedProfile = this.profileList.getSelectedValue(); + this.profilesListModel.removeElement(selectedProfile); + IngestProfile.deleteProfile(selectedProfile); + + // Select the first of the remaining set definitions. This will cause + // the selection listeners to repopulate the subordinate components. + this.resetComponents(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_deleteProfileButtonActionPerformed + + private void resetComponents() { + if (!this.profilesListModel.isEmpty()) { + this.profileList.setSelectedIndex(0); + } else { + this.profilesListModel.clear(); + this.profileDescArea.setText(""); + this.filterDescArea.setText(""); + this.filterNameText.setText(""); + this.selectedModulesArea.setText(""); + } + } + private void editProfileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editProfileButtonActionPerformed + IngestProfile selectedProfile = profileList.getSelectedValue(); + doProfileDialog(selectedProfile); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_editProfileButtonActionPerformed + + private void doProfileDialog(IngestProfile selectedProfile) { + // Create a files set defintion panle. + ProfilePanel panel; + if (selectedProfile != null) { + // Editing an existing set definition. + panel = new ProfilePanel(selectedProfile); + } else { + // Creating a new set definition. + panel = new ProfilePanel(); + } + // Do a dialog box with the files set panel until the user either enters + // a valid definition or cancels. Note that the panel gives the user + // feedback when isValidDefinition() is called. + int option = JOptionPane.OK_OPTION; + // do { + option = JOptionPane.showConfirmDialog(null, panel, "new profile title", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); +// } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); + + if (option == JOptionPane.OK_OPTION) { + panel.saveSettings(); + //this.resetComponents(); + load(); + } + + } + @Override public void saveSettings() { } - void store() { + @Override + public void store() { } - void load() { + @Override + public void load() { + int currentIndex = profileList.getSelectedIndex(); + profilesListModel.clear(); + IngestProfileList iList = new IngestProfileList(); + iList.loadProfileList(); + for (IngestProfile profile : iList.profileList) { + profilesListModel.addElement(profile); + } + if (profilesListModel.isEmpty()) { + editProfileButton.setEnabled(false); + deleteProfileButton.setEnabled(false); + } else { + editProfileButton.setEnabled(true); + deleteProfileButton.setEnabled(true); + } + profileList.setSelectedIndex(currentIndex); + } + + private final class ProfileListSelectionListener implements ListSelectionListener { + + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + + // Get the selected interesting files set and populate the set + // components. + IngestProfile selectedProfile = ProfileSettingsPanel.this.profileList.getSelectedValue(); + if (selectedProfile != null) { + profileDescArea.setText(selectedProfile.getDescription()); + selectedModulesArea.setText(""); + for (String moduleName : selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY)) { + selectedModulesArea.append(moduleName + "\n");// Populate the components that display the properties of the selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY); + } + + } + + } } @@ -209,7 +330,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel { private javax.swing.JTextArea profileDescArea; private javax.swing.JLabel profileDescLabel; private javax.swing.JScrollPane profileDescPane; - private javax.swing.JList profileList; + private javax.swing.JList profileList; private javax.swing.JLabel profileListLabel; private javax.swing.JScrollPane profileListPane; private javax.swing.JTextArea selectedModulesArea; From 75dfeaeb28b132bdb7c3e9ea64248c574e53c593 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Jan 2017 10:57:50 -0500 Subject: [PATCH 08/73] 2197-improved synchronization of file access when reading new .properties --- .../autopsy/ingest/Bundle.properties | 2 +- .../autopsy/ingest/IngestProfileList.java | 159 ++++++++---------- .../autopsy/ingest/ProfilePanel.java | 2 +- .../autopsy/ingest/ProfileSettingsPanel.form | 2 +- .../autopsy/ingest/ProfileSettingsPanel.java | 11 +- .../modules/interestingitems/FilesSet.java | 2 +- 6 files changed, 85 insertions(+), 93 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 4bcde5e112..bb1407dc3f 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -129,7 +129,7 @@ ProfileSettingsPanel.profileListLabel.text=Profiles: ProfileSettingsPanel.profileDescArea.AccessibleContext.accessibleName= ProfileSettingsPanel.profileDescLabel.text=Profile Description: ProfileSettingsPanel.filterNameLabel.text=Filter: -ProfileSettingsPanel.filterNameText.text=filter name here +ProfileSettingsPanel.filterNameText.text= ProfileSettingsPanel.fitlerDescLabel.text=Filter Description: ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules: ProfilePanel.profileDescLabel.text=Profile Description: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java index e6e9d678aa..7385192435 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java @@ -23,10 +23,9 @@ public class IngestProfileList { private static final String PROFILE_FOLDER = "profiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; - private static final String PROFILE_SELECTED_KEY = "Profile_Selected"; + private static final String PROFILE_FILTER_KEY = "Profile_Filter"; List profileList = null; - List nameList = null; - private IngestProfile lastUsedProfile = null; + private static final Object PROFILE_LOCK = new Object(); List getIngestProfileList() { if (profileList == null) { @@ -35,40 +34,28 @@ public class IngestProfileList { return profileList; } - void readFilesFromDirectory() { + private void readFilesFromDirectory() { + synchronized (PROFILE_LOCK) { + File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); + File[] directoryListing = dir.listFiles(); - File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); - System.out.println(dir.toString()); //WJS-TODO remove sout - File[] directoryListing = dir.listFiles(); - - if (directoryListing != null) { - profileList = new ArrayList<>(); - nameList = new ArrayList<>(); - for (File child : directoryListing) { - String name = child.getName().split("\\.")[0]; - String context = PROFILE_FOLDER + File.separator + name; - // name = ModuleSettings.getConfigSetting(context, PROFILE_NAME_KEY); - System.out.println("-=-=-=-=-=-" + name); - nameList.add(name); - String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); - System.out.println(desc); - String selected = ModuleSettings.getConfigSetting(context, PROFILE_SELECTED_KEY); - profileList.add(new IngestProfile(name, desc, selected)); + if (directoryListing != null) { + profileList = new ArrayList<>(); + for (File child : directoryListing) { + String name = child.getName().split("\\.")[0]; + String context = PROFILE_FOLDER + File.separator + name; + String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); + String fileIngestFilter = ModuleSettings.getConfigSetting(context, PROFILE_FILTER_KEY); + profileList.add(new IngestProfile(name, desc, fileIngestFilter)); + } + } else { + profileList = Collections.emptyList(); } - } else { - profileList = Collections.emptyList(); } } void loadProfileList() { readFilesFromDirectory(); - lastUsedProfile = new IngestProfile("lastProfileUsed", "last used description here soon", "lastProfileUsed"); - //WJS-TODO add saved profile list items to list; - - } - - IngestProfile getLastUsedProfile() { - return lastUsedProfile; } void saveProfileList() { @@ -119,79 +106,75 @@ public class IngestProfileList { } static void deleteProfile(IngestProfile selectedProfile) { - try { - Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, selectedProfile.getName() + ".properties")); - Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), selectedProfile.getName() + ".properties")); - FileUtils.deleteDirectory(IngestJobSettings.getSavedModuleSettingsFolder(selectedProfile.getName() + File.separator).toFile()); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); + synchronized (PROFILE_LOCK) { + try { + Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, selectedProfile.getName() + ".properties")); + Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), selectedProfile.getName() + ".properties")); + FileUtils.deleteDirectory(IngestJobSettings.getSavedModuleSettingsFolder(selectedProfile.getName() + File.separator).toFile()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } } - } static void renameProfile(String oldName, String newName) { if (!oldName.equals(newName)) { //if renameProfile was called with the new name being the same as the old name, it is complete already - File oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, oldName + ".properties").toFile(); - File newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, newName + ".properties").toFile(); - oldFile.renameTo(newFile); - oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), oldName + ".properties").toFile(); - newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), newName + ".properties").toFile(); - oldFile.renameTo(newFile); - oldFile = IngestJobSettings.getSavedModuleSettingsFolder(oldName + File.separator).toFile(); - newFile = IngestJobSettings.getSavedModuleSettingsFolder(newName + File.separator).toFile(); - oldFile.renameTo(newFile); + synchronized (PROFILE_LOCK) { + File oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, oldName + ".properties").toFile(); + File newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, newName + ".properties").toFile(); + oldFile.renameTo(newFile); + oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), oldName + ".properties").toFile(); + newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), newName + ".properties").toFile(); + oldFile.renameTo(newFile); + oldFile = IngestJobSettings.getSavedModuleSettingsFolder(oldName + File.separator).toFile(); + newFile = IngestJobSettings.getSavedModuleSettingsFolder(newName + File.separator).toFile(); + oldFile.renameTo(newFile); + } } - } HashSet getModuleNames(String key) { - if (ModuleSettings.settingExists(this.getName(), key) == false) { - ModuleSettings.setConfigSetting(this.getName(), key, ""); - } - HashSet moduleNames = new HashSet<>(); - String modulesSetting = ModuleSettings.getConfigSetting(this.getName(), key); - if (!modulesSetting.isEmpty()) { - String[] settingNames = modulesSetting.split(", "); - for (String name : settingNames) { - // Map some old core module names to the current core module names. - switch (name) { - case "Thunderbird Parser": //NON-NLS - case "MBox Parser": //NON-NLS - moduleNames.add("Email Parser"); //NON-NLS - break; - case "File Extension Mismatch Detection": //NON-NLS - moduleNames.add("Extension Mismatch Detector"); //NON-NLS - break; - case "EWF Verify": //NON-NLS - case "E01 Verify": //NON-NLS - moduleNames.add("E01 Verifier"); //NON-NLS - break; - case "Archive Extractor": //NON-NLS - moduleNames.add("Embedded File Extractor"); //NON-NLS - break; - default: - moduleNames.add(name); + synchronized (PROFILE_LOCK) { + if (ModuleSettings.settingExists(this.getName(), key) == false) { + ModuleSettings.setConfigSetting(this.getName(), key, ""); + } + HashSet moduleNames = new HashSet<>(); + String modulesSetting = ModuleSettings.getConfigSetting(this.getName(), key); + if (!modulesSetting.isEmpty()) { + String[] settingNames = modulesSetting.split(", "); + for (String name : settingNames) { + // Map some old core module names to the current core module names. + switch (name) { + case "Thunderbird Parser": //NON-NLS + case "MBox Parser": //NON-NLS + moduleNames.add("Email Parser"); //NON-NLS + break; + case "File Extension Mismatch Detection": //NON-NLS + moduleNames.add("Extension Mismatch Detector"); //NON-NLS + break; + case "EWF Verify": //NON-NLS + case "E01 Verify": //NON-NLS + moduleNames.add("E01 Verifier"); //NON-NLS + break; + case "Archive Extractor": //NON-NLS + moduleNames.add("Embedded File Extractor"); //NON-NLS + break; + default: + moduleNames.add(name); + } } } + return moduleNames; } - return moduleNames; } -// FilesSet getFileIngestFilter() { -// if (ModuleSettings.settingExists(this.name, key) == false) { -// ModuleSettings.setConfigSetting(this.name, key, ""); -// } -// HashSet moduleNames = new HashSet<>(); -// String modulesSetting = ModuleSettings.getConfigSetting(this.name, key); -// -// } static void saveProfile(IngestProfile profile) { - System.out.println("==============PNAME===========" + profile.getName()); - String context = PROFILE_FOLDER + File.separator + profile.getName(); - - ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName());//WJS-TODO write name, desc, context - ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription());//WJS-TODO write name, desc, context - ModuleSettings.setConfigSetting(context, PROFILE_SELECTED_KEY, profile.getFileIngestFilter());//WJS-TODO write name, desc, context + synchronized (PROFILE_LOCK) { + String context = PROFILE_FOLDER + File.separator + profile.getName(); + ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName()); + ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription()); + ModuleSettings.setConfigSetting(context, PROFILE_FILTER_KEY, profile.getFileIngestFilter()); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index ecd3a04144..6890cf05ef 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -136,7 +136,7 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { } else if (!profile.getName().equals(profileNameField.getText())) { IngestProfile.renameProfile(profile.getName(), profileNameField.getText()); } - profile = new IngestProfile(profileNameField.getText(), profileDescArea.getText(), profileNameField.getText()); + profile = new IngestProfile(profileNameField.getText(), profileDescArea.getText(), ingestSettingsPanel.getSettings().getFileIngestFilter().getName()); IngestProfile.saveProfile(profile); ingestSettingsPanel.getSettings().saveAs(profileNameField.getText()); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 0da9a58764..02ae8de9b4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -56,7 +56,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 39b0aac169..c1554d9901 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -11,8 +11,11 @@ import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { @@ -157,7 +160,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addComponent(fitlerDescLabel) .addGroup(layout.createSequentialGroup() .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGap(0, 0, 0) .addComponent(filterNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 208, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(selectedModulesLabel) .addComponent(profileDescLabel)) @@ -306,6 +309,12 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op IngestProfile selectedProfile = ProfileSettingsPanel.this.profileList.getSelectedValue(); if (selectedProfile != null) { profileDescArea.setText(selectedProfile.getDescription()); + filterNameText.setText(selectedProfile.getFileIngestFilter()); + try { + filterDescArea.setText(FilesSetsManager.getInstance().getFileIngestFiltersWithDefaults().get(selectedProfile.getFileIngestFilter()).getDescription()); + } catch (FilesSetsManager.FilesSetsManagerException ex) { + filterDescArea.setText("FAILED TO LOAD FILTER"); + } selectedModulesArea.setText(""); for (String moduleName : selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY)) { selectedModulesArea.append(moduleName + "\n");// Populate the components that display the properties of the selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java index 8f78dd331b..7c80584493 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java @@ -83,7 +83,7 @@ public final class FilesSet implements Serializable { * * @return A description string, possibly the empty string. */ - String getDescription() { + public String getDescription() { return this.description; } From b407e7d93c85240ab039ff98a7196c112f7d322f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 20 Jan 2017 12:43:28 -0500 Subject: [PATCH 09/73] 2197 - removed FileIngestFilterDefsOptionsPanelController --- .../autopsy/ingest/IngestJobSettings.java | 8 +- .../autopsy/ingest/ProfileSettingsPanel.java | 11 +- ...ngestFilterDefsOptionsPanelController.java | 146 ------------------ 3 files changed, 15 insertions(+), 150 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index 68e6ab7a03..15d04c51d0 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -157,8 +157,14 @@ public class IngestJobSettings { this.store(); } - public void saveAs(String executionContext) { + /** + * Saves the settings with a new context name removing the old profile folder + * + * @param executionContext will be used to name the new folder for storing the settings + */ + void saveAs(String executionContext) { this.executionContext = executionContext; + this.createSavedModuleSettingsFolder(); this.store(); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index c1554d9901..e711f2f688 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -6,12 +6,12 @@ package org.sleuthkit.autopsy.ingest; //WJS-TODO hook up all labels and fields to bundle properties instead of plain text +import java.util.Map; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; @@ -19,6 +19,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { + private final DefaultListModel profilesListModel = new DefaultListModel<>(); /** @@ -311,9 +312,13 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op profileDescArea.setText(selectedProfile.getDescription()); filterNameText.setText(selectedProfile.getFileIngestFilter()); try { - filterDescArea.setText(FilesSetsManager.getInstance().getFileIngestFiltersWithDefaults().get(selectedProfile.getFileIngestFilter()).getDescription()); + Map fileIngestFilters = FilesSetsManager.getInstance().getCustomFileIngestFilters(); + for (FilesSet fSet : FilesSetsManager.getStandardFileIngestFilters()) { + fileIngestFilters.put(fSet.getName(), fSet); + } + filterDescArea.setText(fileIngestFilters.get(selectedProfile.getFileIngestFilter()).getDescription()); } catch (FilesSetsManager.FilesSetsManagerException ex) { - filterDescArea.setText("FAILED TO LOAD FILTER"); + filterDescArea.setText("FAILED TO LOAD FILTER"); } selectedModulesArea.setText(""); for (String moduleName : selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY)) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java deleted file mode 100644 index 6a65433120..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FileIngestFilterDefsOptionsPanelController.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2016 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.modules.interestingitems; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import javax.swing.JComponent; -import javax.swing.SwingUtilities; -import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.HelpCtx; -import org.openide.util.Lookup; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * Class for creating an FilesSetDefsPanel which will be used for configuring - * the FileIngestFilter. - */ -public final class FileIngestFilterDefsOptionsPanelController extends OptionsPanelController { - - private FilesSetDefsPanel panel; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - private boolean changed; - private static final Logger LOGGER = Logger.getLogger(FileIngestFilterDefsOptionsPanelController.class.getName()); - - /** - * Component should load its data here. - */ - @Override - public void update() { - getPanel().load(); - changed = false; - } - - - /** - * This method is called when both the Ok and Apply buttons are pressed. It - * applies to any of the panels that have been opened in the process of - * using the options pane. - */ - @Override - public void applyChanges() { - if (changed) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - getPanel().store(); - changed = false; - } - }); - } - } - - /** - * This method is called when the Cancel button is pressed. It applies to - * any of the panels that have been opened in the process of using the - * options pane. - */ - @Override - public void cancel() { - // need not do anything special, if no changes have been persisted yet - } - - @Override - public boolean isValid() { - return true; - } - - /** - * Used to determine whether any changes have been made to this controller's - * panel. - * - * @return Whether or not a change has been made. - */ - @Override - public boolean isChanged() { - return changed; - } - - @Override - public HelpCtx getHelpCtx() { - return null; - } - - @Override - public JComponent getComponent(Lookup masterLookup) { - return getPanel(); - } - - @Override - public void addPropertyChangeListener(PropertyChangeListener l) { - pcs.addPropertyChangeListener(l); - } - - @Override - public void removePropertyChangeListener(PropertyChangeListener l) { - pcs.removePropertyChangeListener(l); - } - - /** - * Creates an interestingItemsDefPanel that will be labeled to indicate it - * is for File Ingest Filter settings - * - * @return an FilesSetDefsPanel which has text and fields modified to - * indicate it is for File Ingest Filtering. - */ - private FilesSetDefsPanel getPanel() { - if (panel == null) { - panel = new FilesSetDefsPanel(FilesSetDefsPanel.PANEL_TYPE.FILE_INGEST_FILTERS); - panel.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) { - changed(); - } - } - }); - } - return panel; - } - - void changed() { - if (!changed) { - changed = true; - pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true); - } - pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null); - } - -} From b5cadd0f2d6907b759abf716df07f6303250e3ab Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 20 Jan 2017 16:39:39 -0500 Subject: [PATCH 10/73] 2197-profile area mostly switched over to having text defined via @Messages --- .../autopsy/ingest/Bundle.properties | 13 ---- .../autopsy/ingest/IngestOptionsPanel.java | 14 ++-- .../autopsy/ingest/IngestProfileList.java | 41 ++++++++++-- .../autopsy/ingest/ProfilePanel.form | 10 +-- .../autopsy/ingest/ProfilePanel.java | 30 ++++++--- .../autopsy/ingest/ProfileSettingsPanel.form | 27 +++----- .../autopsy/ingest/ProfileSettingsPanel.java | 64 ++++++++++++------- 7 files changed, 114 insertions(+), 85 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index bb1407dc3f..9e512e392c 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -122,16 +122,3 @@ IngestSettingsPanel.jCheckBoxEnableProcTimeout.text= IngestSettingsPanel.jLabelSetProcessTimeOut.text=Enable timeout to allow modules to automatically terminate after a set amount of time: IngestSettingsPanel.restartRequiredLabel.text=For this computer, a maximum of {0} file ingest threads should be used. Application restart required to take effect. IngestSettingsPanel.jLabelNumThreads.text=Number of threads to use for file ingest: -ProfileSettingsPanel.newProfileButton.text=New Profile -ProfileSettingsPanel.editProfileButton.text=Edit Profile -ProfileSettingsPanel.deleteProfileButton.text=Delete Profile -ProfileSettingsPanel.profileListLabel.text=Profiles: -ProfileSettingsPanel.profileDescArea.AccessibleContext.accessibleName= -ProfileSettingsPanel.profileDescLabel.text=Profile Description: -ProfileSettingsPanel.filterNameLabel.text=Filter: -ProfileSettingsPanel.filterNameText.text= -ProfileSettingsPanel.fitlerDescLabel.text=Filter Description: -ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules: -ProfilePanel.profileDescLabel.text=Profile Description: -ProfilePanel.profileNameLabel.text=Profile Name: -ProfilePanel.profileNameField.text= diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 52f6fb713c..b6aa94038d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -38,16 +38,16 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti } private void customizeComponents() { - setName("Temporary Name"); + setName("Temporary Name"); //WJS-TODO Bundle @Messages filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); settingsPanel = new IngestSettingsPanel(); profilePanel = new ProfileSettingsPanel(); - tabbedPane.insertTab("Settings", null, - settingsPanel, "Tootip 1", 0); - tabbedPane.insertTab("File Filters", null, - filterPanel, "Tooltip 2", 1); - tabbedPane.insertTab("Profiles", null, - profilePanel, "Tooltip 3", 2); + tabbedPane.insertTab("Settings", null, //WJS-TODO Bundle @Messages + settingsPanel, "Tootip 1", 0); //WJS-TODO Bundle @Messages + tabbedPane.insertTab("File Filters", null, //WJS-TODO Bundle @Messages + filterPanel, "Tooltip 2", 1); //WJS-TODO Bundle @Messages + tabbedPane.insertTab("Profiles", null, //WJS-TODO Bundle @Messages + profilePanel, "Tooltip 3", 2); //WJS-TODO Bundle @Messages } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java index 7385192435..c67c684ab4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest; @@ -20,7 +33,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; public class IngestProfileList { - private static final String PROFILE_FOLDER = "profiles"; + private static final String PROFILE_FOLDER = "Profiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; @@ -67,11 +80,25 @@ public class IngestProfileList { static class IngestProfile { - static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS - static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS + private static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS + private static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS private final String name; private final String description; - private final String fileIngestFilter; //can this just be the name? //WJS-TODO replace with A list of selected/unselected ingest modules and runtime settings for the modules. + private final String fileIngestFilter; + + /** + * @return the ENABLED_MODULES_KEY + */ + static String getEnabledModulesKey() { + return ENABLED_MODULES_KEY; + } + + /** + * @return the DISABLED_MODULES_KEY + */ + static String getDisabledModulesKey() { + return DISABLED_MODULES_KEY; + } IngestProfile(String name, String desc, String selected) { this.name = name; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form index b898a39e88..bb7e45eb77 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.form @@ -77,7 +77,6 @@ - @@ -88,23 +87,18 @@ - + - + - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 6890cf05ef..2225a162db 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -1,11 +1,25 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest; import java.beans.PropertyChangeListener; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; /** @@ -13,11 +27,14 @@ import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; * @author wschaefer */ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { - + +@NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", +"ProfilePanel.profiles.profileNameLabel.text=Profile Name:"}) + IngestJobSettingsPanel ingestSettingsPanel; IngestJobSettings tempSettings; IngestProfile profile; - final static String NEW_PROFILE_NAME = "TemporaryNewProfile"; + final static String NEW_PROFILE_NAME = "TemporaryNewProfile"; //WJS-TODO Bundle @Messages /** * Creates new form ProfilePanel @@ -61,7 +78,6 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { profileDescArea.setRows(5); profileDescArea.setWrapStyleWord(true); profileDescArea.setMinimumSize(new java.awt.Dimension(10, 22)); - profileDescArea.setName(""); // NOI18N profileDescArea.setPreferredSize(new java.awt.Dimension(14, 40)); profileDescPane.setViewportView(profileDescArea); @@ -69,8 +85,6 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { org.openide.awt.Mnemonics.setLocalizedText(profileNameLabel, org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.profileNameLabel.text")); // NOI18N - profileNameField.setText(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.profileNameField.text")); // NOI18N - jPanel1.setLayout(new java.awt.BorderLayout()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 02ae8de9b4..0b4ab81c67 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -53,7 +53,7 @@ - + @@ -86,12 +86,12 @@ - - - + + + - + @@ -215,20 +215,13 @@ - - - - - - - @@ -247,16 +240,11 @@ - - - - - - + - + @@ -299,6 +287,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index e711f2f688..74fe94af1c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -1,24 +1,46 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest; -//WJS-TODO hook up all labels and fields to bundle properties instead of plain text import java.util.Map; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { - +@NbBundle.Messages({"ProfileSettingsPanel.title=Profile Settings", + "ProfileSettingsPanel.profileListLabel.text=Profiles:", + "ProfileSettingsPanel.profileDescLabel.text=Profile Description:", + "ProfileSettingsPanel.filterNameLabel.text=Filter:", + "ProfileSettingsPanel.filterDescLabel.text=Filter Description:", + "ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules:", + "ProfileSettingsPanel.newProfileButton.text=New Profile", + "ProfileSettingsPanel.editProfileButton.text=Edit Profile", + "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile" +}) private final DefaultListModel profilesListModel = new DefaultListModel<>(); @@ -52,7 +74,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op profileDescLabel = new javax.swing.JLabel(); filterNameLabel = new javax.swing.JLabel(); filterNameText = new javax.swing.JLabel(); - fitlerDescLabel = new javax.swing.JLabel(); + filterDescLabel = new javax.swing.JLabel(); filterDescPane = new javax.swing.JScrollPane(); filterDescArea = new javax.swing.JTextArea(); selectedModulesPane = new javax.swing.JScrollPane(); @@ -100,20 +122,15 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op profileDescArea.setColumns(20); profileDescArea.setLineWrap(true); profileDescArea.setRows(5); - profileDescArea.setWrapStyleWord(true); profileDescArea.setMinimumSize(new java.awt.Dimension(10, 22)); - profileDescArea.setName(""); // NOI18N profileDescArea.setPreferredSize(new java.awt.Dimension(14, 40)); profileDescPane.setViewportView(profileDescArea); - profileDescArea.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileDescArea.AccessibleContext.accessibleName")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(profileDescLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileDescLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(filterNameLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.filterNameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(filterNameText, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.filterNameText.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(fitlerDescLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.fitlerDescLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(filterDescLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.filterDescLabel.text")); // NOI18N filterDescArea.setEditable(false); filterDescArea.setBackground(new java.awt.Color(240, 240, 240)); @@ -126,6 +143,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op selectedModulesArea.setEditable(false); selectedModulesArea.setBackground(new java.awt.Color(240, 240, 240)); selectedModulesArea.setColumns(20); + selectedModulesArea.setLineWrap(true); selectedModulesArea.setRows(5); selectedModulesPane.setViewportView(selectedModulesArea); @@ -149,7 +167,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(editProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE))))) + .addComponent(deleteProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 98, Short.MAX_VALUE))))) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() @@ -158,7 +176,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING))) - .addComponent(fitlerDescLabel) + .addComponent(filterDescLabel) .addGroup(layout.createSequentialGroup() .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) @@ -184,11 +202,11 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addGroup(layout.createSequentialGroup() .addComponent(profileDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(filterNameLabel) - .addComponent(filterNameText)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(filterNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(filterNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(fitlerDescLabel) + .addComponent(filterDescLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(filterDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addGap(18, 18, 18) @@ -257,7 +275,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op // feedback when isValidDefinition() is called. int option = JOptionPane.OK_OPTION; // do { - option = JOptionPane.showConfirmDialog(null, panel, "new profile title", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + option = JOptionPane.showConfirmDialog(null, panel,Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); // } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); if (option == JOptionPane.OK_OPTION) { @@ -318,11 +336,11 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } filterDescArea.setText(fileIngestFilters.get(selectedProfile.getFileIngestFilter()).getDescription()); } catch (FilesSetsManager.FilesSetsManagerException ex) { - filterDescArea.setText("FAILED TO LOAD FILTER"); + filterDescArea.setText("FAILED TO LOAD FILTER"); //WJS-TODO remove this handle / handle error correctly? / make this Bundle prop } selectedModulesArea.setText(""); - for (String moduleName : selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY)) { - selectedModulesArea.append(moduleName + "\n");// Populate the components that display the properties of the selectedProfile.getModuleNames(IngestProfile.ENABLED_MODULES_KEY); + for (String moduleName : selectedProfile.getModuleNames(IngestProfile.getEnabledModulesKey())) { + selectedModulesArea.append(moduleName + "\n"); } } @@ -335,10 +353,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private javax.swing.JButton deleteProfileButton; private javax.swing.JButton editProfileButton; private javax.swing.JTextArea filterDescArea; + private javax.swing.JLabel filterDescLabel; private javax.swing.JScrollPane filterDescPane; private javax.swing.JLabel filterNameLabel; private javax.swing.JLabel filterNameText; - private javax.swing.JLabel fitlerDescLabel; private javax.swing.JSeparator jSeparator1; private javax.swing.JButton newProfileButton; private javax.swing.JTextArea profileDescArea; From 1a979b588012cf09091aa525c6696a3cbc351cf2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 20 Jan 2017 16:46:29 -0500 Subject: [PATCH 11/73] 2197 - fixed Bundle properties name for label text --- Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java | 1 - Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java index c67c684ab4..e1ccc41735 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java @@ -204,5 +204,4 @@ public class IngestProfileList { } } } - } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 2225a162db..fa83b6734c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; public class ProfilePanel extends IngestModuleGlobalSettingsPanel { @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", -"ProfilePanel.profiles.profileNameLabel.text=Profile Name:"}) +"ProfilePanel.profileNameLabel.text=Profile Name:"}) IngestJobSettingsPanel ingestSettingsPanel; IngestJobSettings tempSettings; From 4489e48640762fbf278c66866cba18e9d1611b65 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 20 Jan 2017 16:52:20 -0500 Subject: [PATCH 12/73] 2197 allow Filter name box to auto-resize --- .../autopsy/ingest/ProfileSettingsPanel.form | 15 ++++++++++----- .../autopsy/ingest/ProfileSettingsPanel.java | 13 ++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 0b4ab81c67..6f75b9cd0c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -53,14 +53,19 @@ - - - + + + + + + + + + + - - diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 74fe94af1c..b11a0f9f11 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -176,13 +176,16 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING))) - .addComponent(filterDescLabel) .addGroup(layout.createSequentialGroup() .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(filterNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 208, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(selectedModulesLabel) - .addComponent(profileDescLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(filterDescLabel) + .addComponent(selectedModulesLabel) + .addComponent(profileDescLabel)) + .addGap(0, 0, Short.MAX_VALUE))) .addGap(14, 14, 14)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() From 25eb6b44d97c6a546c9505be96f76ad8dd87f0f4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 20 Jan 2017 17:31:21 -0500 Subject: [PATCH 13/73] 2197 checking to ensure profiles are named now --- .../autopsy/ingest/ProfilePanel.java | 25 ++++++++++++++++--- .../autopsy/ingest/ProfileSettingsPanel.java | 9 +++---- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index fa83b6734c..cc254185f8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -19,18 +19,24 @@ package org.sleuthkit.autopsy.ingest; import java.beans.PropertyChangeListener; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSetPanel; +import static org.sleuthkit.autopsy.modules.interestingitems.FilesSetPanel.getCreateNewFileIngestFilterString; +import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; /** * * @author wschaefer */ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { - -@NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", -"ProfilePanel.profileNameLabel.text=Profile Name:"}) - + + @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", + "ProfilePanel.profileNameLabel.text=Profile Name:"}) + IngestJobSettingsPanel ingestSettingsPanel; IngestJobSettings tempSettings; IngestProfile profile; @@ -161,4 +167,15 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { public void load() { } + + boolean isValidDefinition() { + if (this.profileNameField.getText().isEmpty()) { + NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( + NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profilesMustBeNamed"), + NotifyDescriptor.WARNING_MESSAGE); + DialogDisplayer.getDefault().notify(notifyDesc); + return false; + } + return true; + } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index b11a0f9f11..9147425283 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -273,17 +273,14 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op // Creating a new set definition. panel = new ProfilePanel(); } - // Do a dialog box with the files set panel until the user either enters - // a valid definition or cancels. Note that the panel gives the user - // feedback when isValidDefinition() is called. + // Do a dialog box with the profilePanel till the user enters a name or chooses cancel int option = JOptionPane.OK_OPTION; - // do { + do { option = JOptionPane.showConfirmDialog(null, panel,Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); -// } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); + } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); if (option == JOptionPane.OK_OPTION) { panel.saveSettings(); - //this.resetComponents(); load(); } From df361b5e535a4409cacd5e5bae861d60974398ba Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 10:48:07 -0500 Subject: [PATCH 14/73] 2197 - remaining text changed to @Messages, disabling during ingest added --- .../autopsy/ingest/IngestOptionsPanel.java | 73 ++++++++++++++++--- .../autopsy/ingest/IngestSettingsPanel.java | 2 +- .../autopsy/ingest/ProfilePanel.java | 11 ++- .../autopsy/ingest/ProfileSettingsPanel.java | 5 +- 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index b6aa94038d..a4a7e6273b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -18,7 +18,10 @@ */ package org.sleuthkit.autopsy.ingest; +import java.awt.EventQueue; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TYPE; @@ -27,31 +30,79 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY * Global options panel for keyword searching. */ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { - +@NbBundle.Messages({"IngestOptionsPanel.settingsTab.text=Settings", + "IngestOptionsPanel.settingsTab.toolTipText=Settings regarding resources available to ingest.", + "IngestOptionsPanel.fileFiltersTab.text=File Filters", + "IngestOptionsPanel.fileFiltersTab.toolTipText=Settings for creating and editing ingest file filters.", + "IngestOptionsPanel.profilesTab.text=Profiles", + "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles.", + "IngestOptionsPanel.title.text=Ingest Options" +}) private FilesSetDefsPanel filterPanel; private IngestSettingsPanel settingsPanel; private ProfileSettingsPanel profilePanel; - + /** + * This panel implements a property change listener that listens to ingest + * job events so it can disable the buttons on the panel if ingest is + * running. This is done to prevent changes to user-defined types while the + * type definitions are in use. + */ + IngestJobEventPropertyChangeListener ingestJobEventsListener; + IngestOptionsPanel() { initComponents(); customizeComponents(); } private void customizeComponents() { - setName("Temporary Name"); //WJS-TODO Bundle @Messages + setName(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.title.text")); filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); settingsPanel = new IngestSettingsPanel(); profilePanel = new ProfileSettingsPanel(); - tabbedPane.insertTab("Settings", null, //WJS-TODO Bundle @Messages - settingsPanel, "Tootip 1", 0); //WJS-TODO Bundle @Messages - tabbedPane.insertTab("File Filters", null, //WJS-TODO Bundle @Messages - filterPanel, "Tooltip 2", 1); //WJS-TODO Bundle @Messages - tabbedPane.insertTab("Profiles", null, //WJS-TODO Bundle @Messages - profilePanel, "Tooltip 3", 2); //WJS-TODO Bundle @Messages - - + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text") , null, + settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 0); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.text"), null, + filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 1); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, + profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 2); + addIngestJobEventsListener(); + } + + /** + * Add a property change listener that listens to ingest job events to + * disable the buttons on the panel if ingest is running. This is done to + * prevent changes to user-defined types while the type definitions are in + * use. + */ + // TODO: Disabling during ingest would not be necessary if the file ingest + // modules obtained and shared a per data source ingest job snapshot of the + // file type definitions. + private void addIngestJobEventsListener() { + ingestJobEventsListener = new IngestJobEventPropertyChangeListener(); + IngestManager.getInstance().addIngestJobEventListener(ingestJobEventsListener); } + /** + * A property change listener that listens to ingest job events. + */ + private class IngestJobEventPropertyChangeListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + enableTabs(); + } + }); + } + } + + private void enableTabs(){ + boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); + tabbedPane.setEnabled(!ingestIsRunning); + } + @Override public void addPropertyChangeListener(PropertyChangeListener l) { filterPanel.addPropertyChangeListener(l); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java index 63143d5174..26359d1e62 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index cc254185f8..3f32a85307 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -23,10 +23,7 @@ import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; -import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; -import org.sleuthkit.autopsy.modules.interestingitems.FilesSetPanel; -import static org.sleuthkit.autopsy.modules.interestingitems.FilesSetPanel.getCreateNewFileIngestFilterString; -import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; + /** * @@ -35,12 +32,14 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; public class ProfilePanel extends IngestModuleGlobalSettingsPanel { @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", - "ProfilePanel.profileNameLabel.text=Profile Name:"}) + "ProfilePanel.profileNameLabel.text=Profile Name:", + "ProfilePanel.newProfileText=NewEmptyProfile", + "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named."}) IngestJobSettingsPanel ingestSettingsPanel; IngestJobSettings tempSettings; IngestProfile profile; - final static String NEW_PROFILE_NAME = "TemporaryNewProfile"; //WJS-TODO Bundle @Messages + final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); /** * Creates new form ProfilePanel diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 9147425283..88cbb18eb1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -39,7 +39,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op "ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules:", "ProfileSettingsPanel.newProfileButton.text=New Profile", "ProfileSettingsPanel.editProfileButton.text=Edit Profile", - "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile" + "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile", + "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter" }) private final DefaultListModel profilesListModel = new DefaultListModel<>(); @@ -336,7 +337,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } filterDescArea.setText(fileIngestFilters.get(selectedProfile.getFileIngestFilter()).getDescription()); } catch (FilesSetsManager.FilesSetsManagerException ex) { - filterDescArea.setText("FAILED TO LOAD FILTER"); //WJS-TODO remove this handle / handle error correctly? / make this Bundle prop + filterDescArea.setText(NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.messages.filterLoadFailed")); } selectedModulesArea.setText(""); for (String moduleName : selectedProfile.getModuleNames(IngestProfile.getEnabledModulesKey())) { From 5afe85aaa5558b72af808842e2605e7065f6383c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 11:18:17 -0500 Subject: [PATCH 15/73] 2197-bug fix for when ingest settings tab wasn't last selected --- .../autopsy/ingest/Bundle.properties | 2 + .../autopsy/ingest/Bundle_ja.properties | 2 + .../autopsy/ingest/IngestOptionsPanel.java | 3 + .../autopsy/ingest/IngestSettingsPanel.form | 59 +++++++++++++------ .../autopsy/ingest/IngestSettingsPanel.java | 52 +++++++++++----- .../autopsy/ingest/ProfileSettingsPanel.form | 36 ++++++++--- .../autopsy/ingest/ProfileSettingsPanel.java | 36 ++++++++--- .../interestingitems/Bundle.properties | 1 + .../interestingitems/Bundle_ja.properties | 1 + .../interestingitems/FilesSetDefsPanel.form | 41 +++++++++++-- .../interestingitems/FilesSetDefsPanel.java | 37 ++++++++++-- 11 files changed, 208 insertions(+), 62 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 9e512e392c..333d179c74 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -122,3 +122,5 @@ IngestSettingsPanel.jCheckBoxEnableProcTimeout.text= IngestSettingsPanel.jLabelSetProcessTimeOut.text=Enable timeout to allow modules to automatically terminate after a set amount of time: IngestSettingsPanel.restartRequiredLabel.text=For this computer, a maximum of {0} file ingest threads should be used. Application restart required to take effect. IngestSettingsPanel.jLabelNumThreads.text=Number of threads to use for file ingest: +IngestSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. +ProfileSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index eb2713faa1..7f83c8c5c0 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -115,3 +115,5 @@ IngestSettingsPanel.jLabelNumThreads.text=\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u IngestSettingsPanel.jLabelProcessTimeOutUnits.text=\u6642\u9593 IngestSettingsPanel.jLabelSetProcessTimeOut.text=\u4e00\u5b9a\u306e\u6642\u9593\u304c\u904e\u304e\u305f\u5f8c\u306b\u81ea\u52d5\u7684\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u505c\u6b62\u3067\u304d\u308b\u3088\u3046\u306b\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u3092\u6709\u52b9\u5316\uff1a IngestSettingsPanel.restartRequiredLabel.text=\u3053\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u3067\u306f\u6700\u5927{0}\u306e\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u7528\u3059\u3079\u304d\u3067\u3059\u3002\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u518d\u8d77\u52d5\u304c\u5fc5\u8981\u3067\u3059\u3002 +IngestSettingsPanel.ingestWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +ProfileSettingsPanel.ingestWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index a4a7e6273b..5b4ebdac8b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -101,6 +101,9 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti private void enableTabs(){ boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); tabbedPane.setEnabled(!ingestIsRunning); + settingsPanel.enableButtons(!ingestIsRunning); + profilePanel.enableButtons(!ingestIsRunning); + } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form index a483a0cdb1..4996fc373f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form @@ -46,32 +46,40 @@ - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + + + + + - @@ -95,7 +103,9 @@ - + + + @@ -168,6 +178,21 @@ + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java index 26359d1e62..5a1bd0cd8b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -72,7 +72,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { } }; this.jFormattedTextFieldProcTimeOutHrs.getDocument().addDocumentListener(docListener); - + this.ingestWarningLabel.setVisible(false); } void load() { @@ -107,6 +107,13 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { return true; } + void enableButtons(boolean isEnabled){ + numberOfFileIngestThreadsComboBox.setEnabled(isEnabled); + jFormattedTextFieldProcTimeOutHrs.setEnabled(isEnabled); + jCheckBoxEnableProcTimeout.setEnabled(isEnabled); + ingestWarningLabel.setVisible(!isEnabled); + } + /** * 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 @@ -126,6 +133,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { jCheckBoxEnableProcTimeout = new javax.swing.JCheckBox(); jFormattedTextFieldProcTimeOutHrs = new JFormattedTextField(NumberFormat.getIntegerInstance()); jLabelProcessTimeOutUnits = new javax.swing.JLabel(); + ingestWarningLabel = new javax.swing.JLabel(); jScrollPane1.setBorder(null); @@ -158,6 +166,10 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { org.openide.awt.Mnemonics.setLocalizedText(jLabelProcessTimeOutUnits, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jLabelProcessTimeOutUnits.text")); // NOI18N + ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ingestWarningLabel.text")); // NOI18N + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( @@ -165,24 +177,29 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(restartRequiredLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelNumThreads) - .addComponent(jLabelSetProcessTimeOut) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(jCheckBoxEnableProcTimeout) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabelProcessTimeOutUnits))) - .addGap(213, 213, 213))) - .addGap(215, 215, 215)) + .addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(restartRequiredLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabelNumThreads) + .addComponent(jLabelSetProcessTimeOut) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(jCheckBoxEnableProcTimeout) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabelProcessTimeOutUnits))) + .addGap(213, 213, 213))) + .addGap(215, 215, 215)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(ingestWarningLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -201,7 +218,9 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabelProcessTimeOutUnits))) - .addContainerGap(298, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ingestWarningLabel) + .addContainerGap(277, Short.MAX_VALUE)) ); jScrollPane1.setViewportView(jPanel1); @@ -234,6 +253,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.ButtonGroup buttonGroup3; + private javax.swing.JLabel ingestWarningLabel; private javax.swing.JCheckBox jCheckBoxEnableProcTimeout; private javax.swing.JFormattedTextField jFormattedTextFieldProcTimeOutHrs; private javax.swing.JLabel jLabelNumThreads; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 6f75b9cd0c..6c37eb6522 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -45,14 +45,6 @@ - - - - - - - - @@ -66,6 +58,18 @@ + + + + + + + + + + + + @@ -111,6 +115,7 @@ + @@ -305,5 +310,20 @@ + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 88cbb18eb1..cbf428cbc3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -52,6 +52,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op initComponents(); this.profileList.setModel(profilesListModel); this.profileList.addListSelectionListener(new ProfileSettingsPanel.ProfileListSelectionListener()); + ingestWarningLabel.setVisible(false); } /** @@ -81,6 +82,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op selectedModulesPane = new javax.swing.JScrollPane(); selectedModulesArea = new javax.swing.JTextArea(); selectedModulesLabel = new javax.swing.JLabel(); + ingestWarningLabel = new javax.swing.JLabel(); setBorder(javax.swing.BorderFactory.createEtchedBorder()); @@ -150,6 +152,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op org.openide.awt.Mnemonics.setLocalizedText(selectedModulesLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.selectedModulesLabel.text")); // NOI18N + ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.ingestWarningLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -171,12 +177,6 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addComponent(deleteProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 98, Short.MAX_VALUE))))) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) - .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING))) .addGroup(layout.createSequentialGroup() .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -186,7 +186,16 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addComponent(filterDescLabel) .addComponent(selectedModulesLabel) .addComponent(profileDescLabel)) - .addGap(0, 0, Short.MAX_VALUE))) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(ingestWarningLabel) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) + .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING)))) .addGap(14, 14, 14)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() @@ -222,7 +231,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(newProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(editProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(deleteProfileButton)) + .addComponent(deleteProfileButton) + .addComponent(ingestWarningLabel)) .addContainerGap()) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() @@ -246,7 +256,14 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op this.resetComponents(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteProfileButtonActionPerformed - + + void enableButtons(boolean isEnabled){ + newProfileButton.setEnabled(isEnabled); + editProfileButton.setEnabled(isEnabled); + deleteProfileButton.setEnabled(isEnabled); + ingestWarningLabel.setVisible(!isEnabled); + } + private void resetComponents() { if (!this.profilesListModel.isEmpty()) { this.profileList.setSelectedIndex(0); @@ -358,6 +375,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private javax.swing.JScrollPane filterDescPane; private javax.swing.JLabel filterNameLabel; private javax.swing.JLabel filterNameText; + private javax.swing.JLabel ingestWarningLabel; private javax.swing.JSeparator jSeparator1; private javax.swing.JButton newProfileButton; private javax.swing.JTextArea profileDescArea; diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties index 405269afb6..52aede37df 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties @@ -80,3 +80,4 @@ FilesSetDefsPanel.filesRadioButton.text=Files FilesSetRulePanel.allRadioButton.text=All FilesSetDefsPanel.ingoreUnallocCheckbox.text=Ignore Unallocated Space FilesSetDefsPanel.ingoreUnallocCheckbox.toolTipText=Ignores unallocated space, such as deleted files. May run faster but produce less complete results. +FilesSetDefsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle_ja.properties index 078be65eb0..2010d61f65 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle_ja.properties @@ -49,3 +49,4 @@ FilesSetDefsPanel.fileNameExtensionRadioButton.text=\u62e1\u5f35\u5b50\u306e\u30 FilesSetDefsPanel.rulesListLabel.text=\u30eb\u30fc\u30eb\uff1a FilesSetDefsPanel.editRuleButton.text=\u30eb\u30fc\u30eb\u3092\u7de8\u96c6 FilesSetDefsPanel.filesRadioButton.text=\u30d5\u30a1\u30a4\u30eb +FilesSetDefsPanel.ingestWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form index 4565237aa8..29bd143b28 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form @@ -120,8 +120,14 @@ - - + + + + + + + + @@ -195,10 +201,18 @@ - - - - + + + + + + + + + + + + @@ -839,6 +853,21 @@ + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 2afc136613..8255e0c94e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -167,6 +167,16 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp } } + void enableButtons(boolean isEnabled) { + newRuleButton.setEnabled(isEnabled); + newSetButton.setEnabled(isEnabled); + editRuleButton.setEnabled(isEnabled); + editSetButton.setEnabled(isEnabled); + deleteRuleButton.setEnabled(isEnabled); + deleteSetButton.setEnabled(isEnabled); + ingestWarningLabel.setVisible(!isEnabled); + } + /** * @inheritDoc */ @@ -562,6 +572,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp fileSizeSpinner = new javax.swing.JSpinner(); fileSizeUnitComboBox = new javax.swing.JComboBox(); ingoreUnallocCheckbox = new javax.swing.JCheckBox(); + ingestWarningLabel = new javax.swing.JLabel(); setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); @@ -760,6 +771,10 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp ingoreUnallocCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingoreUnallocCheckbox.toolTipText")); // NOI18N ingoreUnallocCheckbox.setEnabled(false); + ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingestWarningLabel.text")); // NOI18N + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( @@ -811,8 +826,12 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp .addComponent(ignoreKnownFilesCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(ingoreUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jLabel5) - .addComponent(jLabel6))) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel5) + .addComponent(jLabel6)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ingestWarningLabel)))) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(29, 29, 29) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -870,10 +889,15 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp .addComponent(editSetButton) .addComponent(deleteSetButton))) .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jLabel6) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel5) - .addGap(1, 1, 1) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel5) + .addGap(1, 1, 1)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addComponent(ingestWarningLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))) .addComponent(setDescScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(6, 6, 6) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) @@ -1013,6 +1037,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private javax.swing.JComboBox fileSizeUnitComboBox; private javax.swing.JRadioButton filesRadioButton; private javax.swing.JCheckBox ignoreKnownFilesCheckbox; + private javax.swing.JLabel ingestWarningLabel; private javax.swing.JCheckBox ingoreUnallocCheckbox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; From 57ef8159d91658e6e5e3e44824afa33a4b02021a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 11:22:56 -0500 Subject: [PATCH 16/73] 2197-enable/disable buttons on file ingest filter tab --- Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java | 1 + .../autopsy/modules/interestingitems/FilesSetDefsPanel.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 5b4ebdac8b..314f6ac45a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -103,6 +103,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti tabbedPane.setEnabled(!ingestIsRunning); settingsPanel.enableButtons(!ingestIsRunning); profilePanel.enableButtons(!ingestIsRunning); + filterPanel.enableButtons(!ingestIsRunning); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 8255e0c94e..3392623275 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -86,7 +86,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp this.setsList.addListSelectionListener(new FilesSetDefsPanel.SetsListSelectionListener()); this.rulesList.setModel(rulesListModel); this.rulesList.addListSelectionListener(new FilesSetDefsPanel.RulesListSelectionListener()); - + this.ingestWarningLabel.setVisible(false); if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { //Hide the mimetype settings when this is displaying FileSet rules instead of interesting item rules this.mimeTypeComboBox.setVisible(false); this.jLabel7.setVisible(false); @@ -167,7 +167,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp } } - void enableButtons(boolean isEnabled) { + public void enableButtons(boolean isEnabled) { newRuleButton.setEnabled(isEnabled); newSetButton.setEnabled(isEnabled); editRuleButton.setEnabled(isEnabled); From 80c85daef88c3d90bf7da0493a38b6401838bf9a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 12:00:49 -0500 Subject: [PATCH 17/73] 2197-buttons should no longer re-enable before ingest finishes --- .../autopsy/ingest/IngestProfileList.java | 8 ++- .../autopsy/ingest/ProfileSettingsPanel.java | 53 ++++++++++--------- .../interestingitems/FilesSetDefsPanel.java | 18 ++++--- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java index e1ccc41735..67920f0459 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java @@ -31,13 +31,13 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -public class IngestProfileList { +class IngestProfileList { private static final String PROFILE_FOLDER = "Profiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; - List profileList = null; + private List profileList = null; private static final Object PROFILE_LOCK = new Object(); List getIngestProfileList() { @@ -70,6 +70,10 @@ public class IngestProfileList { void loadProfileList() { readFilesFromDirectory(); } + + List getProfileList(){ + return this.profileList; + } void saveProfileList() { //save last used profile diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index cbf428cbc3..7ae3833087 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -31,18 +31,19 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { -@NbBundle.Messages({"ProfileSettingsPanel.title=Profile Settings", - "ProfileSettingsPanel.profileListLabel.text=Profiles:", - "ProfileSettingsPanel.profileDescLabel.text=Profile Description:", - "ProfileSettingsPanel.filterNameLabel.text=Filter:", - "ProfileSettingsPanel.filterDescLabel.text=Filter Description:", - "ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules:", - "ProfileSettingsPanel.newProfileButton.text=New Profile", - "ProfileSettingsPanel.editProfileButton.text=Edit Profile", - "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile", - "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter" -}) - + + @NbBundle.Messages({"ProfileSettingsPanel.title=Profile Settings", + "ProfileSettingsPanel.profileListLabel.text=Profiles:", + "ProfileSettingsPanel.profileDescLabel.text=Profile Description:", + "ProfileSettingsPanel.filterNameLabel.text=Filter:", + "ProfileSettingsPanel.filterDescLabel.text=Filter Description:", + "ProfileSettingsPanel.selectedModulesLabel.text=Selected Ingest Modules:", + "ProfileSettingsPanel.newProfileButton.text=New Profile", + "ProfileSettingsPanel.editProfileButton.text=Edit Profile", + "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile", + "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter" + }) + private final DefaultListModel profilesListModel = new DefaultListModel<>(); /** @@ -256,14 +257,14 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op this.resetComponents(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteProfileButtonActionPerformed - - void enableButtons(boolean isEnabled){ + + void enableButtons(boolean isEnabled) { newProfileButton.setEnabled(isEnabled); editProfileButton.setEnabled(isEnabled); deleteProfileButton.setEnabled(isEnabled); - ingestWarningLabel.setVisible(!isEnabled); + ingestWarningLabel.setVisible(!isEnabled); } - + private void resetComponents() { if (!this.profilesListModel.isEmpty()) { this.profileList.setSelectedIndex(0); @@ -294,7 +295,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op // Do a dialog box with the profilePanel till the user enters a name or chooses cancel int option = JOptionPane.OK_OPTION; do { - option = JOptionPane.showConfirmDialog(null, panel,Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + option = JOptionPane.showConfirmDialog(null, panel, Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); if (option == JOptionPane.OK_OPTION) { @@ -320,15 +321,17 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op profilesListModel.clear(); IngestProfileList iList = new IngestProfileList(); iList.loadProfileList(); - for (IngestProfile profile : iList.profileList) { + for (IngestProfile profile : iList.getProfileList()) { profilesListModel.addElement(profile); } - if (profilesListModel.isEmpty()) { - editProfileButton.setEnabled(false); - deleteProfileButton.setEnabled(false); - } else { - editProfileButton.setEnabled(true); - deleteProfileButton.setEnabled(true); + if (newProfileButton.isEnabled()) { + if (profilesListModel.isEmpty()) { + editProfileButton.setEnabled(false); + deleteProfileButton.setEnabled(false); + } else { + editProfileButton.setEnabled(true); + deleteProfileButton.setEnabled(true); + } } profileList.setSelectedIndex(currentIndex); } @@ -354,7 +357,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } filterDescArea.setText(fileIngestFilters.get(selectedProfile.getFileIngestFilter()).getDescription()); } catch (FilesSetsManager.FilesSetsManagerException ex) { - filterDescArea.setText(NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.messages.filterLoadFailed")); + filterDescArea.setText(NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.messages.filterLoadFailed")); } selectedModulesArea.setText(""); for (String moduleName : selectedProfile.getModuleNames(IngestProfile.getEnabledModulesKey())) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 3392623275..7251e152d9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -65,6 +65,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private final JButton cancelButton = new JButton("Cancel"); private final PANEL_TYPE panelType; private final String ruleDialogTitle; + private boolean canBeEnabled = true; // The following is a map of interesting files set names to interesting // files set definitions. It is a snapshot of the files set definitions @@ -168,6 +169,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp } public void enableButtons(boolean isEnabled) { + canBeEnabled = isEnabled; newRuleButton.setEnabled(isEnabled); newSetButton.setEnabled(isEnabled); editRuleButton.setEnabled(isEnabled); @@ -230,7 +232,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp this.setDescriptionTextArea.setText(""); this.ignoreKnownFilesCheckbox.setSelected(true); this.ingoreUnallocCheckbox.setSelected(true); - this.newSetButton.setEnabled(true); + this.newSetButton.setEnabled(true && canBeEnabled); this.editSetButton.setEnabled(false); this.deleteSetButton.setEnabled(false); } @@ -250,7 +252,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp this.equalitySignComboBox.setSelectedIndex(2); this.fileSizeUnitComboBox.setSelectedIndex(1); this.fileSizeSpinner.setValue(0); - this.newRuleButton.setEnabled(!this.setsListModel.isEmpty()); + this.newRuleButton.setEnabled(!this.setsListModel.isEmpty() && canBeEnabled); this.editRuleButton.setEnabled(false); this.deleteRuleButton.setEnabled(false); } @@ -279,9 +281,9 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp FilesSetDefsPanel.this.ignoreKnownFilesCheckbox.setSelected(selectedSet.ignoresKnownFiles()); FilesSetDefsPanel.this.ingoreUnallocCheckbox.setSelected(selectedSet.ingoresUnallocatedSpace()); // Enable the new, edit and delete set buttons. - FilesSetDefsPanel.this.newSetButton.setEnabled(true); - FilesSetDefsPanel.this.editSetButton.setEnabled(true); - FilesSetDefsPanel.this.deleteSetButton.setEnabled(true); + FilesSetDefsPanel.this.newSetButton.setEnabled(true && canBeEnabled); + FilesSetDefsPanel.this.editSetButton.setEnabled(true && canBeEnabled); + FilesSetDefsPanel.this.deleteSetButton.setEnabled(true && canBeEnabled); // Populate the rule definitions list, sorted by name. TreeMap rules = new TreeMap<>(selectedSet.getRules()); @@ -367,9 +369,9 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp } // Enable the new, edit and delete rule buttons. - FilesSetDefsPanel.this.newRuleButton.setEnabled(true); - FilesSetDefsPanel.this.editRuleButton.setEnabled(true); - FilesSetDefsPanel.this.deleteRuleButton.setEnabled(true); + FilesSetDefsPanel.this.newRuleButton.setEnabled(true && canBeEnabled); + FilesSetDefsPanel.this.editRuleButton.setEnabled(true && canBeEnabled); + FilesSetDefsPanel.this.deleteRuleButton.setEnabled(true && canBeEnabled); } else { FilesSetDefsPanel.this.resetRuleComponents(); } From 00e52bd873266eac87254b1f44450b70a36bacff Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 12:21:23 -0500 Subject: [PATCH 18/73] 2197 removed saving from cancel method of ingest options panel --- .../org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 314f6ac45a..db51f5ea71 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -143,11 +143,9 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti boolean valid() { return true; } - - public void cancel() { - saveSettings(); + + void cancel(){ } - /** * 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 From a818e0be7a79fdd6c9ee01c7f04f2e64980e1aa6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 15:37:18 -0500 Subject: [PATCH 19/73] 2197 documentation fixes --- .../autopsy/ingest/IngestJobSettings.java | 15 +++- .../autopsy/ingest/IngestOptionsPanel.java | 78 ++++++++++++------- .../ingest/IngestOptionsPanelController.java | 35 ++++++++- .../autopsy/ingest/IngestProfileList.java | 68 +++++++++++++--- .../autopsy/ingest/IngestSettingsPanel.java | 11 +++ .../autopsy/ingest/ProfilePanel.java | 16 +++- .../autopsy/ingest/ProfileSettingsPanel.java | 16 ++++ docs/doxygen/modAdvanced.dox | 1 + 8 files changed, 191 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index 15d04c51d0..03fa136a80 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -57,6 +57,15 @@ public class IngestJobSettings { private static final String MODULE_SETTINGS_FOLDER_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), IngestJobSettings.MODULE_SETTINGS_FOLDER).toAbsolutePath().toString(); private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS private static final Logger LOGGER = Logger.getLogger(IngestJobSettings.class.getName()); + + /** + * @return the ENABLED_MODULES_KEY + */ + static String getEnabledModulesKey() { + return ENABLED_MODULES_KEY; + } + + private FilesSet fileIngestFilter; private String executionContext; private final IngestType ingestType; @@ -510,8 +519,8 @@ public class IngestJobSettings { disabledModuleNames.add(moduleName); } } - ModuleSettings.setConfigSetting(this.executionContext, ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(enabledModuleNames)); - ModuleSettings.setConfigSetting(this.executionContext, DISABLED_MODULES_KEY, makeCommaSeparatedValuesList(disabledModuleNames)); + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(enabledModuleNames)); + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.DISABLED_MODULES_KEY, makeCommaSeparatedValuesList(disabledModuleNames)); /** * Save the last used File Ingest Filter setting for this context. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index db51f5ea71..7d6964022d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,14 +30,15 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY * Global options panel for keyword searching. */ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { -@NbBundle.Messages({"IngestOptionsPanel.settingsTab.text=Settings", - "IngestOptionsPanel.settingsTab.toolTipText=Settings regarding resources available to ingest.", - "IngestOptionsPanel.fileFiltersTab.text=File Filters", - "IngestOptionsPanel.fileFiltersTab.toolTipText=Settings for creating and editing ingest file filters.", - "IngestOptionsPanel.profilesTab.text=Profiles", - "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles.", - "IngestOptionsPanel.title.text=Ingest Options" -}) + + @NbBundle.Messages({"IngestOptionsPanel.settingsTab.text=Settings", + "IngestOptionsPanel.settingsTab.toolTipText=Settings regarding resources available to ingest.", + "IngestOptionsPanel.fileFiltersTab.text=File Filters", + "IngestOptionsPanel.fileFiltersTab.toolTipText=Settings for creating and editing ingest file filters.", + "IngestOptionsPanel.profilesTab.text=Profiles", + "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles.", + "IngestOptionsPanel.title.text=Ingest Options" + }) private FilesSetDefsPanel filterPanel; private IngestSettingsPanel settingsPanel; private ProfileSettingsPanel profilePanel; @@ -48,35 +49,32 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti * type definitions are in use. */ IngestJobEventPropertyChangeListener ingestJobEventsListener; - + IngestOptionsPanel() { initComponents(); customizeComponents(); } private void customizeComponents() { - setName(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.title.text")); + setName(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.title.text")); filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); settingsPanel = new IngestSettingsPanel(); profilePanel = new ProfileSettingsPanel(); - tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text") , null, - settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 0); - tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.text"), null, - filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 1); - tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, - profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 2); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text"), null, + settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 0); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.text"), null, + filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 1); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, + profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 2); addIngestJobEventsListener(); } - - /** + + /** * Add a property change listener that listens to ingest job events to * disable the buttons on the panel if ingest is running. This is done to * prevent changes to user-defined types while the type definitions are in * use. */ - // TODO: Disabling during ingest would not be necessary if the file ingest - // modules obtained and shared a per data source ingest job snapshot of the - // file type definitions. private void addIngestJobEventsListener() { ingestJobEventsListener = new IngestJobEventPropertyChangeListener(); IngestManager.getInstance().addIngestJobEventListener(ingestJobEventsListener); @@ -97,16 +95,23 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti }); } } - - private void enableTabs(){ + + /** + * Disables tabs and options inside of tabs during Ingest, and re-enables + * them after Ingest is complete or cancelled. + */ + private void enableTabs() { boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); tabbedPane.setEnabled(!ingestIsRunning); settingsPanel.enableButtons(!ingestIsRunning); profilePanel.enableButtons(!ingestIsRunning); filterPanel.enableButtons(!ingestIsRunning); - + } - + + /** + * @inheritDoc + */ @Override public void addPropertyChangeListener(PropertyChangeListener l) { filterPanel.addPropertyChangeListener(l); @@ -114,6 +119,9 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti profilePanel.addPropertyChangeListener(l); } + /** + * @inheritDoc + */ @Override public void removePropertyChangeListener(PropertyChangeListener l) { filterPanel.removePropertyChangeListener(l); @@ -121,6 +129,9 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti profilePanel.removePropertyChangeListener(l); } + /** + * @inheritDoc + */ @Override public void saveSettings() { filterPanel.store(); @@ -128,11 +139,17 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti profilePanel.store(); } + /** + * @inheritDoc + */ @Override public void store() { saveSettings(); } + /** + * @inheritDoc + */ @Override public void load() { filterPanel.load(); @@ -143,9 +160,14 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti boolean valid() { return true; } - - void cancel(){ + + /** + * Method called when the cancel button is clicked. + */ + void cancel() { + //doesn't need to do anything } + /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java index a683261fde..ec086ba9b4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2016 Basis Technology Corp. + * Copyright 2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,12 +40,20 @@ public class IngestOptionsPanelController extends OptionsPanelController { private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; + /** + * @inheritDoc + */ @Override public void update() { getPanel().load(); changed = false; } + /** + * Get the IngestOptionsPanel which is contained inside this controller. + * + * @return panel + */ private IngestOptionsPanel getPanel() { if (panel == null) { panel = new IngestOptionsPanel(); @@ -61,6 +69,9 @@ public class IngestOptionsPanelController extends OptionsPanelController { return panel; } + /** + * @inheritDoc + */ @Override public void applyChanges() { if (changed) { @@ -73,38 +84,58 @@ public class IngestOptionsPanelController extends OptionsPanelController { }); } } - + /** + * @inheritDoc + */ @Override public void cancel() { getPanel().cancel(); } + /** + * @inheritDoc + */ @Override public boolean isValid() { return getPanel().valid(); } + /** + * @inheritDoc + */ @Override public boolean isChanged() { return changed; } + /** + * @inheritDoc + */ @Override public JComponent getComponent(Lookup lkp) { return getPanel(); } + /** + * @inheritDoc + */ @Override public HelpCtx getHelpCtx() { return null; } + /** + * @inheritDoc + */ @Override public void addPropertyChangeListener(PropertyChangeListener pl) { pcs.addPropertyChangeListener(pl); } + /** + * @inheritDoc + */ @Override public void removePropertyChangeListener(PropertyChangeListener pl) { pcs.removePropertyChangeListener(pl); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java index 67920f0459..09d6d11fdc 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java @@ -47,6 +47,9 @@ class IngestProfileList { return profileList; } + /** + * Read the stored profile definitions from their directory. + */ private void readFilesFromDirectory() { synchronized (PROFILE_LOCK) { File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); @@ -67,14 +70,25 @@ class IngestProfileList { } } + /** + * Loads the list of profiles from disk. + */ void loadProfileList() { readFilesFromDirectory(); } - - List getProfileList(){ + + /** + * Gets the list of profiles which currently exist. + * + * @return profileList + */ + List getProfileList() { return this.profileList; } + /** + * Saves the list of profiles which currently exist to disk. + */ void saveProfileList() { //save last used profile for (IngestProfile profile : getIngestProfileList()) { @@ -82,26 +96,24 @@ class IngestProfileList { } } + /** + * An individual Ingest Profile, consists of a name, a description, and a + * FileIngestFilter. The name can be used to find the ModuleSettings for + * this profile. + */ static class IngestProfile { - private static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS - private static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS private final String name; private final String description; private final String fileIngestFilter; /** + * The key for Enabled ingest modules + * * @return the ENABLED_MODULES_KEY */ static String getEnabledModulesKey() { - return ENABLED_MODULES_KEY; - } - - /** - * @return the DISABLED_MODULES_KEY - */ - static String getDisabledModulesKey() { - return DISABLED_MODULES_KEY; + return IngestJobSettings.getEnabledModulesKey(); } IngestProfile(String name, String desc, String selected) { @@ -110,12 +122,19 @@ class IngestProfileList { this.fileIngestFilter = selected; } + /** + * The string value of an IngestProfile is simply its name + * + * @return getName(); + */ @Override public String toString() { return getName(); } /** + * The unique name field for this Ingest Profile. + * * @return the name */ String getName() { @@ -123,6 +142,8 @@ class IngestProfileList { } /** + * The optional user defined description of this Ingest Profile. + * * @return the description */ String getDescription() { @@ -130,12 +151,19 @@ class IngestProfileList { } /** + * The file ingest filter which was selected to be used. + * * @return the fileIngestFilter */ String getFileIngestFilter() { return fileIngestFilter; } + /** + * Deletes all of the files which are currently storing a profile. + * + * @param selectedProfile + */ static void deleteProfile(IngestProfile selectedProfile) { synchronized (PROFILE_LOCK) { try { @@ -148,6 +176,12 @@ class IngestProfileList { } } + /** + * Renames the files and directories associated with a profile + * + * @param oldName the name of the profile you want to rename + * @param newName the name which you want the profile to have + */ static void renameProfile(String oldName, String newName) { if (!oldName.equals(newName)) { //if renameProfile was called with the new name being the same as the old name, it is complete already synchronized (PROFILE_LOCK) { @@ -164,6 +198,11 @@ class IngestProfileList { } } + /** + * Gets the module names for a given key. + * + * @param key The key string. + */ HashSet getModuleNames(String key) { synchronized (PROFILE_LOCK) { if (ModuleSettings.settingExists(this.getName(), key) == false) { @@ -199,6 +238,11 @@ class IngestProfileList { } } + /** + * Save a Ingest profile file in the profile folder. + * + * @param profile + */ static void saveProfile(IngestProfile profile) { synchronized (PROFILE_LOCK) { String context = PROFILE_FOLDER + File.separator + profile.getName(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java index 5a1bd0cd8b..4a6c77d896 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -75,6 +75,9 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { this.ingestWarningLabel.setVisible(false); } + /** + * Load the existing settings. + */ void load() { numberOfFileIngestThreadsComboBox.setSelectedItem(UserPreferences.numberOfFileIngestThreads()); if (UserPreferences.getIsTimeOutEnabled()) { @@ -92,6 +95,9 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { } } + /** + * Store the existing settings. + */ void store() { UserPreferences.setNumberOfFileIngestThreads((Integer) numberOfFileIngestThreadsComboBox.getSelectedItem()); @@ -107,6 +113,11 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { return true; } + /** + * Enable or Disable buttons based on whether Ingest is running. + * + * @param isEnabled + */ void enableButtons(boolean isEnabled){ numberOfFileIngestThreadsComboBox.setEnabled(isEnabled); jFormattedTextFieldProcTimeOutHrs.setEnabled(isEnabled); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 3f32a85307..fc6c912480 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -24,10 +24,8 @@ import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; - /** - * - * @author wschaefer + * Panel to display options for profile creation. */ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { @@ -39,7 +37,7 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { IngestJobSettingsPanel ingestSettingsPanel; IngestJobSettings tempSettings; IngestProfile profile; - final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); + final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); /** * Creates new form ProfilePanel @@ -148,6 +146,9 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { private javax.swing.JLabel profileNameLabel; // End of variables declaration//GEN-END:variables + /** + * Save a new or edited profile. + */ @Override public void saveSettings() { if (profile == null) { @@ -160,6 +161,9 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { ingestSettingsPanel.getSettings().saveAs(profileNameField.getText()); } + /** + * Save a new or edited profile. + */ public void store() { saveSettings(); } @@ -167,6 +171,10 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { public void load() { } + /** + * Checks that information entered constitutes a valid ingest profile. + * @return true for valid, false for invalid. + */ boolean isValidDefinition() { if (this.profileNameField.getText().isEmpty()) { NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 7ae3833087..a7b3f9c162 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -258,6 +258,11 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteProfileButtonActionPerformed + /** + * Enable / disable buttons, so they can be disabled while ingest is running. + * + * @param isEnabled + */ void enableButtons(boolean isEnabled) { newProfileButton.setEnabled(isEnabled); editProfileButton.setEnabled(isEnabled); @@ -265,6 +270,9 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op ingestWarningLabel.setVisible(!isEnabled); } + /** + * Refresh displayed information. + */ private void resetComponents() { if (!this.profilesListModel.isEmpty()) { this.profileList.setSelectedIndex(0); @@ -282,6 +290,11 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_editProfileButtonActionPerformed + /** + * Open a dialog for the the creation or modification of a profile. + * + * @param selectedProfile + */ private void doProfileDialog(IngestProfile selectedProfile) { // Create a files set defintion panle. ProfilePanel panel; @@ -315,6 +328,9 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } + /** + * Load the stored profile information. + */ @Override public void load() { int currentIndex = profileList.getSelectedIndex(); diff --git a/docs/doxygen/modAdvanced.dox b/docs/doxygen/modAdvanced.dox index ac24ddbad9..ef3b546662 100755 --- a/docs/doxygen/modAdvanced.dox +++ b/docs/doxygen/modAdvanced.dox @@ -34,6 +34,7 @@ Autopsy will generate events as the application runs and modules may want to lis - Case change events occur when a case is opened, closed, or changed. The org.sleuthkit.autopsy.casemodule.Case.addPropertyChangeListener() method can be used for this. - IngestManager events occur when new results are available. The org.sleuthkit.autopsy.ingest.IngestManager.addPropertyChangeListener() method can be used for this. +Preventing a user from modifying settings during ingest can be accomplished by listening for Ingest Job Events, and when there is an event setting the enabled status of those settings based off the opposite of IngestManager.getInstance().isIngestRunning(), which returns a boolean. */ From 96fb0438c7429013fa83cf12a9c71bec7a1da765 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Jan 2017 16:45:48 -0500 Subject: [PATCH 20/73] 2197 added duplicate profile name detection --- ...ProfileList.java => IngestProfileMap.java} | 35 ++++++++----------- .../autopsy/ingest/ProfilePanel.java | 7 +++- .../autopsy/ingest/ProfileSettingsPanel.java | 21 ++++++++--- 3 files changed, 36 insertions(+), 27 deletions(-) rename Core/src/org/sleuthkit/autopsy/ingest/{IngestProfileList.java => IngestProfileMap.java} (93%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java rename to Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java index 09d6d11fdc..c371534a0b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileList.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java @@ -22,29 +22,33 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.List; +import java.util.TreeMap; import org.apache.commons.io.FileUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -class IngestProfileList { +class IngestProfileMap { private static final String PROFILE_FOLDER = "Profiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; - private List profileList = null; + private TreeMap profileMap = null; private static final Object PROFILE_LOCK = new Object(); - List getIngestProfileList() { - if (profileList == null) { + /** + * Gets the collection of profiles which currently exist. + * + * @return profileList + */ + TreeMap getIngestProfileMap() { + if (profileMap == null) { loadProfileList(); } - return profileList; + return profileMap; } /** @@ -55,17 +59,15 @@ class IngestProfileList { File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); File[] directoryListing = dir.listFiles(); + profileMap = new TreeMap<>(); if (directoryListing != null) { - profileList = new ArrayList<>(); for (File child : directoryListing) { String name = child.getName().split("\\.")[0]; String context = PROFILE_FOLDER + File.separator + name; String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); String fileIngestFilter = ModuleSettings.getConfigSetting(context, PROFILE_FILTER_KEY); - profileList.add(new IngestProfile(name, desc, fileIngestFilter)); + profileMap.put(name, new IngestProfile(name, desc, fileIngestFilter)); } - } else { - profileList = Collections.emptyList(); } } } @@ -77,21 +79,12 @@ class IngestProfileList { readFilesFromDirectory(); } - /** - * Gets the list of profiles which currently exist. - * - * @return profileList - */ - List getProfileList() { - return this.profileList; - } - /** * Saves the list of profiles which currently exist to disk. */ void saveProfileList() { //save last used profile - for (IngestProfile profile : getIngestProfileList()) { + for (IngestProfile profile : getIngestProfileMap().values()) { IngestProfile.saveProfile(profile); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index fc6c912480..b0d4d69811 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -19,10 +19,11 @@ package org.sleuthkit.autopsy.ingest; import java.beans.PropertyChangeListener; +import java.util.TreeMap; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; +import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; /** * Panel to display options for profile creation. @@ -60,6 +61,9 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { jPanel1.add(ingestSettingsPanel, 0); } + String getProfileName(){ + return profileNameField.getText(); + } /** * 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 @@ -183,6 +187,7 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { DialogDisplayer.getDefault().notify(notifyDesc); return false; } + return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index a7b3f9c162..6a8d5b2cc5 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.ingest; import java.util.Map; +import java.util.TreeMap; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; @@ -26,7 +27,8 @@ import javax.swing.event.ListSelectionListener; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; -import org.sleuthkit.autopsy.ingest.IngestProfileList.IngestProfile; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; @@ -41,7 +43,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op "ProfileSettingsPanel.newProfileButton.text=New Profile", "ProfileSettingsPanel.editProfileButton.text=Edit Profile", "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile", - "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter" + "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter", + "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text=Profile with name {0} already exists." }) private final DefaultListModel profilesListModel = new DefaultListModel<>(); @@ -311,6 +314,15 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op option = JOptionPane.showConfirmDialog(null, panel, Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); + TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); + + if (profileMap.containsKey(panel.getProfileName()) && selectedProfile == null) { + MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), + "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text", + panel.getProfileName())); + return; + } + if (option == JOptionPane.OK_OPTION) { panel.saveSettings(); load(); @@ -335,9 +347,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op public void load() { int currentIndex = profileList.getSelectedIndex(); profilesListModel.clear(); - IngestProfileList iList = new IngestProfileList(); - iList.loadProfileList(); - for (IngestProfile profile : iList.getProfileList()) { + IngestProfileMap profileMap = new IngestProfileMap(); + for (IngestProfile profile : profileMap.getIngestProfileMap().values()) { profilesListModel.addElement(profile); } if (newProfileButton.isEnabled()) { From 82a921e27f9e9bed9d2c9aa4087a706794d6cf1a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Jan 2017 10:56:25 -0500 Subject: [PATCH 21/73] 2197-changed config profile directory name to match design document --- Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java index c371534a0b..f1bbed0a3e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; class IngestProfileMap { - private static final String PROFILE_FOLDER = "Profiles"; + private static final String PROFILE_FOLDER = "IngestProfiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; From 473b7dc17a9a0c1ae934e5121c665d613d99931e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Jan 2017 11:33:05 -0500 Subject: [PATCH 22/73] 2197 - hiding history button when creating profile as per design doc --- .../sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java | 6 +++++- Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 2f2480b694..ea9f5b52cf 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -184,7 +184,11 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { */ pastJobsButton.setEnabled(!dataSources.isEmpty() && !ingestJobs.isEmpty()); } - + + void setPastJobsButtonVisible(boolean isVisible){ + pastJobsButton.setVisible(isVisible); + } + /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index b0d4d69811..9831b4b0db 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.ingest; import java.beans.PropertyChangeListener; -import java.util.TreeMap; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; @@ -47,6 +46,7 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { initComponents(); tempSettings = new IngestJobSettings(NEW_PROFILE_NAME); ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); + ingestSettingsPanel.setPastJobsButtonVisible(false); jPanel1.add(ingestSettingsPanel, 0); } @@ -58,6 +58,7 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { profileNameField.setText(profile.getName()); tempSettings = new IngestJobSettings(selectedProfile.getName()); ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); + ingestSettingsPanel.setPastJobsButtonVisible(false); jPanel1.add(ingestSettingsPanel, 0); } From c76f4a788776488e9bf38c1a1894f17eb97ac941 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Jan 2017 15:33:36 -0500 Subject: [PATCH 23/73] 2198-Run ingest module wizard added but not connected to profiles --- Core/nbproject/project.xml | 16 +++ .../autopsy/ingest/IngestJobSettings.java | 4 +- .../ingest/IngestJobSettingsPanel.java | 1 + .../autopsy/ingest/IngestProfileMap.java | 7 +- .../ingest/RunIngestModulesAction.java | 12 +- .../ingest/RunIngestModulesDialog.java | 2 +- .../runIngestModuleWizard/Bundle.properties | 2 + .../IngestProfileSelectionPanel.form | 93 +++++++++++++ .../IngestProfileSelectionPanel.java | 129 ++++++++++++++++++ .../RunIngestModuleAction.java | 62 +++++++++ .../RunIngestModuleWizardWizardIterator.java | 101 ++++++++++++++ .../RunIngestModuleWizardWizardPanel1.java | 94 +++++++++++++ .../RunIngestModuleWizardWizardPanel2.java | 70 ++++++++++ .../ShortCircuitableWizardPanel.java | 20 +++ 14 files changed, 604 insertions(+), 9 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 28a8815bca..fb43fea301 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -31,6 +31,14 @@ 1.46.1 + + org.netbeans.api.templates + + + + 1.6.1 + + org.netbeans.core @@ -155,6 +163,14 @@ 9.7.1 + + org.openide.loaders + + + + 7.63.2 + + org.openide.modules diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index 03fa136a80..b5c3410522 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -120,7 +120,7 @@ public class IngestJobSettings { /** * Constructs an ingest job settings object for a given execution context. * Examples of execution contexts include the add data source wizard and the - * run ingest modules dialog. Different execution conterxts may have + * run ingest modules dialog. Different execution contexts may have * different ingest job settings. * * @param executionContext The ingest execution context identifier. @@ -137,7 +137,7 @@ public class IngestJobSettings { /** * Constructs an ingest job settings object for a given context. Examples of * execution contexts include the add data source wizard and the run ingest - * modules dialog. Different execution conterxts may have different ingest + * modules dialog. Different execution contexts may have different ingest * job settings. * * @param context The context identifier string. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index ea9f5b52cf..d82b94d4ef 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -84,6 +84,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { initComponents(); customizeComponents(); fileIngestFilterComboBox.setSelectedItem(settings.getFileIngestFilter().getName()); + this.setName("Configure Ingest Modules"); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java index f1bbed0a3e..e533ce3fe4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java @@ -22,7 +22,6 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Collections; import java.util.HashSet; import java.util.TreeMap; import org.apache.commons.io.FileUtils; @@ -30,7 +29,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -class IngestProfileMap { +public class IngestProfileMap { private static final String PROFILE_FOLDER = "IngestProfiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; @@ -44,7 +43,7 @@ class IngestProfileMap { * * @return profileList */ - TreeMap getIngestProfileMap() { + public TreeMap getIngestProfileMap() { if (profileMap == null) { loadProfileList(); } @@ -94,7 +93,7 @@ class IngestProfileMap { * FileIngestFilter. The name can be used to find the ModuleSettings for * this profile. */ - static class IngestProfile { + public static class IngestProfile { private final String name; private final String description; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java index 285b916c81..d071dda0b7 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java @@ -19,8 +19,12 @@ package org.sleuthkit.autopsy.ingest; import java.awt.event.ActionEvent; +import java.text.MessageFormat; import java.util.Collections; import javax.swing.AbstractAction; +import org.openide.DialogDisplayer; +import org.openide.WizardDescriptor; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleWizardWizardIterator; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; @@ -47,7 +51,11 @@ final class RunIngestModulesAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { - final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(dataSource)); - ingestDialog.display(); + WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardWizardIterator()); + // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() + wiz.setTitleFormat(new MessageFormat("{0}")); + wiz.setTitle("Run Ingest Modules"); + if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index f2cab6ecd1..67f5f41c98 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -99,7 +99,7 @@ public final class RunIngestModulesDialog extends JDialog { /** * Center the dialog. */ - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();; + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); /** * Get the default or saved ingest job settings for this context and use diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties new file mode 100644 index 0000000000..66a07f4bad --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties @@ -0,0 +1,2 @@ +IngestProfileSelectionPanel.jButton1.text=Ingest Settings +IngestProfileSelectionPanel.jLabel1.text=Select Profile: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form new file mode 100644 index 0000000000..07f136df0f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form @@ -0,0 +1,93 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java new file mode 100644 index 0000000000..dcc931a250 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -0,0 +1,129 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; + +public final class IngestProfileSelectionPanel extends JPanel implements ItemListener { + + RunIngestModuleWizardWizardPanel1 wizardPanel; + + /** + * Creates new form runIngestModuleWizardVisualPanel1 + */ + public IngestProfileSelectionPanel(RunIngestModuleWizardWizardPanel1 panel) { + initComponents(); + //WJS-TODO figure out how to get width of writable area, if text length greater than width. Trim text to width minus 3 chars in length and then add ... to the end + wizardPanel = panel; + int[] tempIDs = getElements(); + customSettings = new JRadioButton("Custom Settings - configure individual module settings"); + customSettings.setRolloverEnabled(true); + customSettings.setToolTipText("configure individual module settings"); + buttonGroup1.add(customSettings); + jPanel1.add(customSettings); + for (int i = 0; i < tempIDs.length; i++) { + JRadioButton myRadio = new JRadioButton("Fiction Profile #" + i + " - This is a fictional profile for place holder text"); + myRadio.addItemListener(this); + buttonGroup1.add(myRadio); + jPanel1.add(myRadio); + } + + } + + @Override + public String getName() { + return "Ingest Profile Selection"; + } + + int getNumOfElements() { + return 10; + } + + int[] getElements() { + int size = getNumOfElements(); + int[] elements = new int[size]; + for (int i = 5; i < 5 + size; i++) { + elements[i - 5] = i; + } + return elements; + } + + /** + * 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 + * regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonGroup1 = new javax.swing.ButtonGroup(); + jButton1 = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + + org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.jButton1.text")); // NOI18N + + jScrollPane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + jPanel1.setAutoscrolls(true); + jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.PAGE_AXIS)); + jScrollPane1.setViewportView(jPanel1); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.jLabel1.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 523, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 385, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jButton1) + .addGap(18, 18, 18)) + ); + }// //GEN-END:initComponents + + + boolean hasNextPanel = true; + private JRadioButton customSettings; + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JButton jButton1; + private javax.swing.JLabel jLabel1; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + // End of variables declaration//GEN-END:variables + + @Override + public void itemStateChanged(ItemEvent e) { + boolean hadNextPanel = hasNextPanel; + hasNextPanel= !hasNextPanel; + System.out.println("SWITCHED VALUES, VALUE NOW:"+ hasNextPanel); + wizardPanel.fireChangeEvent(); + this.firePropertyChange("LAST_ENABLED", hadNextPanel, hasNextPanel); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java new file mode 100644 index 0000000000..9231485d9f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.MessageFormat; +import org.openide.DialogDisplayer; +import org.openide.WizardDescriptor; +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.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.openide.util.actions.Presenter; +import org.openide.util.lookup.ServiceProvider; + + + + + + @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleAction") +@ActionRegistration( + displayName = "#CTL_RunIngestModulesAction", lazy = false) +@ActionReference(path = "Toolbars/Tools", position = 200) + @ServiceProvider(service = RunIngestModuleAction.class) +@Messages("CTL_RunIngestModulesAction=Run Ingest Modules Wizard") +public final class RunIngestModuleAction extends CallableSystemAction implements Presenter.Toolbar { + public static ActionListener run() { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardWizardIterator()); + // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() + // {1} will be replaced by WizardDescriptor.Iterator.name() + wiz.setTitleFormat(new MessageFormat("{0} ({1})")); + wiz.setTitle("...dialog title..."); + if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { + } + } + }; + } + + @Override + public void performAction() { + + } + + @Override + public String getName() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public HelpCtx getHelpCtx() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java new file mode 100644 index 0000000000..d68f283d65 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java @@ -0,0 +1,101 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; + +import java.awt.Component; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.TreeMap; +import javax.swing.JComponent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.sleuthkit.autopsy.ingest.IngestProfileMap; + +public final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iterator { + + private int index; + + private List panels; + + + private List getPanels() { + if (panels == null) { + panels = new ArrayList(); + TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); + if (!profileMap.isEmpty()) { + panels.add(new RunIngestModuleWizardWizardPanel1()); + } + + panels.add(new RunIngestModuleWizardWizardPanel2()); + String[] steps = new String[panels.size()]; + for (int i = 0; i < panels.size(); i++) { + Component c = panels.get(i).getComponent(); + // Default step name to component name of panel. + steps[i] = c.getName(); + if (c instanceof JComponent) { // assume Swing components + JComponent jc = (JComponent) c; + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i); + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps); + jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true); + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true); + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true); + } + } + } + return panels; + } + + @Override + public ShortCircuitableWizardPanel current() { + return getPanels().get(index); + } + + @Override + public String name() { + return ""; + } + + @Override + public boolean hasNext() { + return (index < getPanels().size() - 1) && current().shouldCheckForNext(); + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public void nextPanel() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + index++; + } + + @Override + public void previousPanel() { + if (!hasPrevious()) { + throw new NoSuchElementException(); + } + index--; + } + + // If nothing unusual changes in the middle of the wizard, simply: + @Override + public void addChangeListener(ChangeListener l) { + } + + @Override + public void removeChangeListener(ChangeListener l) { + } + // If something changes dynamically (besides moving between panels), e.g. + // the number of panels changes in response to user input, then use + // ChangeSupport to implement add/removeChangeListener and call fireChange + // when needed + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java new file mode 100644 index 0000000000..9fe809eac5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java @@ -0,0 +1,94 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; + +import java.util.HashSet; +import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.util.HelpCtx; + +public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPanel { + + private final Set listeners = new HashSet(1); + /** + * The visual component that displays this panel. If you need to access the + * component from this class, just use getComponent(). + */ + private IngestProfileSelectionPanel component; + + // Get the visual component for the panel. In this template, the component + // is kept separate. This can be more efficient: if the wizard is created + // but never displayed, or not all panels are displayed, it is better to + // create only those which really need to be visible. + @Override + public IngestProfileSelectionPanel getComponent() { + if (component == null) { + component = new IngestProfileSelectionPanel(this); + } + return component; + } + + @Override + boolean shouldCheckForNext() { + return component.hasNextPanel; + } + + @Override + public HelpCtx getHelp() { + // Show no Help button for this panel: + return HelpCtx.DEFAULT_HELP; + // If you have context help: + // return new HelpCtx("help.key.here"); + } + + @Override + public boolean isValid() { + // If it is always OK to press Next or Finish, then: + return true; + // If it depends on some condition (form filled out...) and + // this condition changes (last form field filled in...) then + // use ChangeSupport to implement add/removeChangeListener below. + // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful. + } + + protected final void fireChangeEvent() { + Set ls; + synchronized (listeners) { + ls = new HashSet<>(listeners); + } + ChangeEvent ev = new ChangeEvent(this); + for (ChangeListener l : ls) { + l.stateChanged(ev); + } + } + + @Override + public void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + @Override + public void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + @Override + public void readSettings(WizardDescriptor wiz) { + // use wiz.getProperty to retrieve previous panel state + } + + @Override + public void storeSettings(WizardDescriptor wiz) { + // use wiz.putProperty to remember current panel state + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java new file mode 100644 index 0000000000..82fe45ca13 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java @@ -0,0 +1,70 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; + +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.util.HelpCtx; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; + +public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPanel { + + /**f + The visual ingestJobSettingsPanel that displays this panel. If you need to access the + ingestJobSettingsPanel from this class, just use getComponent(). + */ + private IngestJobSettingsPanel ingestJobSettingsPanel; + + // Get the visual ingestJobSettingsPanel for the panel. In this template, the ingestJobSettingsPanel + // is kept separate. This can be more efficient: if the wizard is created + // but never displayed, or not all panels are displayed, it is better to + // create only those which really need to be visible. + @Override + public IngestJobSettingsPanel getComponent() { + if (ingestJobSettingsPanel == null) { + ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings("org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleAction")); + } + return ingestJobSettingsPanel; + } + + @Override + public HelpCtx getHelp() { + // Show no Help button for this panel: + return HelpCtx.DEFAULT_HELP; + // If you have context help: + // return new HelpCtx("help.key.here"); + } + + @Override + public boolean isValid() { + // If it is always OK to press Next or Finish, then: + return true; + // If it depends on some condition (form filled out...) and + // this condition changes (last form field filled in...) then + // use ChangeSupport to implement add/removeChangeListener below. + // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful. + } + + @Override + public void addChangeListener(ChangeListener l) { + } + + @Override + public void removeChangeListener(ChangeListener l) { + } + + @Override + public void readSettings(WizardDescriptor wiz) { + // use wiz.getProperty to retrieve previous panel state + } + + @Override + public void storeSettings(WizardDescriptor wiz) { + // use wiz.putProperty to remember current panel state + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java new file mode 100644 index 0000000000..9a5ca8656c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java @@ -0,0 +1,20 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; + +import org.openide.WizardDescriptor; + +/** + * + * + */ + +public abstract class ShortCircuitableWizardPanel implements WizardDescriptor.Panel { + + boolean shouldCheckForNext(){ + return true; + } +} From 7c88dca3e95f5752ff1ffd4796afa1c7bfdb2fca Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 1 Feb 2017 15:40:14 -0500 Subject: [PATCH 24/73] Merge from stashed changes --- .../sleuthkit/autopsy/modules/interestingitems/Bundle.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties index e5ae1eb726..f78d977613 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties @@ -81,3 +81,4 @@ FilesSetDefsPanel.ingoreUnallocCheckbox.text=Ignore Unallocated Space FilesSetDefsPanel.ingoreUnallocCheckbox.toolTipText=Ignores unallocated space, such as deleted files. May run faster but produce less complete results. FilesSetDefsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. FilesSetDefsPanel.allRadioButton.text=All + From d974369b629a894c33a15d20f655b55524c3078e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 1 Feb 2017 15:42:21 -0500 Subject: [PATCH 25/73] merged in remaining stashed changed --- .../autopsy/ingest/IngestTasksScheduler.java | 1 + .../ingest/RunIngestModulesAction.java | 24 ++++++- .../IngestProfileSelectionPanel.java | 61 ++++++++++++------ .../RunIngestModuleAction.java | 62 ------------------- .../RunIngestModuleWizardWizardIterator.java | 24 ++++--- .../RunIngestModuleWizardWizardPanel1.java | 4 +- .../RunIngestModuleWizardWizardPanel2.java | 4 +- .../netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 9 files changed, 89 insertions(+), 95 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java index f22ef93d94..f7c32930c0 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java @@ -32,6 +32,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java index d071dda0b7..fca7bce492 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java @@ -21,12 +21,13 @@ package org.sleuthkit.autopsy.ingest; import java.awt.event.ActionEvent; import java.text.MessageFormat; import java.util.Collections; +import java.util.List; import javax.swing.AbstractAction; +import javax.swing.JOptionPane; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleWizardWizardIterator; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.Image; /** * This class is used to add the action to the run ingest modules menu item. @@ -36,7 +37,7 @@ import org.sleuthkit.datamodel.Image; final class RunIngestModulesAction extends AbstractAction { Content dataSource; - + /** * the constructor */ @@ -55,7 +56,26 @@ final class RunIngestModulesAction extends AbstractAction { // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle("Run Ingest Modules"); + System.out.println("GONNA GET EXECUTION CONTEXT "); if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { + //WJS-TODO figure out how to get the context / profile name out of the wizard after finish is selected. + String executionContext = (String)wiz.getProperty("executionContext"); //NON-NLS + System.out.println("EXECUTION CONTEXT " + executionContext); +// IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext); +// ingestJobSettings.save(); +// showWarnings(ingestJobSettings); +// IngestManager.getInstance().queueIngestJob(Collections.singletonList(dataSource), ingestJobSettings); + } + } + + private static void showWarnings(IngestJobSettings ingestJobSettings) { + List warnings = ingestJobSettings.getWarnings(); + if (warnings.isEmpty() == false) { + StringBuilder warningMessage = new StringBuilder(); + for (String warning : warnings) { + warningMessage.append(warning).append("\n"); + } + JOptionPane.showMessageDialog(null, warningMessage.toString()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index dcc931a250..e7d4582e0f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -5,15 +5,24 @@ */ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; +import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; +import org.sleuthkit.autopsy.ingest.IngestProfileMap; +import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; public final class IngestProfileSelectionPanel extends JPanel implements ItemListener { + private static final String CUSTOM_SETTINGS_TEXT = "Custom Settings - configure individual module settings"; RunIngestModuleWizardWizardPanel1 wizardPanel; + String selectedProfile; + List elements = Collections.emptyList(); /** * Creates new form runIngestModuleWizardVisualPanel1 @@ -22,14 +31,22 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis initComponents(); //WJS-TODO figure out how to get width of writable area, if text length greater than width. Trim text to width minus 3 chars in length and then add ... to the end wizardPanel = panel; - int[] tempIDs = getElements(); - customSettings = new JRadioButton("Custom Settings - configure individual module settings"); + elements = getElements(); + customSettings = new JRadioButton(CUSTOM_SETTINGS_TEXT, true); + customSettings.setName(RunIngestModuleWizardWizardIterator.getDefaultContext()); + customSettings.setRolloverEnabled(true); - customSettings.setToolTipText("configure individual module settings"); + customSettings.setToolTipText(CUSTOM_SETTINGS_TEXT); buttonGroup1.add(customSettings); jPanel1.add(customSettings); - for (int i = 0; i < tempIDs.length; i++) { - JRadioButton myRadio = new JRadioButton("Fiction Profile #" + i + " - This is a fictional profile for place holder text"); + + selectedProfile = customSettings.getName(); + String tempDescription = "REPLACE THIS WITH DESCRIPTION"; + + for (IngestProfile profile : elements) { + JRadioButton myRadio = new JRadioButton(profile.toString() + tempDescription); + myRadio.setName(profile.toString()); + myRadio.setToolTipText(tempDescription); myRadio.addItemListener(this); buttonGroup1.add(myRadio); jPanel1.add(myRadio); @@ -42,15 +59,9 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis return "Ingest Profile Selection"; } - int getNumOfElements() { - return 10; - } - - int[] getElements() { - int size = getNumOfElements(); - int[] elements = new int[size]; - for (int i = 5; i < 5 + size; i++) { - elements[i - 5] = i; + List getElements() { + if (elements.isEmpty()) { + fetchListContents(); } return elements; } @@ -107,7 +118,6 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis ); }// //GEN-END:initComponents - boolean hasNextPanel = true; private JRadioButton customSettings; // Variables declaration - do not modify//GEN-BEGIN:variables @@ -120,10 +130,25 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis @Override public void itemStateChanged(ItemEvent e) { + for (Component rButton : jPanel1.getComponents()) { + JRadioButton jrb = (JRadioButton) rButton; + if (jrb.isSelected()) { + selectedProfile = jrb.getName(); + break; + } + } + boolean hadNextPanel = hasNextPanel; - hasNextPanel= !hasNextPanel; - System.out.println("SWITCHED VALUES, VALUE NOW:"+ hasNextPanel); + hasNextPanel = !hasNextPanel; + System.out.println( + "SWITCHED VALUES, VALUE NOW:" + hasNextPanel); wizardPanel.fireChangeEvent(); - this.firePropertyChange("LAST_ENABLED", hadNextPanel, hasNextPanel); + this.firePropertyChange( + "LAST_ENABLED", hadNextPanel, hasNextPanel); + } + + private void fetchListContents() { + elements = new ArrayList(); + elements.addAll(new IngestProfileMap().getIngestProfileMap().values()); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java deleted file mode 100644 index 9231485d9f..0000000000 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleAction.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.text.MessageFormat; -import org.openide.DialogDisplayer; -import org.openide.WizardDescriptor; -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.Messages; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; -import org.openide.util.lookup.ServiceProvider; - - - - - - @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleAction") -@ActionRegistration( - displayName = "#CTL_RunIngestModulesAction", lazy = false) -@ActionReference(path = "Toolbars/Tools", position = 200) - @ServiceProvider(service = RunIngestModuleAction.class) -@Messages("CTL_RunIngestModulesAction=Run Ingest Modules Wizard") -public final class RunIngestModuleAction extends CallableSystemAction implements Presenter.Toolbar { - public static ActionListener run() { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardWizardIterator()); - // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() - // {1} will be replaced by WizardDescriptor.Iterator.name() - wiz.setTitleFormat(new MessageFormat("{0} ({1})")); - wiz.setTitle("...dialog title..."); - if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { - } - } - }; - } - - @Override - public void performAction() { - - } - - @Override - public String getName() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public HelpCtx getHelpCtx() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } -} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java index d68f283d65..333d0ddc66 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java @@ -17,19 +17,27 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap; public final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iterator { + private final static String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleAction"; + private int index; private List panels; - + /** + * @return the DEFAULT_CONTEXT + */ + static String getDefaultContext() { + return DEFAULT_CONTEXT; + } + private List getPanels() { if (panels == null) { - panels = new ArrayList(); - TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); - if (!profileMap.isEmpty()) { - panels.add(new RunIngestModuleWizardWizardPanel1()); - } - + panels = new ArrayList<>(); + TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); + if (!profileMap.isEmpty()) { + panels.add(new RunIngestModuleWizardWizardPanel1()); + } + panels.add(new RunIngestModuleWizardWizardPanel2()); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { @@ -56,7 +64,7 @@ public final class RunIngestModuleWizardWizardIterator implements WizardDescript @Override public String name() { - return ""; + return index + 1 + ". from " + getPanels().size(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java index 9fe809eac5..0eb9534fa5 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java @@ -65,6 +65,7 @@ public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPan for (ChangeListener l : ls) { l.stateChanged(ev); } + } @Override @@ -88,7 +89,8 @@ public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPan @Override public void storeSettings(WizardDescriptor wiz) { - // use wiz.putProperty to remember current panel state + System.out.println("STORING EXECUTION CONTEXT" + component.selectedProfile); + wiz.putProperty("executionContext", component.selectedProfile); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java index 82fe45ca13..65618d63db 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java @@ -26,11 +26,11 @@ public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPan @Override public IngestJobSettingsPanel getComponent() { if (ingestJobSettingsPanel == null) { - ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings("org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleAction")); + ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModuleWizardWizardIterator.getDefaultContext())); } return ingestJobSettingsPanel; } - + @Override public HelpCtx getHelp() { // Show no Help button for this panel: diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 8eb490c76e..2588954fb9 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Mon, 02 Jan 2017 18:41:13 -0500 +#Mon, 30 Jan 2017 13:39:12 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 756018bd64..0fe774eeab 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Mon, 02 Jan 2017 18:41:13 -0500 +#Mon, 30 Jan 2017 13:39:12 -0500 CTL_MainWindow_Title=Autopsy 4.3.0 CTL_MainWindow_Title_No_Project=Autopsy 4.3.0 From 04dabbe23b1b4fb1ce2b666188881a550845c486 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 1 Feb 2017 17:18:24 -0500 Subject: [PATCH 26/73] 2198 - Loads and uses profile currently --- .../autopsy/ingest/RunIngestModulesAction.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java index fca7bce492..f781a5169b 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java @@ -56,15 +56,12 @@ final class RunIngestModulesAction extends AbstractAction { // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle("Run Ingest Modules"); - System.out.println("GONNA GET EXECUTION CONTEXT "); if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { - //WJS-TODO figure out how to get the context / profile name out of the wizard after finish is selected. String executionContext = (String)wiz.getProperty("executionContext"); //NON-NLS - System.out.println("EXECUTION CONTEXT " + executionContext); -// IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext); -// ingestJobSettings.save(); -// showWarnings(ingestJobSettings); -// IngestManager.getInstance().queueIngestJob(Collections.singletonList(dataSource), ingestJobSettings); + IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext); + ingestJobSettings.save(); + showWarnings(ingestJobSettings); + IngestManager.getInstance().queueIngestJob(Collections.singletonList(dataSource), ingestJobSettings); } } From 130050646e18182a920cd643e297a825ec250b9e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Feb 2017 11:38:27 -0500 Subject: [PATCH 27/73] 2198-RunIngestModulesAction now used in place of RunIngestModulesDialog --- .../autopsy/datamodel/ImageNode.java | 16 ++------ .../datamodel/VirtualDirectoryNode.java | 13 +----- .../DirectoryTreeFilterNode.java | 23 ++--------- .../ingest/RunIngestModulesAction.java | 40 ++++++++++++++----- .../autopsy/ingest/RunIngestSubMenu.java | 5 +-- .../RunIngestModuleWizardWizardIterator.java | 4 +- .../RunIngestModuleWizardWizardPanel2.java | 18 +++++---- 7 files changed, 52 insertions(+), 67 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 8b2f3b9ae7..3e710c9c1e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.sql.ResultSet; @@ -27,7 +26,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; -import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.Children; import org.openide.nodes.Sheet; @@ -40,7 +38,7 @@ import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; -import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; @@ -101,22 +99,14 @@ public class ImageNode extends AbstractContentNode { "ImageNode.getActions.openFileSearchByAttr.text=Open File Search by Attributes",}) public Action[] getActions(boolean context) { - List actionsList = new ArrayList(); + List actionsList = new ArrayList<>(); for (Action a : super.getActions(true)) { actionsList.add(a); } actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); actionsList.add(new FileSearchAction( Bundle.ImageNode_getActions_openFileSearchByAttr_text())); - actionsList.add(new AbstractAction( - Bundle.ImageNode_action_runIngestMods_text()) { - @Override - public void actionPerformed(ActionEvent e) { - final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(content)); - ingestDialog.display(); - } - }); - + actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); return actionsList.toArray(new Action[0]); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 246c6d6e1d..1660e75eff 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.awt.event.ActionEvent; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -27,7 +26,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; -import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; @@ -38,7 +36,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -100,14 +98,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNodesingletonList(content)); - ingestDialog.display(); - } - }); + actions.add(new RunIngestModulesAction(Collections.singletonList(content))); actions.addAll(ContextMenuExtensionPoint.getActions()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index 0ae016bd00..6b5b774d07 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.directorytree; -import java.awt.event.ActionEvent; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.logging.Level; -import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; @@ -33,7 +30,7 @@ import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractContentNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; -import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; @@ -108,14 +105,7 @@ class DirectoryTreeFilterNode extends FilterNode { Directory dir = this.getLookup().lookup(Directory.class); if (dir != null) { actions.add(ExtractAction.getInstance()); - actions.add(new AbstractAction( - NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.runIngestMods.text")) { - @Override - public void actionPerformed(ActionEvent e) { - final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(dir); - ingestDialog.display(); - } - }); + actions.add(new RunIngestModulesAction(dir)); } final Image img = this.getLookup().lookup(Image.class); @@ -138,14 +128,7 @@ class DirectoryTreeFilterNode extends FilterNode { if (img != null || isRootVD) { actions.add(new FileSearchAction( NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.openFileSrcByAttr.text"))); - actions.add(new AbstractAction( - NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.runIngestMods.text")) { - @Override - public void actionPerformed(ActionEvent e) { - final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(content)); - ingestDialog.display(); - } - }); + actions.add(new RunIngestModulesAction(dir)); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java index f781a5169b..a39750bf2d 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java @@ -20,31 +20,49 @@ package org.sleuthkit.autopsy.ingest; import java.awt.event.ActionEvent; import java.text.MessageFormat; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; +import javax.swing.Action; import javax.swing.JOptionPane; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleWizardWizardIterator; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Directory; /** * This class is used to add the action to the run ingest modules menu item. * When the data source is pressed, it should open the wizard for ingest * modules. */ -final class RunIngestModulesAction extends AbstractAction { +public final class RunIngestModulesAction extends AbstractAction { - Content dataSource; + @Messages("RunIngestModulesAction.name=Run Ingest Modules") + + private final List dataSources = new ArrayList<>(); + private final IngestJobSettings.IngestType ingestType; /** * the constructor + * @param dataSources */ - public RunIngestModulesAction(Content dataSource) { - this.dataSource = dataSource; + public RunIngestModulesAction(List dataSources) { + this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); + this.dataSources.addAll(dataSources); + this.ingestType = IngestJobSettings.IngestType.ALL_MODULES; + } + + /** + * the constructor + * @param dir + */ + public RunIngestModulesAction(Directory dir) { + this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); + this.dataSources.add(dir); + this.ingestType = IngestJobSettings.IngestType.FILES_ONLY; } - /** * Runs the ingest modules wizard on the data source. * @@ -55,13 +73,13 @@ final class RunIngestModulesAction extends AbstractAction { WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardWizardIterator()); // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() wiz.setTitleFormat(new MessageFormat("{0}")); - wiz.setTitle("Run Ingest Modules"); + wiz.setTitle(Bundle.RunIngestModulesAction_name()); + if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { - String executionContext = (String)wiz.getProperty("executionContext"); //NON-NLS - IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext); - ingestJobSettings.save(); + String executionContext = (String)wiz.getProperty("executionContext"); //NON-NLS + IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext, this.ingestType); showWarnings(ingestJobSettings); - IngestManager.getInstance().queueIngestJob(Collections.singletonList(dataSource), ingestJobSettings); + IngestManager.getInstance().queueIngestJob(this.dataSources, ingestJobSettings); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java index 8c2892c558..8c9b61a646 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.ingest; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.swing.JComponent; import javax.swing.JMenuItem; @@ -26,8 +27,6 @@ import org.openide.awt.DynamicMenuContent; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** @@ -61,7 +60,7 @@ final class RunIngestSubMenu extends JMenuItem implements DynamicMenuContent { String action = dataSources.get(i).getName(); JMenuItem menuItem = new JMenuItem(action); menuItem.setActionCommand(action.toUpperCase()); - menuItem.addActionListener(new RunIngestModulesAction(dataSources.get(i))); + menuItem.addActionListener(new RunIngestModulesAction(Collections.singletonList(dataSources.get(i)))); comps[i] = menuItem; } // If no dataSources are open, create a disabled empty menu diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java index 333d0ddc66..ab87eccb51 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java @@ -17,7 +17,7 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap; public final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iterator { - private final static String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleAction"; + private final static String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleAction"; private int index; @@ -26,7 +26,7 @@ public final class RunIngestModuleWizardWizardIterator implements WizardDescript /** * @return the DEFAULT_CONTEXT */ - static String getDefaultContext() { + public static String getDefaultContext() { return DEFAULT_CONTEXT; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java index 65618d63db..f9da9f52c5 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java @@ -11,11 +11,13 @@ import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; -public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPanel { +public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPanel { - /**f - The visual ingestJobSettingsPanel that displays this panel. If you need to access the - ingestJobSettingsPanel from this class, just use getComponent(). + /** + * f + * The visual ingestJobSettingsPanel that displays this panel. If you need + * to access the ingestJobSettingsPanel from this class, just use + * getComponent(). */ private IngestJobSettingsPanel ingestJobSettingsPanel; @@ -30,7 +32,7 @@ public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPan } return ingestJobSettingsPanel; } - + @Override public HelpCtx getHelp() { // Show no Help button for this panel: @@ -48,7 +50,7 @@ public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPan // use ChangeSupport to implement add/removeChangeListener below. // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful. } - + @Override public void addChangeListener(ChangeListener l) { } @@ -64,7 +66,9 @@ public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPan @Override public void storeSettings(WizardDescriptor wiz) { - // use wiz.putProperty to remember current panel state + IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); + ingestJobSettings.save(); + wiz.putProperty("executionContext", RunIngestModuleWizardWizardIterator.getDefaultContext()); //NON-NLS } } From b3d3d63ae73204bcbe8a08181257acc24045419c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Feb 2017 12:22:13 -0500 Subject: [PATCH 28/73] 2198 Removed now obsolete RunIngestModulesDialog class --- .../autopsy/ingest/Bundle.properties | 1 - .../autopsy/ingest/Bundle_ja.properties | 2 +- .../ingest/IngestProgressSnapshotDialog.java | 2 +- .../ingest/RunIngestModulesDialog.java | 241 ------------------ .../AddFileTypeSignatureDialog.java | 4 +- 5 files changed, 4 insertions(+), 246 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 333d179c74..889f53d152 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -23,7 +23,6 @@ IngestJob.progress.fileIngest.displayName=Analyzing files from {0} IngestJob.progress.fileIngest.cancelMessage=Waiting for {0} on {1} IngestJob.progress.cancelling={0} (Cancelling...) IngestJob.cancellationDialog.title=Cancel Ingest -IngestDialog.title.text=Run Ingest Modules IngestDialog.startButton.title=Start IngestDialog.closeButton.title=Close IngestManager.moduleErr=Module Error diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index 7f83c8c5c0..fa49df5cde 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -2,7 +2,7 @@ CTL_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8 HINT_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8\u30a6\u30a3\u30f3\u30c9\u30a6 IngestDialog.closeButton.title=\u9589\u3058\u308b IngestDialog.startButton.title=\u958b\u59cb -IngestDialog.title.text=\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +RunIngestModulesAction.name=\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 IngestJob.progress.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 IngestJob.progress.dataSourceIngest.displayName={1}\u306e{0} IngestJob.progress.fileIngest.displayName={0}\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java index deb9d14ede..3323240a88 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java @@ -38,7 +38,7 @@ import org.openide.windows.WindowManager; */ public final class IngestProgressSnapshotDialog extends JDialog { - private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestProgressSnapshotDialog.title.text"); + private static final String TITLE = NbBundle.getMessage(IngestProgressSnapshotDialog.class, "IngestProgressSnapshotDialog.title.text"); private static final Dimension DIMENSIONS = new Dimension(500, 300); /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java deleted file mode 100644 index 67f5f41c98..0000000000 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2016 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.ingest; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.List; -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import org.openide.util.NbBundle; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.Directory; - -/** - * - * A dialog box that allows a user to configure and execute analysis of one or - * more data sources with ingest modules or analysis of the contents of a - * directory with file-level ingest modules. - */ -public final class RunIngestModulesDialog extends JDialog { - - private static final long serialVersionUID = 1L; - private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); - private final IngestType ingestType; - private final List dataSources = new ArrayList<>(); - private IngestJobSettingsPanel ingestJobSettingsPanel; - - /** - * Constructs a dialog box that allows a user to configure and execute - * analysis of one or more data sources with ingest modules. - * - * @param frame The dialog parent window. - * @param title The title for the dialog. - * @param modal True if the dialog should be modal, false otherwise. - * @param dataSources The data sources to be analyzed. - */ - public RunIngestModulesDialog(JFrame frame, String title, boolean modal, List dataSources) { - super(frame, title, modal); - this.dataSources.addAll(dataSources); - this.ingestType = IngestType.ALL_MODULES; - } - - /** - * Constructs a dialog box that allows a user to configure and execute - * analysis of one or more data sources with ingest modules. - * - * @param dataSources The data sources to be processed. - */ - public RunIngestModulesDialog(List dataSources) { - this((JFrame) WindowManager.getDefault().getMainWindow(), TITLE, true, dataSources); - } - - /** - * Constructs a dialog box that allows a user to configure and execute - * analysis of the contents of a directory with file-level ingest modules. - * - * @param dir - */ - public RunIngestModulesDialog(Directory dir) { - this.dataSources.add(dir); - this.ingestType = IngestType.FILES_ONLY; - } - - /** - * Displays this dialog. - */ - public void display() { - setLayout(new BorderLayout()); - - /** - * Center the dialog. - */ - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - /** - * Get the default or saved ingest job settings for this context and use - * them to create and add an ingest job settings panel. - */ - IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName(), this.ingestType); - RunIngestModulesDialog.showWarnings(ingestJobSettings); - this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings, dataSources); - setPreferredSize(this.ingestJobSettingsPanel.getPreferredSize()); - add(this.ingestJobSettingsPanel, BorderLayout.CENTER); - - // Add a start ingest button. - JButton startButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.startButton.title")); - startButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - doButtonAction(true); - } - }); - - // Add a close button. - JButton closeButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.closeButton.title")); - closeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - doButtonAction(false); - } - }); - - // Put the buttons in their own panel, under the settings panel. - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING)); - buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); - buttonPanel.add(startButton); - buttonPanel.add(new javax.swing.Box.Filler(new Dimension(5, 10), new Dimension(5, 10), new Dimension(5, 10))); - buttonPanel.add(closeButton); - - add(buttonPanel, BorderLayout.SOUTH); - - /** - * Add a handler for when the dialog window is closed directly, - * bypassing the buttons. - */ - this.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - doButtonAction(false); - } - }); - - /** - * Show the dialog. - */ - int width = this.getPreferredSize().width; - int height = this.getPreferredSize().height; - setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); - pack(); - setVisible(true); - } - - /** - * Closes this dialog. - */ - @Deprecated - public void close() { - setVisible(false); - dispose(); - } - - /** - * Saves the ingest job settings, optionally starts an ingest job for each - * data source, then closes the dialog - * - * @param startIngestJob True if ingest job(s) should be started, false - * otherwise. - */ - private void doButtonAction(boolean startIngestJob) { - IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); - ingestJobSettings.save(); - showWarnings(ingestJobSettings); - if (startIngestJob) { - IngestManager.getInstance().queueIngestJob(RunIngestModulesDialog.this.dataSources, ingestJobSettings); - } - setVisible(false); - dispose(); - } - - private static void showWarnings(IngestJobSettings ingestJobSettings) { - List warnings = ingestJobSettings.getWarnings(); - if (warnings.isEmpty() == false) { - StringBuilder warningMessage = new StringBuilder(); - for (String warning : warnings) { - warningMessage.append(warning).append("\n"); - } - JOptionPane.showMessageDialog(null, warningMessage.toString()); - } - } - - /** - * Constructs a dialog box that allows a user to configure and execute - * analysis of one or more data sources with ingest modules. - * - * @param frame The dialog parent window. - * @param title The title for the dialog. - * @param modal True if the dialog should be modal, false otherwise. - * - * @deprecated - */ - @Deprecated - public RunIngestModulesDialog(JFrame frame, String title, boolean modal) { - super(frame, title, modal); - this.ingestType = IngestType.ALL_MODULES; - } - - /** - * Constructs a dialog box that allows a user to configure and run an ingest - * job on one or more data sources. - * - * @deprecated - */ - @Deprecated - public RunIngestModulesDialog() { - this(new JFrame(TITLE), TITLE, true); - } - - /** - * Sets the data sources to be processed. - * - * @param dataSources The data sources. - * - * @deprecated - */ - @Deprecated - public void setDataSources(List dataSources) { - this.dataSources.clear(); - this.dataSources.addAll(dataSources); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java index 3365d33eb3..ce92176308 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java @@ -32,7 +32,7 @@ import javax.swing.JFrame; import javax.swing.JPanel; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; /** @@ -43,7 +43,7 @@ final class AddFileTypeSignatureDialog extends JDialog { private static final long serialVersionUID = 1L; private final AddFileTypeSignaturePanel addFileTypeSigPanel; - private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); + private static final String TITLE = NbBundle.getMessage(RunIngestModulesAction.class, "RunIngestModulesAction.name"); private Signature signature; private BUTTON_PRESSED result; From 6fbe9202ff509bdd5c68ca85e81470d8f263e5ed Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Feb 2017 13:07:46 -0500 Subject: [PATCH 29/73] 2198 - moved RunIngestModulesAction to a non exposed package so it can be public --- Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java | 2 +- .../sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java | 2 +- .../autopsy/directorytree/DirectoryTreeFilterNode.java | 2 +- Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties | 1 - .../src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java | 1 + .../ingest/runIngestModuleWizard/Bundle_ja.properties | 1 + .../RunIngestModuleWizardWizardIterator.java | 4 ++-- .../RunIngestModulesAction.java | 7 ++++--- .../runIngestModuleWizard/ShortCircuitableWizardPanel.java | 5 ++--- .../modules/filetypeid/AddFileTypeSignatureDialog.java | 4 ++-- 10 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle_ja.properties rename Core/src/org/sleuthkit/autopsy/ingest/{ => runIngestModuleWizard}/RunIngestModulesAction.java (94%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 3e710c9c1e..5a4f99dae0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -38,7 +38,7 @@ import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; -import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 1660e75eff..2dcb6fce3d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index 6b5b774d07..257e81f378 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -30,7 +30,7 @@ import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractContentNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; -import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index fa49df5cde..f7af8964cc 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -2,7 +2,6 @@ CTL_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8 HINT_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8\u30a6\u30a3\u30f3\u30c9\u30a6 IngestDialog.closeButton.title=\u9589\u3058\u308b IngestDialog.startButton.title=\u958b\u59cb -RunIngestModulesAction.name=\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 IngestJob.progress.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 IngestJob.progress.dataSourceIngest.displayName={1}\u306e{0} IngestJob.progress.fileIngest.displayName={0}\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java index 8c9b61a646..a8fabc1f31 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.ingest; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle_ja.properties new file mode 100644 index 0000000000..39d7a2632b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle_ja.properties @@ -0,0 +1 @@ +RunIngestModulesAction.name=\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java index ab87eccb51..d2b4ba97b1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java @@ -15,7 +15,7 @@ import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.sleuthkit.autopsy.ingest.IngestProfileMap; -public final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iterator { +final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iterator { private final static String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleAction"; @@ -26,7 +26,7 @@ public final class RunIngestModuleWizardWizardIterator implements WizardDescript /** * @return the DEFAULT_CONTEXT */ - public static String getDefaultContext() { + static String getDefaultContext() { return DEFAULT_CONTEXT; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java similarity index 94% rename from Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index a39750bf2d..d2939797e9 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.ingest; +package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; import java.awt.event.ActionEvent; import java.text.MessageFormat; @@ -28,7 +28,8 @@ import javax.swing.JOptionPane; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModuleWizardWizardIterator; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java index 9a5ca8656c..8fb5dcddb4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java @@ -8,11 +8,10 @@ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; import org.openide.WizardDescriptor; /** - * + * Abstract class for exten * */ - -public abstract class ShortCircuitableWizardPanel implements WizardDescriptor.Panel { +abstract class ShortCircuitableWizardPanel implements WizardDescriptor.Panel { boolean shouldCheckForNext(){ return true; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java index ce92176308..d5cade3571 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ import javax.swing.JFrame; import javax.swing.JPanel; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.ingest.RunIngestModulesAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; /** From 998a0399bc1d42ba5235b6686db69593aa1ef1b0 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Feb 2017 18:24:03 -0500 Subject: [PATCH 30/73] 2198 Last profile used now saved, profile descriptions now visible --- .../autopsy/ingest/IngestOptionsPanel.java | 4 +- .../autopsy/ingest/IngestProfileMap.java | 2 +- ... => EarlyFinishWizardDescriptorPanel.java} | 0 .../IngestProfileSelectionPanel.form | 11 ++ .../IngestProfileSelectionPanel.java | 137 +++++++++++++----- .../RunIngestModuleWizardWizardPanel1.java | 21 ++- .../RunIngestModuleWizardWizardPanel2.java | 2 +- 7 files changed, 131 insertions(+), 46 deletions(-) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{ShortCircuitableWizardPanel.java => EarlyFinishWizardDescriptorPanel.java} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 7d6964022d..d2a3001259 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY /** * Global options panel for keyword searching. */ -class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { +public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { @NbBundle.Messages({"IngestOptionsPanel.settingsTab.text=Settings", "IngestOptionsPanel.settingsTab.toolTipText=Settings regarding resources available to ingest.", @@ -50,7 +50,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti */ IngestJobEventPropertyChangeListener ingestJobEventsListener; - IngestOptionsPanel() { + public IngestOptionsPanel() { initComponents(); customizeComponents(); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java index e533ce3fe4..5189619c3e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java @@ -138,7 +138,7 @@ public class IngestProfileMap { * * @return the description */ - String getDescription() { + public String getDescription() { return description; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortCircuitableWizardPanel.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form index 07f136df0f..7f5b676190 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form @@ -8,6 +8,14 @@
+ + + + + + + + @@ -60,6 +68,9 @@ + + +
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index e7d4582e0f..059539e100 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -1,11 +1,25 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest.runIngestModuleWizard; import java.awt.Component; +import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; @@ -14,58 +28,84 @@ import java.util.List; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; +import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; +import org.sleuthkit.autopsy.ingest.IngestOptionsPanel; import org.sleuthkit.autopsy.ingest.IngestProfileMap; import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; -public final class IngestProfileSelectionPanel extends JPanel implements ItemListener { +final class IngestProfileSelectionPanel extends JPanel implements ItemListener { - private static final String CUSTOM_SETTINGS_TEXT = "Custom Settings - configure individual module settings"; - RunIngestModuleWizardWizardPanel1 wizardPanel; - String selectedProfile; - List elements = Collections.emptyList(); + private static final String CUSTOM_SETTINGS_DISPLAY_NAME = "Custom Settings"; + private static final String CUSTOM_SETTINGS_DESCRIPTION = "configure individual module settings in next step of wizard"; //WJS-TODO these should be @Message + private final RunIngestModuleWizardWizardPanel1 wizardPanel; + private String selectedProfile; + private List elements = Collections.emptyList(); /** * Creates new form runIngestModuleWizardVisualPanel1 */ - public IngestProfileSelectionPanel(RunIngestModuleWizardWizardPanel1 panel) { + IngestProfileSelectionPanel(RunIngestModuleWizardWizardPanel1 panel, String lastSelectedProfile) { initComponents(); //WJS-TODO figure out how to get width of writable area, if text length greater than width. Trim text to width minus 3 chars in length and then add ... to the end wizardPanel = panel; + selectedProfile = lastSelectedProfile; + populateListOfCheckboxes(); + + } + + String getLastSelectedProfile() { + return selectedProfile; + } + + private void populateListOfCheckboxes() { elements = getElements(); - customSettings = new JRadioButton(CUSTOM_SETTINGS_TEXT, true); - customSettings.setName(RunIngestModuleWizardWizardIterator.getDefaultContext()); - - customSettings.setRolloverEnabled(true); - customSettings.setToolTipText(CUSTOM_SETTINGS_TEXT); - buttonGroup1.add(customSettings); - jPanel1.add(customSettings); - - selectedProfile = customSettings.getName(); - String tempDescription = "REPLACE THIS WITH DESCRIPTION"; - + addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModuleWizardWizardIterator.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); for (IngestProfile profile : elements) { - JRadioButton myRadio = new JRadioButton(profile.toString() + tempDescription); - myRadio.setName(profile.toString()); - myRadio.setToolTipText(tempDescription); - myRadio.addItemListener(this); - buttonGroup1.add(myRadio); - jPanel1.add(myRadio); + addRadioButton(profile.toString(), profile.toString(), profile.getDescription()); } + } + + private void addRadioButton(String profileDisplayName, String profileContextName, String profileDesc) { + String displayText = profileDisplayName + " - " + profileDesc; + int width = jScrollPane1.getWidth(); + if (width > 3) { + if (displayText.length() > width) { + String ellipses = "..."; + displayText = displayText.substring(0, width - ellipses.length()) + ellipses; + } + } else { + System.out.println("NOT KNOWN BEFORE DRAWN USE DIFFERENT WAY TO GET WIDTH"); //WJS-TODO remove this when working + } + JRadioButton myRadio = new JRadioButton(displayText); //NON-NLS + myRadio.setName(profileContextName); + myRadio.setToolTipText(profileDesc); + myRadio.addItemListener(this); + if (profileContextName.equals(selectedProfile)) { + myRadio.setSelected(true); + } + + buttonGroup1.add(myRadio); + jPanel1.add(myRadio); } @Override public String getName() { - return "Ingest Profile Selection"; + return "Ingest Profile Selection"; //WJS-TODO @Messages this } - List getElements() { + private List getElements() { if (elements.isEmpty()) { fetchListContents(); } return elements; } + private void clearListOfCheckBoxes() { + buttonGroup1 = new javax.swing.ButtonGroup(); + jPanel1.removeAll(); + } + /** * 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 @@ -80,7 +120,15 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); + setMaximumSize(new java.awt.Dimension(5750, 3000)); + setPreferredSize(new java.awt.Dimension(625, 450)); + org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.jButton1.text")); // NOI18N + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); jScrollPane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); @@ -118,8 +166,25 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis ); }// //GEN-END:initComponents + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog(true); + IngestOptionsPanel ingestOptions = new IngestOptionsPanel(); + ingestOptions.load(); + dialog.addApplyButtonListener( + (ActionEvent e) -> { + ingestOptions.store(); + clearListOfCheckBoxes(); + fetchListContents(); + jPanel1.revalidate(); + jPanel1.repaint(); + populateListOfCheckboxes(); + dialog.close(); + } + ); + dialog.display(ingestOptions); + }//GEN-LAST:event_jButton1ActionPerformed + boolean hasNextPanel = true; - private JRadioButton customSettings; // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton jButton1; @@ -137,18 +202,18 @@ public final class IngestProfileSelectionPanel extends JPanel implements ItemLis break; } } - boolean hadNextPanel = hasNextPanel; - hasNextPanel = !hasNextPanel; - System.out.println( - "SWITCHED VALUES, VALUE NOW:" + hasNextPanel); + if (selectedProfile.equals(RunIngestModuleWizardWizardIterator.getDefaultContext())) { + hasNextPanel = true; + } else { + hasNextPanel = false; + } wizardPanel.fireChangeEvent(); - this.firePropertyChange( - "LAST_ENABLED", hadNextPanel, hasNextPanel); + this.firePropertyChange("LAST_ENABLED", hadNextPanel, hasNextPanel); //NON-NLS } private void fetchListContents() { - elements = new ArrayList(); + elements = new ArrayList<>(); elements.addAll(new IngestProfileMap().getIngestProfileMap().values()); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java index 0eb9534fa5..28ebf04951 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java @@ -11,15 +11,19 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; -public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPanel { +class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPanel { private final Set listeners = new HashSet(1); + private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS + private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS /** * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). */ private IngestProfileSelectionPanel component; + private String lastProfileUsed; // Get the visual component for the panel. In this template, the component // is kept separate. This can be more efficient: if the wizard is created @@ -28,7 +32,13 @@ public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPan @Override public IngestProfileSelectionPanel getComponent() { if (component == null) { - component = new IngestProfileSelectionPanel(this); + if (ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null + || ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { + lastProfileUsed = RunIngestModuleWizardWizardIterator.getDefaultContext(); + } else { + lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); + } + component = new IngestProfileSelectionPanel(this, lastProfileUsed); } return component; } @@ -65,7 +75,6 @@ public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPan for (ChangeListener l : ls) { l.stateChanged(ev); } - } @Override @@ -84,13 +93,13 @@ public class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPan @Override public void readSettings(WizardDescriptor wiz) { - // use wiz.getProperty to retrieve previous panel state } @Override public void storeSettings(WizardDescriptor wiz) { - System.out.println("STORING EXECUTION CONTEXT" + component.selectedProfile); - wiz.putProperty("executionContext", component.selectedProfile); //NON-NLS + lastProfileUsed = component.getLastSelectedProfile(); + wiz.putProperty("executionContext", lastProfileUsed); //NON-NLS + ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME, lastProfileUsed); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java index f9da9f52c5..563723d2f6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java @@ -11,7 +11,7 @@ import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; -public class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPanel { +class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPanel { /** * f From a1f8fd61307469bd5be454ac1678b890195243f4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Feb 2017 18:24:48 -0500 Subject: [PATCH 31/73] 2198 renames, comments, and general clean up of RunIngestModulesWizard --- .../runIngestModuleWizard/Bundle.properties | 4 +- .../EarlyFinishWizardDescriptorPanel.java | 39 ++++- .../IngestProfileSelectionPanel.form | 30 ++-- .../IngestProfileSelectionPanel.java | 157 +++++++++++------- .../RunIngestModuleWizardWizardIterator.java | 27 ++- .../RunIngestModuleWizardWizardPanel1.java | 27 ++- .../RunIngestModuleWizardWizardPanel2.java | 21 ++- 7 files changed, 204 insertions(+), 101 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties index 66a07f4bad..6171140190 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/Bundle.properties @@ -1,2 +1,2 @@ -IngestProfileSelectionPanel.jButton1.text=Ingest Settings -IngestProfileSelectionPanel.jLabel1.text=Select Profile: +IngestProfileSelectionPanel.ingestSettingsButton.text=Ingest Settings +IngestProfileSelectionPanel.profileListLabel.text=Select Profile: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java index 8fb5dcddb4..d1d277f2a7 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java @@ -1,19 +1,42 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest.runIngestModuleWizard; import org.openide.WizardDescriptor; /** - * Abstract class for exten - * + * An abstract class which provides providing a method which can be checked by + * the iterator containing panels of this type. So that Wizards containing these + * panels can enable finish before the last panel. */ -abstract class ShortCircuitableWizardPanel implements WizardDescriptor.Panel { +abstract class EarlyFinishWizardDescriptorPanel implements WizardDescriptor.Panel { - boolean shouldCheckForNext(){ - return true; + /** + * Whether or not this should be treated as the last panel. + * + * @return true or false + */ + boolean isLastPanel(){ + /* + * This class should be overriden by any panel that might want to + * enable the finish button early for its wizard. + */ + return false; } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form index 7f5b676190..76c5f52c5d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form @@ -2,7 +2,7 @@
- + @@ -34,11 +34,11 @@ - + - - + + @@ -51,35 +51,35 @@ - + - + - + - + - + - + - + - + - + @@ -93,10 +93,10 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 059539e100..9b1dfb299a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -33,16 +33,23 @@ import org.sleuthkit.autopsy.ingest.IngestOptionsPanel; import org.sleuthkit.autopsy.ingest.IngestProfileMap; import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; +/** + * Visual panel for the choosing of ingest profiles by the user when running + * ingest. + */ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { private static final String CUSTOM_SETTINGS_DISPLAY_NAME = "Custom Settings"; private static final String CUSTOM_SETTINGS_DESCRIPTION = "configure individual module settings in next step of wizard"; //WJS-TODO these should be @Message private final RunIngestModuleWizardWizardPanel1 wizardPanel; private String selectedProfile; - private List elements = Collections.emptyList(); + private List profiles = Collections.emptyList(); /** - * Creates new form runIngestModuleWizardVisualPanel1 + * Creates new IngestProfileSelectionPanel + * + * @param panel - the WizardPanel which contains this panel + * @param lastSelectedProfile - the profile that will be selected initially */ IngestProfileSelectionPanel(RunIngestModuleWizardWizardPanel1 panel, String lastSelectedProfile) { initComponents(); @@ -50,24 +57,42 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { wizardPanel = panel; selectedProfile = lastSelectedProfile; populateListOfCheckboxes(); - + this.setName("Ingest Profile Selection"); //WJS-TODO @Messages this } + /** + * Returns the profile that is currently selected in this panel + * + * @return selectedProfile + */ String getLastSelectedProfile() { return selectedProfile; } + /** + * Adds a radio button for custom settings as well as one for each profile + * that has been created to the panel containing them. + */ private void populateListOfCheckboxes() { - elements = getElements(); + profiles = getProfiles(); addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModuleWizardWizardIterator.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); - for (IngestProfile profile : elements) { + for (IngestProfile profile : profiles) { addRadioButton(profile.toString(), profile.toString(), profile.getDescription()); } } + /** + * Creates and configures a single radio button before adding it to both the + * button group and the panel. + * + * @param profileDisplayName - the name of the profile the user should see + * @param profileContextName - the name the profile will be recognized as + * programmatically + * @param profileDesc - the description of the profile + */ private void addRadioButton(String profileDisplayName, String profileContextName, String profileDesc) { String displayText = profileDisplayName + " - " + profileDesc; - int width = jScrollPane1.getWidth(); + int width = profileListScrollPane.getWidth(); if (width > 3) { if (displayText.length() > width) { String ellipses = "..."; @@ -84,26 +109,28 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { myRadio.setSelected(true); } - buttonGroup1.add(myRadio); - jPanel1.add(myRadio); + profileListButtonGroup.add(myRadio); + profileListPanel.add(myRadio); } - @Override - public String getName() { - return "Ingest Profile Selection"; //WJS-TODO @Messages this - } - - private List getElements() { - if (elements.isEmpty()) { - fetchListContents(); + /** + * Getter for the list of profiles + * @return profiles + */ + private List getProfiles() { + if (profiles.isEmpty()) { + fetchProfileList(); } - return elements; + return profiles; } + /** + * Remove everything from the list of checkboxes. + */ private void clearListOfCheckBoxes() { - buttonGroup1 = new javax.swing.ButtonGroup(); - jPanel1.removeAll(); + profileListButtonGroup = new javax.swing.ButtonGroup(); + profileListPanel.removeAll(); } /** @@ -114,29 +141,29 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { // //GEN-BEGIN:initComponents private void initComponents() { - buttonGroup1 = new javax.swing.ButtonGroup(); - jButton1 = new javax.swing.JButton(); - jScrollPane1 = new javax.swing.JScrollPane(); - jPanel1 = new javax.swing.JPanel(); - jLabel1 = new javax.swing.JLabel(); + profileListButtonGroup = new javax.swing.ButtonGroup(); + ingestSettingsButton = new javax.swing.JButton(); + profileListScrollPane = new javax.swing.JScrollPane(); + profileListPanel = new javax.swing.JPanel(); + profileListLabel = new javax.swing.JLabel(); setMaximumSize(new java.awt.Dimension(5750, 3000)); setPreferredSize(new java.awt.Dimension(625, 450)); - org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.jButton1.text")); // NOI18N - jButton1.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsButton, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.ingestSettingsButton.text")); // NOI18N + ingestSettingsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - jButton1ActionPerformed(evt); + ingestSettingsButtonActionPerformed(evt); } }); - jScrollPane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + profileListScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - jPanel1.setAutoscrolls(true); - jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.PAGE_AXIS)); - jScrollPane1.setViewportView(jPanel1); + profileListPanel.setAutoscrolls(true); + profileListPanel.setLayout(new javax.swing.BoxLayout(profileListPanel, javax.swing.BoxLayout.PAGE_AXIS)); + profileListScrollPane.setViewportView(profileListPanel); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(profileListLabel, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.profileListLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -145,11 +172,11 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1) + .addComponent(profileListScrollPane) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(ingestSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(profileListLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(0, 523, Short.MAX_VALUE))) .addContainerGap()) ); @@ -157,16 +184,22 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(profileListLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 385, Short.MAX_VALUE) + .addComponent(profileListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 385, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jButton1) + .addComponent(ingestSettingsButton) .addGap(18, 18, 18)) ); }// //GEN-END:initComponents - private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + /** + * Opens up a dialog with an IngestOptionsPanel so the user can modify any + * settings from that options panel. + * + * @param evt the button press + */ + private void ingestSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ingestSettingsButtonActionPerformed final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog(true); IngestOptionsPanel ingestOptions = new IngestOptionsPanel(); ingestOptions.load(); @@ -174,46 +207,56 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { (ActionEvent e) -> { ingestOptions.store(); clearListOfCheckBoxes(); - fetchListContents(); - jPanel1.revalidate(); - jPanel1.repaint(); + fetchProfileList(); + profileListPanel.revalidate(); + profileListPanel.repaint(); populateListOfCheckboxes(); dialog.close(); } ); dialog.display(ingestOptions); - }//GEN-LAST:event_jButton1ActionPerformed + }//GEN-LAST:event_ingestSettingsButtonActionPerformed - boolean hasNextPanel = true; + boolean isLastPanel = false; // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.ButtonGroup buttonGroup1; - private javax.swing.JButton jButton1; - private javax.swing.JLabel jLabel1; - private javax.swing.JPanel jPanel1; - private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton ingestSettingsButton; + private javax.swing.ButtonGroup profileListButtonGroup; + private javax.swing.JLabel profileListLabel; + private javax.swing.JPanel profileListPanel; + private javax.swing.JScrollPane profileListScrollPane; // End of variables declaration//GEN-END:variables + /** + * Listens for changes and checks the currently selected radio button + * if custom settings button is enabled it enables the next button, + * otherwise it enables the Finish button. + * + * @param e + */ @Override public void itemStateChanged(ItemEvent e) { - for (Component rButton : jPanel1.getComponents()) { + for (Component rButton : profileListPanel.getComponents()) { JRadioButton jrb = (JRadioButton) rButton; if (jrb.isSelected()) { selectedProfile = jrb.getName(); break; } } - boolean hadNextPanel = hasNextPanel; + boolean wasLastPanel = isLastPanel; if (selectedProfile.equals(RunIngestModuleWizardWizardIterator.getDefaultContext())) { - hasNextPanel = true; + isLastPanel = false; } else { - hasNextPanel = false; + isLastPanel = true; } wizardPanel.fireChangeEvent(); - this.firePropertyChange("LAST_ENABLED", hadNextPanel, hasNextPanel); //NON-NLS + this.firePropertyChange("LAST_ENABLED", wasLastPanel, isLastPanel); //NON-NLS } - private void fetchListContents() { - elements = new ArrayList<>(); - elements.addAll(new IngestProfileMap().getIngestProfileMap().values()); + /** + * Get all the currently existing ingest profiles. + */ + private void fetchProfileList() { + profiles = new ArrayList<>(); + profiles.addAll(new IngestProfileMap().getIngestProfileMap().values()); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java index d2b4ba97b1..6d4b508343 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest.runIngestModuleWizard; @@ -21,7 +34,7 @@ final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iter private int index; - private List panels; + private List panels; /** * @return the DEFAULT_CONTEXT @@ -30,7 +43,7 @@ final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iter return DEFAULT_CONTEXT; } - private List getPanels() { + private List getPanels() { if (panels == null) { panels = new ArrayList<>(); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); @@ -58,7 +71,7 @@ final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iter } @Override - public ShortCircuitableWizardPanel current() { + public EarlyFinishWizardDescriptorPanel current() { return getPanels().get(index); } @@ -69,7 +82,7 @@ final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iter @Override public boolean hasNext() { - return (index < getPanels().size() - 1) && current().shouldCheckForNext(); + return (index < getPanels().size() - 1) && !current().isLastPanel(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java index 28ebf04951..ec91e9c2fe 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest.runIngestModuleWizard; @@ -13,7 +26,7 @@ import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.coreutils.ModuleSettings; -class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPanel { +class RunIngestModuleWizardWizardPanel1 extends EarlyFinishWizardDescriptorPanel { private final Set listeners = new HashSet(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS @@ -44,16 +57,14 @@ class RunIngestModuleWizardWizardPanel1 extends ShortCircuitableWizardPanel { } @Override - boolean shouldCheckForNext() { - return component.hasNextPanel; + boolean isLastPanel() { + return component.isLastPanel; } @Override public HelpCtx getHelp() { // Show no Help button for this panel: return HelpCtx.DEFAULT_HELP; - // If you have context help: - // return new HelpCtx("help.key.here"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java index 563723d2f6..eb970dacff 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest.runIngestModuleWizard; @@ -11,7 +24,7 @@ import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; -class RunIngestModuleWizardWizardPanel2 extends ShortCircuitableWizardPanel { +class RunIngestModuleWizardWizardPanel2 extends EarlyFinishWizardDescriptorPanel { /** * f From b559ca70b87e149285c4b54514226108660236d3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 2 Feb 2017 18:30:28 -0500 Subject: [PATCH 32/73] 2198 simplified names of runIngestModuleWizard classes --- .../IngestProfileSelectionPanel.java | 8 ++++---- ...rdIterator.java => RunIngestModuleWizardIterator.java} | 6 +++--- ...WizardPanel1.java => RunIngestModuleWizardPanel1.java} | 4 ++-- ...WizardPanel2.java => RunIngestModuleWizardPanel2.java} | 6 +++--- .../runIngestModuleWizard/RunIngestModulesAction.java | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModuleWizardWizardIterator.java => RunIngestModuleWizardIterator.java} (94%) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModuleWizardWizardPanel1.java => RunIngestModuleWizardPanel1.java} (95%) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModuleWizardWizardPanel2.java => RunIngestModuleWizardPanel2.java} (93%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 9b1dfb299a..898771b29c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -41,7 +41,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { private static final String CUSTOM_SETTINGS_DISPLAY_NAME = "Custom Settings"; private static final String CUSTOM_SETTINGS_DESCRIPTION = "configure individual module settings in next step of wizard"; //WJS-TODO these should be @Message - private final RunIngestModuleWizardWizardPanel1 wizardPanel; + private final RunIngestModuleWizardPanel1 wizardPanel; private String selectedProfile; private List profiles = Collections.emptyList(); @@ -51,7 +51,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { * @param panel - the WizardPanel which contains this panel * @param lastSelectedProfile - the profile that will be selected initially */ - IngestProfileSelectionPanel(RunIngestModuleWizardWizardPanel1 panel, String lastSelectedProfile) { + IngestProfileSelectionPanel(RunIngestModuleWizardPanel1 panel, String lastSelectedProfile) { initComponents(); //WJS-TODO figure out how to get width of writable area, if text length greater than width. Trim text to width minus 3 chars in length and then add ... to the end wizardPanel = panel; @@ -75,7 +75,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { */ private void populateListOfCheckboxes() { profiles = getProfiles(); - addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModuleWizardWizardIterator.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); + addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModuleWizardIterator.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); for (IngestProfile profile : profiles) { addRadioButton(profile.toString(), profile.toString(), profile.getDescription()); } @@ -243,7 +243,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { } } boolean wasLastPanel = isLastPanel; - if (selectedProfile.equals(RunIngestModuleWizardWizardIterator.getDefaultContext())) { + if (selectedProfile.equals(RunIngestModuleWizardIterator.getDefaultContext())) { isLastPanel = false; } else { isLastPanel = true; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java similarity index 94% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java index 6d4b508343..71fabd2aa8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java @@ -28,7 +28,7 @@ import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.sleuthkit.autopsy.ingest.IngestProfileMap; -final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iterator { +final class RunIngestModuleWizardIterator implements WizardDescriptor.Iterator { private final static String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleAction"; @@ -48,10 +48,10 @@ final class RunIngestModuleWizardWizardIterator implements WizardDescriptor.Iter panels = new ArrayList<>(); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); if (!profileMap.isEmpty()) { - panels.add(new RunIngestModuleWizardWizardPanel1()); + panels.add(new RunIngestModuleWizardPanel1()); } - panels.add(new RunIngestModuleWizardWizardPanel2()); + panels.add(new RunIngestModuleWizardPanel2()); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel1.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel1.java index ec91e9c2fe..012e73f421 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel1.java @@ -26,7 +26,7 @@ import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.coreutils.ModuleSettings; -class RunIngestModuleWizardWizardPanel1 extends EarlyFinishWizardDescriptorPanel { +class RunIngestModuleWizardPanel1 extends EarlyFinishWizardDescriptorPanel { private final Set listeners = new HashSet(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS @@ -47,7 +47,7 @@ class RunIngestModuleWizardWizardPanel1 extends EarlyFinishWizardDescriptorPanel if (component == null) { if (ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null || ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { - lastProfileUsed = RunIngestModuleWizardWizardIterator.getDefaultContext(); + lastProfileUsed = RunIngestModuleWizardIterator.getDefaultContext(); } else { lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java index eb970dacff..6cacb9f890 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java @@ -24,7 +24,7 @@ import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; -class RunIngestModuleWizardWizardPanel2 extends EarlyFinishWizardDescriptorPanel { +class RunIngestModuleWizardPanel2 extends EarlyFinishWizardDescriptorPanel { /** * f @@ -41,7 +41,7 @@ class RunIngestModuleWizardWizardPanel2 extends EarlyFinishWizardDescriptorPanel @Override public IngestJobSettingsPanel getComponent() { if (ingestJobSettingsPanel == null) { - ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModuleWizardWizardIterator.getDefaultContext())); + ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModuleWizardIterator.getDefaultContext())); } return ingestJobSettingsPanel; } @@ -81,7 +81,7 @@ class RunIngestModuleWizardWizardPanel2 extends EarlyFinishWizardDescriptorPanel public void storeSettings(WizardDescriptor wiz) { IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); ingestJobSettings.save(); - wiz.putProperty("executionContext", RunIngestModuleWizardWizardIterator.getDefaultContext()); //NON-NLS + wiz.putProperty("executionContext", RunIngestModuleWizardIterator.getDefaultContext()); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index d2939797e9..730b1990cf 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -71,7 +71,7 @@ public final class RunIngestModulesAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { - WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardWizardIterator()); + WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardIterator()); // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle(Bundle.RunIngestModulesAction_name()); From dc1250876822e67f614b75b75f8a60e8f9c97a69 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 3 Feb 2017 09:42:51 -0500 Subject: [PATCH 33/73] 2102: refactor the regression tests --- Testing/nbproject/project.xml | 39 ++- .../autopsy/testing/AutopsyTestCases.java | 290 ++++++++++++++++++ .../autopsy/testing/RegressionTest.java | 252 +-------------- test/script/regression.py | 4 +- 4 files changed, 346 insertions(+), 239 deletions(-) create mode 100755 Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java diff --git a/Testing/nbproject/project.xml b/Testing/nbproject/project.xml index bf4478337b..cfaf244b7b 100644 --- a/Testing/nbproject/project.xml +++ b/Testing/nbproject/project.xml @@ -6,6 +6,41 @@ org.sleuthkit.autopsy.testing + + org.netbeans.libs.junit4 + + + + 1.14 + + + + org.netbeans.modules.jellytools.platform + + + + 3 + 3.28.1 + + + + org.netbeans.modules.jemmy + + + + 3 + 3.26.1 + + + + org.netbeans.modules.nbjunit + + + + 1 + 1.86.1 + + org.sleuthkit.autopsy.core @@ -63,7 +98,9 @@ - + + org.sleuthkit.autopsy.testing + diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java new file mode 100755 index 0000000000..6368a5d8d9 --- /dev/null +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -0,0 +1,290 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.testing; + +import java.awt.AWTException; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.imageio.ImageIO; +import javax.swing.JDialog; +import javax.swing.text.JTextComponent; +import org.netbeans.jellytools.MainWindowOperator; +import org.netbeans.jellytools.NbDialogOperator; +import org.netbeans.jellytools.WizardOperator; +import org.netbeans.jemmy.Timeout; +import org.netbeans.jemmy.operators.JButtonOperator; +import org.netbeans.jemmy.operators.JCheckBoxOperator; +import org.netbeans.jemmy.operators.JComboBoxOperator; +import org.netbeans.jemmy.operators.JDialogOperator; +import org.netbeans.jemmy.operators.JFileChooserOperator; +import org.netbeans.jemmy.operators.JLabelOperator; +import org.netbeans.jemmy.operators.JListOperator; +import org.netbeans.jemmy.operators.JTabbedPaneOperator; +import org.netbeans.jemmy.operators.JTableOperator; +import org.netbeans.jemmy.operators.JTextFieldOperator; +import org.sleuthkit.autopsy.ingest.IngestManager; + +public class AutopsyTestCases { + + private static final Logger logger = Logger.getLogger(AutopsyTestCases.class.getName()); + private long start; + /** + * This method is used to escape file/directory path. Example: + * \\NetworkLocation\foo\bar get escaped to \\\\NetworkLocation\foo\bar so + * that it can be used as intended. + * + * @param path + * + * @return escaped path the the file/directory location. + */ + public static String getEscapedPath(String path) { + if (path.startsWith("\\\\")) { //already has escaped to \\\\NetworkLocation + return path; + } + if (path.startsWith("\\")) { + return "\\" + path; + } else { + return path; + } + } + + public AutopsyTestCases () { + start = 0; + } + + public void testNewCaseWizardOpen(String title) { + logger.info("New Case"); + NbDialogOperator nbdo = new NbDialogOperator(title); + JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button + jbo.pushNoBlock(); + } + + public void testNewCaseWizard() { + logger.info("New Case Wizard"); + WizardOperator wo = new WizardOperator("New Case Information"); + JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1); + jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase" + JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2); + jtfo1.typeText(getEscapedPath(System.getProperty("out_path"))); + wo.btNext().clickMouse(); + JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0); + jtfo2.typeText("000"); // Set the case number + JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1); + jtfo3.typeText("Examiner 1"); // Set the case examiner + start = System.currentTimeMillis(); + wo.btFinish().clickMouse(); + } + + public void testStartAddImageFileDataSource() { + logger.info("Starting Add Image process"); + WizardOperator wo = new WizardOperator("Add Data"); + JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0); + String img_path = getEscapedPath(System.getProperty("img_path")); + String imageDir = img_path; + ((JTextComponent) jtfo0.getSource()).setText(imageDir); + JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 1); + comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York"); + wo.btNext().clickMouse(); + } + + public void testStartAddLogicalFilesDataSource() { + logger.info("Starting Add Logical Files process"); + WizardOperator wo = new WizardOperator("Add Data"); + JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo); + // select the item indexed 2 (Logical Files) from the drop-down list. + comboBoxOperator.selectItem(2); + JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add"); + addButtonOperator.pushNoBlock(); + JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); + fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path")))); + // set the current directory one level above the directory containing logicalFileSet folder. + fileChooserOperator.goUpLevel(); + fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName()); + wo.btNext().clickMouse(); + } + + public void testAddSourceWizard1() { + WizardOperator wo = new WizardOperator("Add Data"); + while (!wo.btFinish().isEnabled()) { + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + } + logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start)); + wo.btFinish().clickMouse(); + } + + public void testConfigureIngest1() { + /* + * This timeout is to allow the setup for the ingest job settings panel + * to complete. + */ + new Timeout("pausing", 10000).sleep(); + + logger.info("Looking for hash lookup module in ingest job settings panel"); + WizardOperator wo = new WizardOperator("Add Data"); + JTableOperator jto = new JTableOperator(wo, 0); + int row = jto.findCellRow("Hash Lookup", 2, 0); + jto.clickOnCell(row, 1); + logger.info("Selected hash lookup module in ingest job settings panel"); + JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); + jbo1.pushNoBlock(); + logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel"); + } + + public void testConfigureHash() { + logger.info("Hash Configure"); + JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false); + JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog); + List databases = new ArrayList<>(); + databases.add(getEscapedPath(System.getProperty("nsrl_path"))); + databases.add(getEscapedPath(System.getProperty("known_bad_path"))); + databases.stream().map((database) -> { + JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import"); + importButtonOperator.pushNoBlock(); + JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Database", false, false); + JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog); + JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0); + browseButtonOperator.pushNoBlock(); + JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); + fileChooserOperator.chooseFile(database); + JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0); + return okButtonOperator; + }).map((okButtonOperator) -> { + okButtonOperator.pushNoBlock(); + return okButtonOperator; + }).forEach((_item) -> { + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + }); + // Used if the database has no index + //JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false); + //JDialogOperator jdo3 = new JDialogOperator(jd3); + //JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0); + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + //jbo3.pushNoBlock(); + JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0); + jbo4.pushNoBlock(); + } + + public void testConfigureIngest2() { + logger.info("Looking for keyword search module in ingest job settings panel"); + WizardOperator wo = new WizardOperator("Add Data"); + JTableOperator jto = new JTableOperator(wo, 0); + int row = jto.findCellRow("Keyword Search", 2, 0); + jto.clickOnCell(row, 1); + logger.info("Selected keyword search module in ingest job settings panel"); + JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); + jbo1.pushNoBlock(); + logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel"); + } + + public void testConfigureSearch() { + logger.info("Search Configure"); + JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false); + JDialogOperator jdo = new JDialogOperator(jd); + String words = getEscapedPath(System.getProperty("keyword_path")); + JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0); + jbo0.pushNoBlock(); + JFileChooserOperator jfco0 = new JFileChooserOperator(); + jfco0.chooseFile(words); + JTableOperator jto = new JTableOperator(jdo, 0); + jto.clickOnCell(0, 0); + new Timeout("pausing", 1000).sleep(); // give it a second to process + if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) { + JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo); + jtpo.selectPage("String Extraction"); + JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)"); + jcbo0.doClick(); + JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)"); + jcbo1.doClick(); + new Timeout("pausing", 1000).sleep(); // give it a second to process + } + JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0); + jbo2.pushNoBlock(); + WizardOperator wo = new WizardOperator("Add Data"); + new Timeout("pausing", 10000).sleep(); // let things catch up + wo.btNext().clickMouse(); + } + + public void testIngest() { + logger.info("Ingest 3"); + new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start + long startIngest = System.currentTimeMillis(); + IngestManager man = IngestManager.getInstance(); + while (man.isIngestRunning()) { + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + } + logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest)); + // allow keyword search to finish saving artifacts, just in case + // but randomize the timing so that we don't always get the same error + // consistently, making it seem like default behavior + Random rand = new Random(); + new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep(); + screenshot("Finished Ingest"); + + } + + public void testGenerateReportToolbar() { + logger.info("Generate Report Toolbars"); + MainWindowOperator mwo = MainWindowOperator.getDefault(); + JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report"); + jbo.pushNoBlock(); + new Timeout("pausing", 5000).sleep(); + } + + public void testGenerateReportButton() throws IOException { + logger.info("Generate Report Button"); + JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false); + JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog); + JListOperator listOperator = new JListOperator(reportDialogOperator); + JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next"); + DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); + Date date = new Date(); + String datenotime = dateFormat.format(date); + listOperator.clickOnItem(0, 1); + new Timeout("pausing", 1000).sleep(); + jbo0.pushNoBlock(); + new Timeout("pausing", 1000).sleep(); + JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish"); + jbo1.pushNoBlock(); + new Timeout("pausing", 500).sleep(); + JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false); + screenshot("Progress"); + JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog); + JLabelOperator.waitJLabel(previewDialog, "Complete", false, false); + JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close"); + jbo2.pushNoBlock(); + new Timeout("pausing", 10000).sleep(); + System.setProperty("ReportStr", datenotime); + screenshot("Done Testing"); + } + + public void screenshot(String name) { + logger.info("Taking screenshot."); + try { + Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); + BufferedImage capture = new Robot().createScreenCapture(screenRect); + String outPath = getEscapedPath(System.getProperty("out_path")); + ImageIO.write(capture, "png", new File(outPath + "\\" + name + ".png")); + new Timeout("pausing", 1000).sleep(); // give it a second to save + } catch (IOException ex) { + logger.log(Level.WARNING, "IOException taking screenshot.", ex); + } catch (AWTException ex) { + logger.log(Level.WARNING, "AWTException taking screenshot.", ex); + + } + } +} diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index b0831cf420..3cebb1cc93 100755 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -18,43 +18,13 @@ */ package org.sleuthkit.autopsy.testing; -import java.awt.AWTException; -import java.awt.Rectangle; -import java.awt.Robot; -import java.awt.Toolkit; -import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Random; -import java.util.logging.Level; import java.util.logging.Logger; -import javax.imageio.ImageIO; -import javax.swing.JDialog; -import javax.swing.JTextField; import junit.framework.Test; import junit.framework.TestCase; -import org.netbeans.jellytools.MainWindowOperator; -import org.netbeans.jellytools.NbDialogOperator; -import org.netbeans.jellytools.WizardOperator; -import org.netbeans.jemmy.Timeout; import org.netbeans.jemmy.Timeouts; -import org.netbeans.jemmy.operators.JButtonOperator; -import org.netbeans.jemmy.operators.JCheckBoxOperator; -import org.netbeans.jemmy.operators.JComboBoxOperator; -import org.netbeans.jemmy.operators.JDialogOperator; -import org.netbeans.jemmy.operators.JFileChooserOperator; -import org.netbeans.jemmy.operators.JLabelOperator; -import org.netbeans.jemmy.operators.JListOperator; -import org.netbeans.jemmy.operators.JTabbedPaneOperator; -import org.netbeans.jemmy.operators.JTableOperator; -import org.netbeans.jemmy.operators.JTextFieldOperator; import org.netbeans.junit.NbModuleSuite; -import org.sleuthkit.autopsy.ingest.IngestManager; /** * This test expects the following system properties to be set: img_path: The @@ -71,7 +41,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager; public class RegressionTest extends TestCase { private static final Logger logger = Logger.getLogger(RegressionTest.class.getName()); - long start; + private static final AutopsyTestCases autopsyTests = new AutopsyTestCases(); /** * Constructor required by JUnit @@ -80,32 +50,12 @@ public class RegressionTest extends TestCase { super(name); } - /** - * This method is used to escape file/directory path. Example: - * \\NetworkLocation\foo\bar get escaped to \\\\NetworkLocation\foo\bar so - * that it can be used as intended. - * - * @param path - * - * @return escaped path the the file/directory location. - */ - private static String getEscapedPath(String path) { - if (path.startsWith("\\\\")) { //already has escaped to \\\\NetworkLocation - return path; - } - else if (path.startsWith("\\")) { - return "\\" + path; - } else { - return path; - } - } - /** * Creates suite from particular test cases. */ public static Test suite() { // run tests with specific configuration - File img_path = new File(getEscapedPath(System.getProperty("img_path"))); + File img_path = new File(AutopsyTestCases.getEscapedPath(System.getProperty("img_path"))); NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(RegressionTest.class). clusters(".*"). enableModules(".*"); @@ -146,8 +96,7 @@ public class RegressionTest extends TestCase { */ @Override public void setUp() { - - logger.info("######## " + getEscapedPath(System.getProperty("img_path")) + " #######"); + logger.info("######## " + AutopsyTestCases.getEscapedPath(System.getProperty("img_path")) + " #######"); Timeouts.setDefault("ComponentOperator.WaitComponentTimeout", 1000000); } @@ -159,219 +108,50 @@ public class RegressionTest extends TestCase { } public void testNewCaseWizardOpen() { - logger.info("New Case"); - NbDialogOperator nbdo = new NbDialogOperator("Welcome"); - JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button - jbo.pushNoBlock(); + autopsyTests.testNewCaseWizardOpen("Welcome"); } public void testNewCaseWizard() { - logger.info("New Case Wizard"); - WizardOperator wo = new WizardOperator("New Case Information"); - JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1); - jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase" - JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2); - jtfo1.typeText(getEscapedPath(System.getProperty("out_path"))); - wo.btNext().clickMouse(); - JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0); - jtfo2.typeText("000"); // Set the case number - JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1); - jtfo3.typeText("Examiner 1"); // Set the case examiner - start = System.currentTimeMillis(); - wo.btFinish().clickMouse(); + autopsyTests.testNewCaseWizard(); } - + public void testStartAddImageFileDataSource() { - logger.info("Starting Add Image process"); - WizardOperator wo = new WizardOperator("Add Data"); - JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0); - String img_path = getEscapedPath(System.getProperty("img_path")); - String imageDir = img_path; - ((JTextField) jtfo0.getSource()).setText(imageDir); - JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 1); - comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York"); - wo.btNext().clickMouse(); + autopsyTests.testStartAddImageFileDataSource(); } public void testStartAddLogicalFilesDataSource() { - logger.info("Starting Add Logical Files process"); - WizardOperator wo = new WizardOperator("Add Data"); - JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo); - // select the item indexed 2 (Logical Files) from the drop-down list. - comboBoxOperator.selectItem(2); - JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add"); - addButtonOperator.pushNoBlock(); - JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); - fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path")))); - // set the current directory one level above the directory containing logicalFileSet folder. - fileChooserOperator.goUpLevel(); - fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName()); - wo.btNext().clickMouse(); + autopsyTests.testStartAddLogicalFilesDataSource(); } public void testAddSourceWizard1() { - WizardOperator wo = new WizardOperator("Add Data"); - while (!wo.btFinish().isEnabled()) { - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process - } - logger.info("Add image took " + (System.currentTimeMillis() - start) + "ms"); - wo.btFinish().clickMouse(); + autopsyTests.testAddSourceWizard1(); } public void testConfigureIngest1() { - /* - * This timeout is to allow the setup for the ingest job settings panel - * to complete. - */ - new Timeout("pausing", 10000).sleep(); - - logger.info("Looking for hash lookup module in ingest job settings panel"); - WizardOperator wo = new WizardOperator("Add Data"); - JTableOperator jto = new JTableOperator(wo, 0); - int row = jto.findCellRow("Hash Lookup", 2, 0); - jto.clickOnCell(row, 1); - logger.info("Selected hash lookup module in ingest job settings panel"); - JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); - jbo1.pushNoBlock(); - logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel"); + autopsyTests.testConfigureIngest1(); } public void testConfigureHash() { - logger.info("Hash Configure"); - JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false); - JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog); - List databases = new ArrayList(); - databases.add(getEscapedPath(System.getProperty("nsrl_path"))); - databases.add(getEscapedPath(System.getProperty("known_bad_path"))); - for (String database : databases) { - JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import"); - importButtonOperator.pushNoBlock(); - JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Database", false, false); - JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog); - JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0); - browseButtonOperator.pushNoBlock(); - JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); - fileChooserOperator.chooseFile(database); - JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0); - okButtonOperator.pushNoBlock(); - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process - } - // Used if the database has no index - //JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false); - //JDialogOperator jdo3 = new JDialogOperator(jd3); - //JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0); - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process - //jbo3.pushNoBlock(); - JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0); - jbo4.pushNoBlock(); + autopsyTests.testConfigureHash(); } public void testConfigureIngest2() { - logger.info("Looking for keyword search module in ingest job settings panel"); - WizardOperator wo = new WizardOperator("Add Data"); - JTableOperator jto = new JTableOperator(wo, 0); - int row = jto.findCellRow("Keyword Search", 2, 0); - jto.clickOnCell(row, 1); - logger.info("Selected keyword search module in ingest job settings panel"); - JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); - jbo1.pushNoBlock(); - logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel"); + autopsyTests.testConfigureIngest2(); } public void testConfigureSearch() { - logger.info("Search Configure"); - JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false); - JDialogOperator jdo = new JDialogOperator(jd); - String words = getEscapedPath(System.getProperty("keyword_path")); - JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0); - jbo0.pushNoBlock(); - JFileChooserOperator jfco0 = new JFileChooserOperator(); - jfco0.chooseFile(words); - JTableOperator jto = new JTableOperator(jdo, 0); - jto.clickOnCell(0, 0); - new Timeout("pausing", 1000).sleep(); // give it a second to process - if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) { - JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo); - jtpo.selectPage("String Extraction"); - JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)"); - jcbo0.doClick(); - JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)"); - jcbo1.doClick(); - new Timeout("pausing", 1000).sleep(); // give it a second to process - } - JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0); - jbo2.pushNoBlock(); - WizardOperator wo = new WizardOperator("Add Data"); - new Timeout("pausing", 10000).sleep(); // let things catch up - wo.btNext().clickMouse(); + autopsyTests.testConfigureSearch(); } public void testIngest() { - logger.info("Ingest 3"); - new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start - long startIngest = System.currentTimeMillis(); - IngestManager man = IngestManager.getInstance(); - while (man.isIngestRunning()) { - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process - } - logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest)); - // allow keyword search to finish saving artifacts, just in case - // but randomize the timing so that we don't always get the same error - // consistently, making it seem like default behavior - Random rand = new Random(); - new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep(); - screenshot("Finished Ingest"); - + autopsyTests.testIngest(); } public void testGenerateReportToolbar() { - logger.info("Generate Report Toolbars"); - MainWindowOperator mwo = MainWindowOperator.getDefault(); - JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report"); - jbo.pushNoBlock(); - new Timeout("pausing", 5000).sleep(); + autopsyTests.testGenerateReportToolbar(); } public void testGenerateReportButton() throws IOException { - logger.info("Generate Report Button"); - JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false); - JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog); - JListOperator listOperator = new JListOperator(reportDialogOperator); - JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next"); - DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); - Date date = new Date(); - String datenotime = dateFormat.format(date); - listOperator.clickOnItem(0, 1); - new Timeout("pausing", 1000).sleep(); - jbo0.pushNoBlock(); - new Timeout("pausing", 1000).sleep(); - JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish"); - jbo1.pushNoBlock(); - new Timeout("pausing", 500).sleep(); - JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false); - screenshot("Progress"); - JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog); - JLabelOperator.waitJLabel(previewDialog, "Complete", false, false); - JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close"); - jbo2.pushNoBlock(); - new Timeout("pausing", 10000).sleep(); - System.setProperty("ReportStr", datenotime); - screenshot("Done Testing"); - } - - public void screenshot(String name) { - logger.info("Taking screenshot."); - try { - Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); - BufferedImage capture = new Robot().createScreenCapture(screenRect); - String outPath = getEscapedPath(System.getProperty("out_path")); - ImageIO.write(capture, "png", new File(outPath + "\\" + name + ".png")); - new Timeout("pausing", 1000).sleep(); // give it a second to save - } catch (IOException ex) { - logger.log(Level.WARNING, "IOException taking screenshot.", ex); - } catch (AWTException ex) { - logger.log(Level.WARNING, "AWTException taking screenshot.", ex); - - } + autopsyTests.testGenerateReportButton(); } } diff --git a/test/script/regression.py b/test/script/regression.py index 0213941921..4ba9fc2174 100755 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -404,7 +404,7 @@ class TestRunner(object): test_data.ant = ["ant"] test_data.ant.append("-v") test_data.ant.append("-f") - test_data.ant.append(make_local_path(test_data.main_config.build_path)) + test_data.ant.append(make_local_path(test_data.main_config.build_path, "build.xml")) test_data.ant.append("regression-test") test_data.ant.append("-l") test_data.ant.append(test_data.antlog_dir) @@ -1485,7 +1485,7 @@ def copy_logs(test_data): shutil.copytree(log_dir, test_data.logs_dir) # copy logs from userdir0/var/log - log_dir = os.path.join("..", "..", "Testing","build","test","qa-functional","work","userdir0","var","log/") + log_dir = os.path.join(test_data.main_config.build_path,"build","test","qa-functional","work","userdir0","var","log/") for log in os.listdir(log_dir): if log.find("log"): new_name = log_dir + "userdir0." + log From c33a84179c847bbbed32f43647242d971c3841ab Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Feb 2017 10:55:17 -0500 Subject: [PATCH 34/73] 2198 additional comments and clean up for the RunIngestModulesWizard --- .../EarlyFinishWizardDescriptorPanel.java | 4 +-- .../IngestProfileSelectionPanel.java | 4 +-- .../RunIngestModuleWizardIterator.java | 18 +++++----- .../RunIngestModuleWizardPanel1.java | 23 +++++++++---- .../RunIngestModuleWizardPanel2.java | 12 ++----- .../RunIngestModulesAction.java | 33 +++++++++++++++---- 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java index d1d277f2a7..ec643d4d81 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java @@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; import org.openide.WizardDescriptor; /** - * An abstract class which provides providing a method which can be checked by + * An abstract class providing a method which can be checked by * the iterator containing panels of this type. So that Wizards containing these * panels can enable finish before the last panel. */ @@ -32,7 +32,7 @@ abstract class EarlyFinishWizardDescriptorPanel implements WizardDescriptor.Pane * * @return true or false */ - boolean isLastPanel(){ + boolean skipRemainingPanels(){ /* * This class should be overriden by any panel that might want to * enable the finish button early for its wizard. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 898771b29c..0113651ca0 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -75,7 +75,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { */ private void populateListOfCheckboxes() { profiles = getProfiles(); - addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModuleWizardIterator.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); + addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModulesAction.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); for (IngestProfile profile : profiles) { addRadioButton(profile.toString(), profile.toString(), profile.getDescription()); } @@ -243,7 +243,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { } } boolean wasLastPanel = isLastPanel; - if (selectedProfile.equals(RunIngestModuleWizardIterator.getDefaultContext())) { + if (selectedProfile.equals(RunIngestModulesAction.getDefaultContext())) { isLastPanel = false; } else { isLastPanel = true; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java index 71fabd2aa8..ca36bdb322 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java @@ -28,21 +28,22 @@ import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.sleuthkit.autopsy.ingest.IngestProfileMap; +/** + * Iterator class for creating a wizard for run ingest modules. + * + */ final class RunIngestModuleWizardIterator implements WizardDescriptor.Iterator { - private final static String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleAction"; - private int index; private List panels; /** - * @return the DEFAULT_CONTEXT + * Gets the list of panels used by this wizard for iterating over. + * Constructing it when it is null. + * + * @return panels - the list of of WizardDescriptor panels */ - static String getDefaultContext() { - return DEFAULT_CONTEXT; - } - private List getPanels() { if (panels == null) { panels = new ArrayList<>(); @@ -80,9 +81,10 @@ final class RunIngestModuleWizardIterator implements WizardDescriptor.Iterator listeners = new HashSet(1); @@ -47,7 +52,7 @@ class RunIngestModuleWizardPanel1 extends EarlyFinishWizardDescriptorPanel { if (component == null) { if (ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null || ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { - lastProfileUsed = RunIngestModuleWizardIterator.getDefaultContext(); + lastProfileUsed = RunIngestModulesAction.getDefaultContext(); } else { lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); } @@ -56,8 +61,15 @@ class RunIngestModuleWizardPanel1 extends EarlyFinishWizardDescriptorPanel { return component; } + /** + * Returns whether or not this should be considered the last panel of the + * wizard. Returns true when a profile is selected, and false when + * custom settings is selected. + * + * @return true or false + */ @Override - boolean isLastPanel() { + boolean skipRemainingPanels() { return component.isLastPanel; } @@ -71,12 +83,11 @@ class RunIngestModuleWizardPanel1 extends EarlyFinishWizardDescriptorPanel { public boolean isValid() { // If it is always OK to press Next or Finish, then: return true; - // If it depends on some condition (form filled out...) and - // this condition changes (last form field filled in...) then - // use ChangeSupport to implement add/removeChangeListener below. - // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful. } + /** + * Fires a change event to notify listeners that changes have taken place. + */ protected final void fireChangeEvent() { Set ls; synchronized (listeners) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java index 6cacb9f890..91f34d4bea 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java @@ -27,7 +27,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; class RunIngestModuleWizardPanel2 extends EarlyFinishWizardDescriptorPanel { /** - * f * The visual ingestJobSettingsPanel that displays this panel. If you need * to access the ingestJobSettingsPanel from this class, just use * getComponent(). @@ -41,7 +40,7 @@ class RunIngestModuleWizardPanel2 extends EarlyFinishWizardDescriptorPanel { @Override public IngestJobSettingsPanel getComponent() { if (ingestJobSettingsPanel == null) { - ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModuleWizardIterator.getDefaultContext())); + ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModulesAction.getDefaultContext())); } return ingestJobSettingsPanel; } @@ -50,18 +49,12 @@ class RunIngestModuleWizardPanel2 extends EarlyFinishWizardDescriptorPanel { public HelpCtx getHelp() { // Show no Help button for this panel: return HelpCtx.DEFAULT_HELP; - // If you have context help: - // return new HelpCtx("help.key.here"); } @Override public boolean isValid() { // If it is always OK to press Next or Finish, then: return true; - // If it depends on some condition (form filled out...) and - // this condition changes (last form field filled in...) then - // use ChangeSupport to implement add/removeChangeListener below. - // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful. } @Override @@ -74,14 +67,13 @@ class RunIngestModuleWizardPanel2 extends EarlyFinishWizardDescriptorPanel { @Override public void readSettings(WizardDescriptor wiz) { - // use wiz.getProperty to retrieve previous panel state } @Override public void storeSettings(WizardDescriptor wiz) { IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); ingestJobSettings.save(); - wiz.putProperty("executionContext", RunIngestModuleWizardIterator.getDefaultContext()); //NON-NLS + wiz.putProperty("executionContext", RunIngestModulesAction.getDefaultContext()); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index 730b1990cf..d0ac6180d7 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -39,15 +39,29 @@ import org.sleuthkit.datamodel.Directory; * modules. */ public final class RunIngestModulesAction extends AbstractAction { - + @Messages("RunIngestModulesAction.name=Run Ingest Modules") + private static final String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleAction"; + + /** + * Returns the name of the default context which will be used when profiles are not available. + * + * @return the DEFAULT_CONTEXT + */ + static String getDefaultContext() { + return DEFAULT_CONTEXT; + } + + private final List dataSources = new ArrayList<>(); private final IngestJobSettings.IngestType ingestType; /** - * the constructor - * @param dataSources + * Creates an action which will make a run ingest modules wizard when it + * is performed. + * + * @param dataSources - the data sources you want to run ingest on */ public RunIngestModulesAction(List dataSources) { this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); @@ -56,8 +70,10 @@ public final class RunIngestModulesAction extends AbstractAction { } /** - * the constructor - * @param dir + * Creates an action which will make a run ingest modules wizard when it + * is performed. + * + * @param dir - the directory you want to run ingest on */ public RunIngestModulesAction(Directory dir) { this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); @@ -65,7 +81,7 @@ public final class RunIngestModulesAction extends AbstractAction { this.ingestType = IngestJobSettings.IngestType.FILES_ONLY; } /** - * Runs the ingest modules wizard on the data source. + * Opens a run ingest modules wizard with the list of data sources. * * @param e the action event */ @@ -84,6 +100,11 @@ public final class RunIngestModulesAction extends AbstractAction { } } + /** + * Display any warnings that the ingestJobSettings have. + * + * @param ingestJobSettings + */ private static void showWarnings(IngestJobSettings ingestJobSettings) { List warnings = ingestJobSettings.getWarnings(); if (warnings.isEmpty() == false) { From f81a8fd1737e0b69ae09086da85304e53d063cc4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Feb 2017 11:30:19 -0500 Subject: [PATCH 35/73] 2198 Names made more consistant, other minor clean up --- .../IngestProfileSelectionPanel.java | 24 ++++++++----------- .../RunIngestModulesAction.java | 2 +- ...va => RunIngestModulesWizardIterator.java} | 6 ++--- ...java => RunIngestModulesWizardPanel1.java} | 2 +- ...java => RunIngestModulesWizardPanel2.java} | 2 +- 5 files changed, 16 insertions(+), 20 deletions(-) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModuleWizardIterator.java => RunIngestModulesWizardIterator.java} (94%) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModuleWizardPanel1.java => RunIngestModulesWizardPanel1.java} (98%) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModuleWizardPanel2.java => RunIngestModulesWizardPanel2.java} (97%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 0113651ca0..a9b7d8f3f7 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -28,6 +28,7 @@ import java.util.List; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; import org.sleuthkit.autopsy.ingest.IngestOptionsPanel; import org.sleuthkit.autopsy.ingest.IngestProfileMap; @@ -39,9 +40,13 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; */ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { - private static final String CUSTOM_SETTINGS_DISPLAY_NAME = "Custom Settings"; - private static final String CUSTOM_SETTINGS_DESCRIPTION = "configure individual module settings in next step of wizard"; //WJS-TODO these should be @Message - private final RunIngestModuleWizardPanel1 wizardPanel; + @Messages({"IngestProfileSelectionPanel.customSettings.name=Custom Settings", + "IngestProfileSelectionPanel.name=Ingest Profile Selection", + "IngestProfileSelectionPanel.customSettings.description=configure individual module settings in next step of wizard"}) + + private static final String CUSTOM_SETTINGS_DISPLAY_NAME = Bundle.IngestProfileSelectionPanel_customSettings_name(); + private static final String CUSTOM_SETTINGS_DESCRIPTION = Bundle.IngestProfileSelectionPanel_customSettings_description(); + private final RunIngestModulesWizardPanel1 wizardPanel; private String selectedProfile; private List profiles = Collections.emptyList(); @@ -51,13 +56,13 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { * @param panel - the WizardPanel which contains this panel * @param lastSelectedProfile - the profile that will be selected initially */ - IngestProfileSelectionPanel(RunIngestModuleWizardPanel1 panel, String lastSelectedProfile) { + IngestProfileSelectionPanel(RunIngestModulesWizardPanel1 panel, String lastSelectedProfile) { initComponents(); //WJS-TODO figure out how to get width of writable area, if text length greater than width. Trim text to width minus 3 chars in length and then add ... to the end wizardPanel = panel; selectedProfile = lastSelectedProfile; populateListOfCheckboxes(); - this.setName("Ingest Profile Selection"); //WJS-TODO @Messages this + this.setName(Bundle.IngestProfileSelectionPanel_name()); } /** @@ -92,15 +97,6 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { */ private void addRadioButton(String profileDisplayName, String profileContextName, String profileDesc) { String displayText = profileDisplayName + " - " + profileDesc; - int width = profileListScrollPane.getWidth(); - if (width > 3) { - if (displayText.length() > width) { - String ellipses = "..."; - displayText = displayText.substring(0, width - ellipses.length()) + ellipses; - } - } else { - System.out.println("NOT KNOWN BEFORE DRAWN USE DIFFERENT WAY TO GET WIDTH"); //WJS-TODO remove this when working - } JRadioButton myRadio = new JRadioButton(displayText); //NON-NLS myRadio.setName(profileContextName); myRadio.setToolTipText(profileDesc); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index d0ac6180d7..d325e649e7 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -87,7 +87,7 @@ public final class RunIngestModulesAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { - WizardDescriptor wiz = new WizardDescriptor(new RunIngestModuleWizardIterator()); + WizardDescriptor wiz = new WizardDescriptor(new RunIngestModulesWizardIterator()); // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle(Bundle.RunIngestModulesAction_name()); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java similarity index 94% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index ca36bdb322..fc54b3f133 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap; * Iterator class for creating a wizard for run ingest modules. * */ -final class RunIngestModuleWizardIterator implements WizardDescriptor.Iterator { +final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator { private int index; @@ -49,10 +49,10 @@ final class RunIngestModuleWizardIterator implements WizardDescriptor.Iterator(); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); if (!profileMap.isEmpty()) { - panels.add(new RunIngestModuleWizardPanel1()); + panels.add(new RunIngestModulesWizardPanel1()); } - panels.add(new RunIngestModuleWizardPanel2()); + panels.add(new RunIngestModulesWizardPanel2()); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel1.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java index 841e75dd41..0b0ed9386d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; * selection panel and is only created when profiles exist. * */ -class RunIngestModuleWizardPanel1 extends EarlyFinishWizardDescriptorPanel { +class RunIngestModulesWizardPanel1 extends EarlyFinishWizardDescriptorPanel { private final Set listeners = new HashSet(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel2.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel2.java index 91f34d4bea..5d80ef1848 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModuleWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel2.java @@ -24,7 +24,7 @@ import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; -class RunIngestModuleWizardPanel2 extends EarlyFinishWizardDescriptorPanel { +class RunIngestModulesWizardPanel2 extends EarlyFinishWizardDescriptorPanel { /** * The visual ingestJobSettingsPanel that displays this panel. If you need From 33efc3bce548108335afb1c88781646e1273c158 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Feb 2017 12:47:19 -0500 Subject: [PATCH 36/73] 2198 fixed a few netbeans warnings --- .../sleuthkit/autopsy/ingest/ProfileSettingsPanel.java | 4 +++- .../IngestProfileSelectionPanel.java | 9 ++------- .../RunIngestModulesWizardPanel1.java | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 6a8d5b2cc5..c2faa9b0d0 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -44,15 +44,17 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op "ProfileSettingsPanel.editProfileButton.text=Edit Profile", "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile", "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter", + "# {0} - profile name", "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text=Profile with name {0} already exists." }) - private final DefaultListModel profilesListModel = new DefaultListModel<>(); + private final DefaultListModel profilesListModel; /** * Creates new form ProfileOptionsPanel */ ProfileSettingsPanel() { + this.profilesListModel = new DefaultListModel<>(); initComponents(); this.profileList.setModel(profilesListModel); this.profileList.addListSelectionListener(new ProfileSettingsPanel.ProfileListSelectionListener()); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index a9b7d8f3f7..088f173a25 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -58,7 +58,6 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { */ IngestProfileSelectionPanel(RunIngestModulesWizardPanel1 panel, String lastSelectedProfile) { initComponents(); - //WJS-TODO figure out how to get width of writable area, if text length greater than width. Trim text to width minus 3 chars in length and then add ... to the end wizardPanel = panel; selectedProfile = lastSelectedProfile; populateListOfCheckboxes(); @@ -97,7 +96,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { */ private void addRadioButton(String profileDisplayName, String profileContextName, String profileDesc) { String displayText = profileDisplayName + " - " + profileDesc; - JRadioButton myRadio = new JRadioButton(displayText); //NON-NLS + JRadioButton myRadio = new JRadioButton(displayText); myRadio.setName(profileContextName); myRadio.setToolTipText(profileDesc); myRadio.addItemListener(this); @@ -239,11 +238,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { } } boolean wasLastPanel = isLastPanel; - if (selectedProfile.equals(RunIngestModulesAction.getDefaultContext())) { - isLastPanel = false; - } else { - isLastPanel = true; - } + isLastPanel = !selectedProfile.equals(RunIngestModulesAction.getDefaultContext()); wizardPanel.fireChangeEvent(); this.firePropertyChange("LAST_ENABLED", wasLastPanel, isLastPanel); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java index 0b0ed9386d..5fc779e8ef 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ class RunIngestModulesWizardPanel1 extends EarlyFinishWizardDescriptorPanel { - private final Set listeners = new HashSet(1); + private final Set listeners = new HashSet<>(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS /** From 17fc209cf7a17ef345fffd088a488328970df435 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Feb 2017 14:45:29 -0500 Subject: [PATCH 37/73] 2198 - fixes to UI of profile panel --- .../autopsy/ingest/ProfileSettingsPanel.form | 147 ++++++++++-------- .../autopsy/ingest/ProfileSettingsPanel.java | 117 +++++++------- 2 files changed, 142 insertions(+), 122 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form index 6c37eb6522..d9d1e54aeb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.form @@ -7,6 +7,9 @@ + + + @@ -24,26 +27,25 @@ + - - - - - - - - - - - - - - + + + + + + + + + + + - + + @@ -59,70 +61,62 @@ - + - - - + + + - - - - - - - - + - - - - - - - - + + + - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + @@ -156,16 +150,17 @@ - - - - - + + + + + + @@ -182,9 +177,15 @@ + + + + + + @@ -201,9 +202,18 @@ + + + + + + + + + @@ -325,5 +335,10 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index c2faa9b0d0..524f2d6815 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -73,7 +73,6 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op profileListPane = new javax.swing.JScrollPane(); profileList = new javax.swing.JList<>(); profileListLabel = new javax.swing.JLabel(); - jSeparator1 = new javax.swing.JSeparator(); newProfileButton = new javax.swing.JButton(); editProfileButton = new javax.swing.JButton(); deleteProfileButton = new javax.swing.JButton(); @@ -89,17 +88,19 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op selectedModulesArea = new javax.swing.JTextArea(); selectedModulesLabel = new javax.swing.JLabel(); ingestWarningLabel = new javax.swing.JLabel(); + jSeparator2 = new javax.swing.JSeparator(); setBorder(javax.swing.BorderFactory.createEtchedBorder()); + setPreferredSize(new java.awt.Dimension(800, 488)); profileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); profileListPane.setViewportView(profileList); org.openide.awt.Mnemonics.setLocalizedText(profileListLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.profileListLabel.text")); // NOI18N - jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); - + newProfileButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.newProfileButton.text")); // NOI18N + newProfileButton.setMargin(new java.awt.Insets(2, 8, 2, 8)); newProfileButton.setMaximumSize(new java.awt.Dimension(97, 23)); newProfileButton.setMinimumSize(new java.awt.Dimension(97, 23)); newProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); @@ -109,7 +110,9 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } }); + editProfileButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(editProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.editProfileButton.text")); // NOI18N + editProfileButton.setMargin(new java.awt.Insets(2, 8, 2, 8)); editProfileButton.setMaximumSize(new java.awt.Dimension(97, 23)); editProfileButton.setMinimumSize(new java.awt.Dimension(97, 23)); editProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); @@ -119,7 +122,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } }); + deleteProfileButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(deleteProfileButton, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.deleteProfileButton.text")); // NOI18N + deleteProfileButton.setMargin(new java.awt.Insets(2, 8, 2, 8)); + deleteProfileButton.setPreferredSize(new java.awt.Dimension(97, 23)); deleteProfileButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteProfileButtonActionPerformed(evt); @@ -162,26 +168,28 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.ingestWarningLabel.text")); // NOI18N + jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() + .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(profileListLabel)) - .addGroup(layout.createSequentialGroup() - .addGap(20, 20, 20) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(profileListPane) - .addGroup(layout.createSequentialGroup() - .addComponent(newProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(profileListLabel) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(profileListPane, javax.swing.GroupLayout.PREFERRED_SIZE, 339, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(newProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editProfileButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(editProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 98, Short.MAX_VALUE))))) - .addGap(18, 18, 18) + .addComponent(deleteProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(6, 6, 6))) + .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(6, 6, 6) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(filterNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -194,56 +202,53 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op .addComponent(profileDescLabel)) .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addGap(10, 10, 10) + .addGap(8, 8, 8) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(ingestWarningLabel) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) - .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING)))) - .addGap(14, 14, 14)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(330, Short.MAX_VALUE) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(564, Short.MAX_VALUE))) + .addComponent(filterDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE) + .addComponent(profileDescPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE) + .addComponent(selectedModulesPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE)))) + .addGap(12, 12, 12)) ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {deleteProfileButton, editProfileButton, newProfileButton}); + layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(profileListLabel) - .addComponent(profileDescLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(profileDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(profileListLabel) + .addComponent(profileDescLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(filterNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(filterNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filterDescLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filterDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(selectedModulesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(selectedModulesPane)) - .addComponent(profileListPane, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE)) - .addGap(4, 4, 4) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(editProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(deleteProfileButton) - .addComponent(ingestWarningLabel)) - .addContainerGap()) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 477, Short.MAX_VALUE))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(profileDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(filterNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(filterNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterDescLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterDescPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(selectedModulesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(selectedModulesPane)) + .addComponent(profileListPane, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)) + .addGap(4, 4, 4) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteProfileButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ingestWarningLabel)) + .addContainerGap()) + .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING))) ); }// //GEN-END:initComponents @@ -408,7 +413,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private javax.swing.JLabel filterNameLabel; private javax.swing.JLabel filterNameText; private javax.swing.JLabel ingestWarningLabel; - private javax.swing.JSeparator jSeparator1; + private javax.swing.JSeparator jSeparator2; private javax.swing.JButton newProfileButton; private javax.swing.JTextArea profileDescArea; private javax.swing.JLabel profileDescLabel; From bf43d674ba6cd25a8df70d6541a1f1f7371895e4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Feb 2017 17:41:59 -0500 Subject: [PATCH 38/73] 2198 replaced custom abstract class with WizardDescriptor.FinishablePanel --- .../EarlyFinishWizardDescriptorPanel.java | 42 ------------------- ...va => IngestModulesConfigWizardPanel.java} | 7 +++- .../IngestProfileSelectionPanel.java | 4 +- ...=> IngestProfileSelectionWizardPanel.java} | 21 ++++------ .../RunIngestModulesWizardIterator.java | 12 +++--- 5 files changed, 21 insertions(+), 65 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModulesWizardPanel2.java => IngestModulesConfigWizardPanel.java} (93%) rename Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/{RunIngestModulesWizardPanel1.java => IngestProfileSelectionWizardPanel.java} (91%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java deleted file mode 100644 index ec643d4d81..0000000000 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/EarlyFinishWizardDescriptorPanel.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.ingest.runIngestModuleWizard; - -import org.openide.WizardDescriptor; - -/** - * An abstract class providing a method which can be checked by - * the iterator containing panels of this type. So that Wizards containing these - * panels can enable finish before the last panel. - */ -abstract class EarlyFinishWizardDescriptorPanel implements WizardDescriptor.Panel { - - /** - * Whether or not this should be treated as the last panel. - * - * @return true or false - */ - boolean skipRemainingPanels(){ - /* - * This class should be overriden by any panel that might want to - * enable the finish button early for its wizard. - */ - return false; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel2.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java index 5d80ef1848..5244eeaaf3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java @@ -24,7 +24,7 @@ import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; -class RunIngestModulesWizardPanel2 extends EarlyFinishWizardDescriptorPanel { +class IngestModulesConfigWizardPanel implements WizardDescriptor.FinishablePanel { /** * The visual ingestJobSettingsPanel that displays this panel. If you need @@ -76,4 +76,9 @@ class RunIngestModulesWizardPanel2 extends EarlyFinishWizardDescriptorPanel { wiz.putProperty("executionContext", RunIngestModulesAction.getDefaultContext()); //NON-NLS } + @Override + public boolean isFinishPanel() { + return true; + } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 088f173a25..7486d74c99 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -46,7 +46,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { private static final String CUSTOM_SETTINGS_DISPLAY_NAME = Bundle.IngestProfileSelectionPanel_customSettings_name(); private static final String CUSTOM_SETTINGS_DESCRIPTION = Bundle.IngestProfileSelectionPanel_customSettings_description(); - private final RunIngestModulesWizardPanel1 wizardPanel; + private final IngestProfileSelectionWizardPanel wizardPanel; private String selectedProfile; private List profiles = Collections.emptyList(); @@ -56,7 +56,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { * @param panel - the WizardPanel which contains this panel * @param lastSelectedProfile - the profile that will be selected initially */ - IngestProfileSelectionPanel(RunIngestModulesWizardPanel1 panel, String lastSelectedProfile) { + IngestProfileSelectionPanel(IngestProfileSelectionWizardPanel panel, String lastSelectedProfile) { initComponents(); wizardPanel = panel; selectedProfile = lastSelectedProfile; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java rename to Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index 5fc779e8ef..bfa8b035cf 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; * selection panel and is only created when profiles exist. * */ -class RunIngestModulesWizardPanel1 extends EarlyFinishWizardDescriptorPanel { +class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePanel { private final Set listeners = new HashSet<>(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS @@ -60,19 +60,7 @@ class RunIngestModulesWizardPanel1 extends EarlyFinishWizardDescriptorPanel { } return component; } - - /** - * Returns whether or not this should be considered the last panel of the - * wizard. Returns true when a profile is selected, and false when - * custom settings is selected. - * - * @return true or false - */ - @Override - boolean skipRemainingPanels() { - return component.isLastPanel; - } - + @Override public HelpCtx getHelp() { // Show no Help button for this panel: @@ -124,4 +112,9 @@ class RunIngestModulesWizardPanel1 extends EarlyFinishWizardDescriptorPanel { ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME, lastProfileUsed); } + @Override + public boolean isFinishPanel() { + return component.isLastPanel; + } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index fc54b3f133..7354255456 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -36,7 +36,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< private int index; - private List panels; + private List> panels; /** * Gets the list of panels used by this wizard for iterating over. @@ -44,15 +44,15 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< * * @return panels - the list of of WizardDescriptor panels */ - private List getPanels() { + private List> getPanels() { if (panels == null) { panels = new ArrayList<>(); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); if (!profileMap.isEmpty()) { - panels.add(new RunIngestModulesWizardPanel1()); + panels.add(new IngestProfileSelectionWizardPanel()); } - panels.add(new RunIngestModulesWizardPanel2()); + panels.add(new IngestModulesConfigWizardPanel()); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); @@ -72,7 +72,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< } @Override - public EarlyFinishWizardDescriptorPanel current() { + public WizardDescriptor.FinishablePanel current() { return getPanels().get(index); } @@ -84,7 +84,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< @Override public boolean hasNext() { - return (index < getPanels().size() - 1) && !current().skipRemainingPanels(); + return (index < getPanels().size() - 1) && !current().isFinishPanel(); } @Override From b99efaf031cb4a28efe399851c36bdafab53bf21 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 6 Feb 2017 16:05:00 -0500 Subject: [PATCH 39/73] 2199 addImageWizard working with profiles --- .../AddImageWizardChooseDataSourcePanel.java | 7 ++- .../AddImageWizardIngestConfigPanel.java | 48 ++++++++++++++++--- .../casemodule/AddImageWizardIterator.java | 26 ++++++++-- .../ingest/IngestJobSettingsPanel.java | 2 +- .../IngestProfileSelectionPanel.java | 4 +- .../IngestProfileSelectionWizardPanel.java | 26 +++++++--- .../RunIngestModulesWizardIterator.java | 14 ++++-- 7 files changed, 102 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 88762ba96a..e845b89349 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -38,7 +38,7 @@ import java.awt.Cursor; * The "Add Image" wizard panel1 handling the logic of selecting image file(s) * to add to Case, and pick the time zone. */ -class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel, PropertyChangeListener { +class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.FinishablePanel, PropertyChangeListener { /** * The visual component that displays this panel. If you need to access the @@ -232,4 +232,9 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel { +class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePanel { - private final IngestJobSettingsPanel ingestJobSettingsPanel; + private IngestJobSettingsPanel ingestJobSettingsPanel; /** * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). */ private Component component = null; - + private String lastProfileUsed = AddImageWizardIngestConfigPanel.class.getCanonicalName(); private final List newContents = Collections.synchronizedList(new ArrayList()); private boolean ingested = false; private boolean readyToIngest = false; @@ -76,8 +77,9 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel> panels; private AddImageAction action; + private int progressPanelIndex; + private int profileSelectionIndex; AddImageWizardIterator(AddImageAction action) { this.action = action; @@ -53,11 +58,17 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator profileMap = new IngestProfileMap().getIngestProfileMap(); + if (!profileMap.isEmpty()) { + panels.add(profileSelectionPanel); + } + panels.add(ingestConfigPanel); panels.add(progressPanel); - + progressPanelIndex = panels.indexOf(progressPanel); //Doing programatically incase more panels added + profileSelectionIndex = panels.indexOf(profileSelectionPanel); //will be -1 if it wasn't added String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); @@ -146,7 +157,16 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator { +public class IngestProfileSelectionWizardPanel implements WizardDescriptor.Panel { private final Set listeners = new HashSet<>(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS @@ -42,6 +42,18 @@ class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePa */ private IngestProfileSelectionPanel component; private String lastProfileUsed; + private final String defaultContext; + + public IngestProfileSelectionWizardPanel(String defaultContext) { + this.defaultContext = defaultContext; + } + + /** + * @return the defaultContext + */ + String getDefaultContext() { + return defaultContext; + } // Get the visual component for the panel. In this template, the component // is kept separate. This can be more efficient: if the wizard is created @@ -50,17 +62,17 @@ class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePa @Override public IngestProfileSelectionPanel getComponent() { if (component == null) { - if (ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null - || ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { - lastProfileUsed = RunIngestModulesAction.getDefaultContext(); - } else { + if (!(ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null) + && !ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); + } else { + lastProfileUsed = getDefaultContext(); } component = new IngestProfileSelectionPanel(this, lastProfileUsed); } return component; } - + @Override public HelpCtx getHelp() { // Show no Help button for this panel: @@ -110,9 +122,9 @@ class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePa lastProfileUsed = component.getLastSelectedProfile(); wiz.putProperty("executionContext", lastProfileUsed); //NON-NLS ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME, lastProfileUsed); + System.out.println("STORED LAST PROFILE USED AS: " + lastProfileUsed); } - @Override public boolean isFinishPanel() { return component.isLastPanel; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index 7354255456..c7bae2a5e0 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -35,8 +35,9 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap; final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator { private int index; + private int profilePanelIndex; - private List> panels; + private List> panels; /** * Gets the list of panels used by this wizard for iterating over. @@ -44,15 +45,17 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< * * @return panels - the list of of WizardDescriptor panels */ - private List> getPanels() { + private List> getPanels() { if (panels == null) { panels = new ArrayList<>(); + IngestProfileSelectionWizardPanel profilePanel = new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext()); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); if (!profileMap.isEmpty()) { - panels.add(new IngestProfileSelectionWizardPanel()); + panels.add(profilePanel); } panels.add(new IngestModulesConfigWizardPanel()); + profilePanelIndex=panels.indexOf(profilePanel); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); @@ -72,7 +75,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< } @Override - public WizardDescriptor.FinishablePanel current() { + public WizardDescriptor.Panel current() { return getPanels().get(index); } @@ -84,7 +87,8 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< @Override public boolean hasNext() { - return (index < getPanels().size() - 1) && !current().isFinishPanel(); + return (index < getPanels().size() - 1 && + !(index == profilePanelIndex && ((IngestProfileSelectionWizardPanel)current()).isFinishPanel())); } @Override From 288a993aafbfb55cfe71470511f49d434b797321 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 6 Feb 2017 17:43:47 -0500 Subject: [PATCH 40/73] 2199 Changed from casting to abstract class use and other clean up --- .../AddImageWizardAddingProgressPanel.java | 7 +- .../AddImageWizardChooseDataSourcePanel.java | 8 +-- .../AddImageWizardIngestConfigPanel.java | 34 ++++------ .../casemodule/AddImageWizardIterator.java | 49 +++++++++----- .../IngestModulesConfigWizardPanel.java | 7 +- .../IngestProfileSelectionWizardPanel.java | 37 +++++++---- .../RunIngestModulesWizardIterator.java | 14 ++-- .../ShortcutWizardDescriptorPanel.java | 64 +++++++++++++++++++ 8 files changed, 145 insertions(+), 75 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 7204664d2f..50134fa88a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -30,6 +30,7 @@ import org.openide.util.HelpCtx; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; /** * The final panel of the add image wizard. It displays a progress bar and @@ -39,7 +40,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgress * {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m * -jm) */ -class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePanel { +class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { /** * flag to indicate that the image adding process is finished and this panel @@ -239,8 +240,4 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa getComponent().showErrors(errorString, critical); } - @Override - public boolean isFinishPanel() { - return true; - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index e845b89349..259cb4f4d3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -33,12 +33,13 @@ import org.openide.util.HelpCtx; import org.openide.util.Lookup; import org.openide.windows.WindowManager; import java.awt.Cursor; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; /** * The "Add Image" wizard panel1 handling the logic of selecting image file(s) * to add to Case, and pick the time zone. */ -class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.FinishablePanel, PropertyChangeListener { +class AddImageWizardChooseDataSourcePanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener { /** * The visual component that displays this panel. If you need to access the @@ -232,9 +233,4 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Finishable public void propertyChange(PropertyChangeEvent evt) { fireChangeEvent(); } - - @Override - public boolean isFinishPanel() { - return false; - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index ccdd0c1426..a37df4227a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -40,6 +40,8 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.IngestProfileSelectionWizardPanel; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; /** * second panel of add image wizard, allows user to configure ingest modules. @@ -47,7 +49,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager; * TODO: review this for dead code. think about moving logic of adding image to * 3rd panel( {@link AddImageWizardAddingProgressPanel}) separate class -jm */ -class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePanel { +class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { private IngestJobSettingsPanel ingestJobSettingsPanel; @@ -60,7 +62,6 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePane private final List newContents = Collections.synchronizedList(new ArrayList()); private boolean ingested = false; private boolean readyToIngest = false; - // task that will clean up the created database file if the wizard is cancelled before it finishes private AddImageAction.CleanupTask cleanupTask; @@ -79,7 +80,6 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePane IngestJobSettings ingestJobSettings = new IngestJobSettings(lastProfileUsed); showWarnings(ingestJobSettings); - System.out.println("LAST PROFILE USED CREATE: " + lastProfileUsed); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); } @@ -162,12 +162,9 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePane */ @Override public void readSettings(WizardDescriptor settings) { - String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS //WJS-TODO remove these copies, leaving copies in IngestProfileSelectionWizardPanel - String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS - if (!(ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null) - && !ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { - lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); - System.out.println("LAST PROFILE USED READ: " + lastProfileUsed); + if (!(ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()) == null) + && !ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()).isEmpty()) { + lastProfileUsed = ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()); } IngestJobSettings ingestJobSettings = new IngestJobSettings(lastProfileUsed); showWarnings(ingestJobSettings); @@ -200,7 +197,6 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePane public void storeSettings(WizardDescriptor settings) { IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); - System.out.println("LAST PROFILE USED STORE: " + lastProfileUsed); ingestJobSettings.save(); showWarnings(ingestJobSettings); @@ -220,13 +216,12 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePane } } - void skippingThisPanel() { - String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS //WJS-TODO remove these copies, leaving copies in IngestProfileSelectionWizardPanel - String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS - if (!(ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null) - && !ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { - lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); - System.out.println("LAST PROFILE USED READ: " + lastProfileUsed); + + @Override + public void processThisPanelBeforeSkipped() { + if (!(ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()) == null) + && !ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()).isEmpty()) { + lastProfileUsed = ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()); } IngestJobSettings ingestJobSettings = new IngestJobSettings(lastProfileUsed); showWarnings(ingestJobSettings); @@ -355,9 +350,4 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.FinishablePane } } - - @Override - public boolean isFinishPanel() { - return false; - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index c8bc86b17b..51aaab6313 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -29,6 +29,7 @@ import org.openide.WizardDescriptor; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfileMap; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.IngestProfileSelectionWizardPanel; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; /** * The iterator class for the "Add Image" wizard panel. This class is used to @@ -37,11 +38,11 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.IngestProfileSelection class AddImageWizardIterator implements WizardDescriptor.Iterator { private int index = 0; - private List> panels; + private List panels; private AddImageAction action; private int progressPanelIndex; - private int profileSelectionIndex; - + private final static String PROP_LASTPROFILE_NAME = "AIW_LASTPROFILE_NAME"; //NON-NLS + AddImageWizardIterator(AddImageAction action) { this.action = action; } @@ -50,25 +51,23 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator> getPanels() { + private List getPanels() { if (panels == null) { - panels = new ArrayList>(); + panels = new ArrayList<>(); AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(); AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel); AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel); - IngestProfileSelectionWizardPanel profileSelectionPanel = new IngestProfileSelectionWizardPanel(AddImageWizardIngestConfigPanel.class.getCanonicalName()); + IngestProfileSelectionWizardPanel profileSelectionPanel = new IngestProfileSelectionWizardPanel(AddImageWizardIngestConfigPanel.class.getCanonicalName(), getPropLastprofileName()); panels.add(dsPanel); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); if (!profileMap.isEmpty()) { panels.add(profileSelectionPanel); } - panels.add(ingestConfigPanel); panels.add(progressPanel); - progressPanelIndex = panels.indexOf(progressPanel); //Doing programatically incase more panels added - profileSelectionIndex = panels.indexOf(profileSelectionPanel); //will be -1 if it wasn't added + progressPanelIndex = panels.indexOf(progressPanel); //Doing programatically because number of panels is variable String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); @@ -101,14 +100,32 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator current() { + public ShortcutWizardDescriptorPanel current() { if (panels != null) { return panels.get(index); } else { @@ -157,14 +174,12 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator { +class IngestModulesConfigWizardPanel extends ShortcutWizardDescriptorPanel { /** * The visual ingestJobSettingsPanel that displays this panel. If you need @@ -76,9 +76,4 @@ class IngestModulesConfigWizardPanel implements WizardDescriptor.FinishablePanel wiz.putProperty("executionContext", RunIngestModulesAction.getDefaultContext()); //NON-NLS } - @Override - public boolean isFinishPanel() { - return true; - } - } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index edfe5e1513..67abe8d3f7 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -31,10 +31,11 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; * selection panel and is only created when profiles exist. * */ -public class IngestProfileSelectionWizardPanel implements WizardDescriptor.Panel { +public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorPanel { + + private final Set listeners = new HashSet<>(1); - private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS /** * The visual component that displays this panel. If you need to access the @@ -42,9 +43,11 @@ public class IngestProfileSelectionWizardPanel implements WizardDescriptor.Panel */ private IngestProfileSelectionPanel component; private String lastProfileUsed; + private final String lastProfilePropertyName; private final String defaultContext; - public IngestProfileSelectionWizardPanel(String defaultContext) { + public IngestProfileSelectionWizardPanel(String defaultContext, String lastProfilePropertyName) { + this.lastProfilePropertyName = lastProfilePropertyName; this.defaultContext = defaultContext; } @@ -54,7 +57,15 @@ public class IngestProfileSelectionWizardPanel implements WizardDescriptor.Panel String getDefaultContext() { return defaultContext; } - + + /** + * Gets the name of the file which stores the last profile used properties. + * + * @return the LAST_PROFILE_PROPERTIES_FILE + */ + public static String getLastProfilePropertiesFile() { + return LAST_PROFILE_PROPERTIES_FILE; + } // Get the visual component for the panel. In this template, the component // is kept separate. This can be more efficient: if the wizard is created // but never displayed, or not all panels are displayed, it is better to @@ -62,9 +73,9 @@ public class IngestProfileSelectionWizardPanel implements WizardDescriptor.Panel @Override public IngestProfileSelectionPanel getComponent() { if (component == null) { - if (!(ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME) == null) - && !ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME).isEmpty()) { - lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); + if (!(ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName) == null) + && !ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName).isEmpty()) { + lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName); } else { lastProfileUsed = getDefaultContext(); } @@ -121,12 +132,16 @@ public class IngestProfileSelectionWizardPanel implements WizardDescriptor.Panel public void storeSettings(WizardDescriptor wiz) { lastProfileUsed = component.getLastSelectedProfile(); wiz.putProperty("executionContext", lastProfileUsed); //NON-NLS - ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME, lastProfileUsed); - System.out.println("STORED LAST PROFILE USED AS: " + lastProfileUsed); + ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName, lastProfileUsed); } - public boolean isFinishPanel() { + @Override + public boolean skipNextPanel() { return component.isLastPanel; } - + + @Override + public boolean panelEnablesSkipping(){ + return true; + } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index c7bae2a5e0..092b616f73 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -35,9 +35,8 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap; final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator { private int index; - private int profilePanelIndex; - - private List> panels; + private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS + private List panels; /** * Gets the list of panels used by this wizard for iterating over. @@ -45,17 +44,16 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< * * @return panels - the list of of WizardDescriptor panels */ - private List> getPanels() { + private List getPanels() { if (panels == null) { panels = new ArrayList<>(); - IngestProfileSelectionWizardPanel profilePanel = new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext()); + IngestProfileSelectionWizardPanel profilePanel = new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext(), PROP_LASTPROFILE_NAME); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); if (!profileMap.isEmpty()) { panels.add(profilePanel); } panels.add(new IngestModulesConfigWizardPanel()); - profilePanelIndex=panels.indexOf(profilePanel); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { Component c = panels.get(i).getComponent(); @@ -75,7 +73,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< } @Override - public WizardDescriptor.Panel current() { + public ShortcutWizardDescriptorPanel current() { return getPanels().get(index); } @@ -88,7 +86,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< @Override public boolean hasNext() { return (index < getPanels().size() - 1 && - !(index == profilePanelIndex && ((IngestProfileSelectionWizardPanel)current()).isFinishPanel())); + !(current().panelEnablesSkipping() && current().skipNextPanel())); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java new file mode 100644 index 0000000000..35c9cf7705 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java @@ -0,0 +1,64 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest.runIngestModuleWizard; + +import org.openide.WizardDescriptor; + +/** + * An abstract class providing a methods which can be checked by + * the iterator containing panels of this type. So that Wizards containing these + * panels can skip panels, but still call necessary methods of those panels. + */ +public abstract class ShortcutWizardDescriptorPanel implements WizardDescriptor.Panel { + + /** + * Whether or not this panel under the correct conditions can enable the skipping of the panel after it. + * @return true or false + */ + public boolean panelEnablesSkipping(){ + /* + * This method should be overriden by any panel that might want to + * enable the iterator to skip the panel that comes after it. + */ + return false; + } + + /** + * Whether or not the panel immediately following this one should be skipped . + * + * @return true or false + */ + public boolean skipNextPanel(){ + /* + * This method should be overriden by any panel that might want to + * enable the iterator to skip the panel that comes after it. + */ + return false; + } + + /** + * Provides a method which will allow code to be executed in a panel you plan to skip + */ + public void processThisPanelBeforeSkipped(){ + /* + * If you need to perform some actions of this panel before it is skipped + * override this method to have it call the necessary code. + */ + } +} From 95450f14785cd2486921c69d94e0f760f4019dc0 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 11:56:25 -0500 Subject: [PATCH 41/73] 2197 fixed when edit and delete buttons are enabled --- .../autopsy/ingest/IngestOptionsPanel.java | 1 + .../autopsy/ingest/ProfileSettingsPanel.java | 52 +++++++++++-------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 7d6964022d..056854becb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -67,6 +67,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 2); addIngestJobEventsListener(); + enableTabs(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 6a8d5b2cc5..c521f00ae6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -262,9 +262,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op }//GEN-LAST:event_deleteProfileButtonActionPerformed /** - * Enable / disable buttons, so they can be disabled while ingest is running. - * - * @param isEnabled + * Enable / disable buttons, so they can be disabled while ingest is + * running. + * + * @param isEnabled */ void enableButtons(boolean isEnabled) { newProfileButton.setEnabled(isEnabled); @@ -286,7 +287,26 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op this.filterNameText.setText(""); this.selectedModulesArea.setText(""); } + refreshEditDeleteButtons(); } + + /** + * When Ingest is not running this will changed enabled status of the edit + * and delete buttons to reflect their current availability. + */ + private void refreshEditDeleteButtons() { + if (newProfileButton.isEnabled()) { + if (profilesListModel.isEmpty()) { + editProfileButton.setEnabled(false); + deleteProfileButton.setEnabled(false); + } else { + editProfileButton.setEnabled(true); + deleteProfileButton.setEnabled(true); + } + } + } + + private void editProfileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editProfileButtonActionPerformed IngestProfile selectedProfile = profileList.getSelectedValue(); doProfileDialog(selectedProfile); @@ -294,9 +314,9 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op }//GEN-LAST:event_editProfileButtonActionPerformed /** - * Open a dialog for the the creation or modification of a profile. - * - * @param selectedProfile + * Open a dialog for the the creation or modification of a profile. + * + * @param selectedProfile */ private void doProfileDialog(IngestProfile selectedProfile) { // Create a files set defintion panle. @@ -315,14 +335,13 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); - + if (profileMap.containsKey(panel.getProfileName()) && selectedProfile == null) { MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text", panel.getProfileName())); return; } - if (option == JOptionPane.OK_OPTION) { panel.saveSettings(); load(); @@ -341,7 +360,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op } /** - * Load the stored profile information. + * Load the stored profile information. */ @Override public void load() { @@ -351,15 +370,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op for (IngestProfile profile : profileMap.getIngestProfileMap().values()) { profilesListModel.addElement(profile); } - if (newProfileButton.isEnabled()) { - if (profilesListModel.isEmpty()) { - editProfileButton.setEnabled(false); - deleteProfileButton.setEnabled(false); - } else { - editProfileButton.setEnabled(true); - deleteProfileButton.setEnabled(true); - } + if (currentIndex < 0 || currentIndex >= profilesListModel.getSize()) { + currentIndex = 0; } + refreshEditDeleteButtons(); profileList.setSelectedIndex(currentIndex); } @@ -370,7 +384,6 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op if (e.getValueIsAdjusting()) { return; } - // Get the selected interesting files set and populate the set // components. IngestProfile selectedProfile = ProfileSettingsPanel.this.profileList.getSelectedValue(); @@ -390,11 +403,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op for (String moduleName : selectedProfile.getModuleNames(IngestProfile.getEnabledModulesKey())) { selectedModulesArea.append(moduleName + "\n"); } - } - } - } // Variables declaration - do not modify//GEN-BEGIN:variables From 5fc2d75476e56939c59346488314640c3a518c73 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 12:17:26 -0500 Subject: [PATCH 42/73] 2197 fixed some access levels on new ProfilePanel --- .../sleuthkit/autopsy/ingest/ProfilePanel.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 9831b4b0db..a56aa07aed 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -27,22 +27,22 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; /** * Panel to display options for profile creation. */ -public class ProfilePanel extends IngestModuleGlobalSettingsPanel { +class ProfilePanel extends IngestModuleGlobalSettingsPanel { @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", "ProfilePanel.profileNameLabel.text=Profile Name:", "ProfilePanel.newProfileText=NewEmptyProfile", "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named."}) - IngestJobSettingsPanel ingestSettingsPanel; - IngestJobSettings tempSettings; - IngestProfile profile; - final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); + private final IngestJobSettingsPanel ingestSettingsPanel; + private final IngestJobSettings tempSettings; + private IngestProfile profile; + private final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); /** * Creates new form ProfilePanel */ - public ProfilePanel() { + ProfilePanel() { initComponents(); tempSettings = new IngestJobSettings(NEW_PROFILE_NAME); ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); @@ -51,7 +51,7 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { } - public ProfilePanel(IngestProfile selectedProfile) { + ProfilePanel(IngestProfile selectedProfile) { initComponents(); profile = selectedProfile; profileDescArea.setText(profile.getDescription()); @@ -169,11 +169,11 @@ public class ProfilePanel extends IngestModuleGlobalSettingsPanel { /** * Save a new or edited profile. */ - public void store() { + void store() { saveSettings(); } - public void load() { + void load() { } /** From 6246f5e9cd4430e5ae3a95130949ed258feae11f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 16:02:25 -0500 Subject: [PATCH 43/73] 2197 can no longer create profiles with out of date filters --- .../autopsy/ingest/IngestOptionsPanel.java | 22 ++++++++++ .../autopsy/ingest/IngestProfileMap.java | 12 +++-- .../autopsy/ingest/ProfilePanel.java | 22 +++++++--- .../autopsy/ingest/ProfileSettingsPanel.java | 44 +++++++++++++------ 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 056854becb..0ddb4e0df6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -21,6 +21,9 @@ package org.sleuthkit.autopsy.ingest; import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel; @@ -66,6 +69,21 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 1); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 2); + //Listener for when tabbed panes are switched, because we can have two file filter definitions panels open at the same time + //we may wind up in a situation where the user has created and saved one in the profiles panel + //so we need to refresh the filterPanel in those cases before proceeding. + tabbedPane.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (e.getSource() instanceof JTabbedPane) { + profilePanel.shouldFiltersBeRefreshed(); + { + filterPanel.load(); + } + } + } + }); + addIngestJobEventsListener(); enableTabs(); } @@ -135,6 +153,10 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti */ @Override public void saveSettings() { + //if a new filter was created in the profilePanel we don't want to save over it accidently + if (profilePanel.shouldFiltersBeRefreshed()) { + filterPanel.load(); + } filterPanel.store(); settingsPanel.store(); profilePanel.store(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java index f1bbed0a3e..851b30cb1b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java @@ -22,7 +22,6 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Collections; import java.util.HashSet; import java.util.TreeMap; import org.apache.commons.io.FileUtils; @@ -109,10 +108,17 @@ class IngestProfileMap { return IngestJobSettings.getEnabledModulesKey(); } - IngestProfile(String name, String desc, String selected) { + /** + * Creates a new IngestProfile + * + * @param name - unique name of the profile + * @param desc - optional description of profile + * @param selectedFilter - the File Ingest Filter used for this profile + */ + IngestProfile(String name, String desc, String selectedFilter) { this.name = name; this.description = desc; - this.fileIngestFilter = selected; + this.fileIngestFilter = selectedFilter; } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index a56aa07aed..477ef6a974 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -25,7 +25,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; /** - * Panel to display options for profile creation. + * Panel to display options for profile creation and editing. */ class ProfilePanel extends IngestModuleGlobalSettingsPanel { @@ -35,7 +35,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named."}) private final IngestJobSettingsPanel ingestSettingsPanel; - private final IngestJobSettings tempSettings; + private final IngestJobSettings settings; private IngestProfile profile; private final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); @@ -44,8 +44,8 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { */ ProfilePanel() { initComponents(); - tempSettings = new IngestJobSettings(NEW_PROFILE_NAME); - ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); + settings = new IngestJobSettings(NEW_PROFILE_NAME); + ingestSettingsPanel = new IngestJobSettingsPanel(settings); ingestSettingsPanel.setPastJobsButtonVisible(false); jPanel1.add(ingestSettingsPanel, 0); @@ -56,8 +56,8 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { profile = selectedProfile; profileDescArea.setText(profile.getDescription()); profileNameField.setText(profile.getName()); - tempSettings = new IngestJobSettings(selectedProfile.getName()); - ingestSettingsPanel = new IngestJobSettingsPanel(tempSettings); + settings = new IngestJobSettings(selectedProfile.getName()); + ingestSettingsPanel = new IngestJobSettingsPanel(settings); ingestSettingsPanel.setPastJobsButtonVisible(false); jPanel1.add(ingestSettingsPanel, 0); } @@ -65,6 +65,14 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { String getProfileName(){ return profileNameField.getText(); } + + String getProfileDesc(){ + return profileDescArea.getText(); + } + + IngestJobSettings getSettings(){ + return ingestSettingsPanel.getSettings(); + } /** * 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 @@ -157,7 +165,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { @Override public void saveSettings() { if (profile == null) { - IngestProfile.renameProfile(tempSettings.getExecutionContext(), profileNameField.getText()); + IngestProfile.renameProfile(settings.getExecutionContext(), profileNameField.getText()); } else if (!profile.getName().equals(profileNameField.getText())) { IngestProfile.renameProfile(profile.getName(), profileNameField.getText()); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index c521f00ae6..137b398567 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -48,12 +48,15 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op }) private final DefaultListModel profilesListModel = new DefaultListModel<>(); - + private TreeMap profiles; + private ProfilePanel panel; + private boolean filtersShouldBeRefreshed; /** * Creates new form ProfileOptionsPanel */ ProfileSettingsPanel() { initComponents(); + this.filtersShouldBeRefreshed = false; this.profileList.setModel(profilesListModel); this.profileList.addListSelectionListener(new ProfileSettingsPanel.ProfileListSelectionListener()); ingestWarningLabel.setVisible(false); @@ -261,6 +264,20 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteProfileButtonActionPerformed + /** + * Returns whether there were possible changes to the filter list since the last time + * this was called. + * + * Resets value to false after being called. + * + * @return true or false + */ + boolean shouldFiltersBeRefreshed(){ + boolean shouldRefresh = filtersShouldBeRefreshed; + filtersShouldBeRefreshed = false; + return shouldRefresh; + } + /** * Enable / disable buttons, so they can be disabled while ingest is * running. @@ -319,8 +336,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op * @param selectedProfile */ private void doProfileDialog(IngestProfile selectedProfile) { - // Create a files set defintion panle. - ProfilePanel panel; + // Create a files set defintion panel. if (selectedProfile != null) { // Editing an existing set definition. panel = new ProfilePanel(selectedProfile); @@ -334,16 +350,16 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op option = JOptionPane.showConfirmDialog(null, panel, Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); - TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); - - if (profileMap.containsKey(panel.getProfileName()) && selectedProfile == null) { + // While adding new profile(selectedPRofile == null), if a profile with same name already exists, do not add to the profiles hashMap. + // In case of editing an existing profile(selectedProfile != null), following check is not performed. + if (this.profiles.containsKey(panel.getProfileName()) && selectedProfile == null) { MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text", panel.getProfileName())); return; } if (option == JOptionPane.OK_OPTION) { - panel.saveSettings(); + this.saveSettings(); load(); } @@ -351,12 +367,12 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op @Override public void saveSettings() { - + this.store(); } @Override public void store() { - + panel.saveSettings(); } /** @@ -364,17 +380,17 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op */ @Override public void load() { - int currentIndex = profileList.getSelectedIndex(); - profilesListModel.clear(); - IngestProfileMap profileMap = new IngestProfileMap(); - for (IngestProfile profile : profileMap.getIngestProfileMap().values()) { + int currentIndex = this.profileList.getSelectedIndex(); + this.profilesListModel.clear(); + this.profiles = new IngestProfileMap().getIngestProfileMap(); + for (IngestProfile profile : this.profiles.values()) { profilesListModel.addElement(profile); } if (currentIndex < 0 || currentIndex >= profilesListModel.getSize()) { currentIndex = 0; } refreshEditDeleteButtons(); - profileList.setSelectedIndex(currentIndex); + this.profileList.setSelectedIndex(currentIndex); } private final class ProfileListSelectionListener implements ListSelectionListener { From 705876079770e270394ecb19724c959f1a631bbf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Tue, 7 Feb 2017 16:37:26 -0500 Subject: [PATCH 44/73] 2102: add/update license header of source file --- .../autopsy/testing/AutopsyTestCases.java | 19 ++++++++++++++++--- .../autopsy/testing/RegressionTest.java | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java index 6368a5d8d9..d5d17136a6 100755 --- a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.testing; diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index 3cebb1cc93..112984b33b 100755 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From c636d06d691af60c08c42fd8ee309a37ab60139d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 17:02:58 -0500 Subject: [PATCH 45/73] 2197 Can no longer delete filters before the profiles that use them --- .../autopsy/ingest/IngestProfileMap.java | 8 ++++---- .../autopsy/ingest/IngestSettingsPanel.form | 6 ------ .../autopsy/ingest/IngestSettingsPanel.java | 4 ---- .../autopsy/ingest/ProfileSettingsPanel.java | 4 +++- .../interestingitems/FilesSetDefsPanel.java | 20 ++++++++++++++++--- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java index 851b30cb1b..82dcedb1ff 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java @@ -29,7 +29,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -class IngestProfileMap { +public class IngestProfileMap { private static final String PROFILE_FOLDER = "IngestProfiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; @@ -43,7 +43,7 @@ class IngestProfileMap { * * @return profileList */ - TreeMap getIngestProfileMap() { + public TreeMap getIngestProfileMap() { if (profileMap == null) { loadProfileList(); } @@ -93,7 +93,7 @@ class IngestProfileMap { * FileIngestFilter. The name can be used to find the ModuleSettings for * this profile. */ - static class IngestProfile { + public static class IngestProfile { private final String name; private final String description; @@ -154,7 +154,7 @@ class IngestProfileMap { * * @return the fileIngestFilter */ - String getFileIngestFilter() { + public String getFileIngestFilter() { return fileIngestFilter; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form index 4996fc373f..c6edecaca9 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form @@ -1,12 +1,6 @@
- - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java index 4a6c77d896..918b93108b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -133,8 +133,6 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { // //GEN-BEGIN:initComponents private void initComponents() { - buttonGroup1 = new javax.swing.ButtonGroup(); - buttonGroup3 = new javax.swing.ButtonGroup(); jScrollPane1 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); jLabelNumThreads = new javax.swing.JLabel(); @@ -262,8 +260,6 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { }//GEN-LAST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.ButtonGroup buttonGroup1; - private javax.swing.ButtonGroup buttonGroup3; private javax.swing.JLabel ingestWarningLabel; private javax.swing.JCheckBox jCheckBoxEnableProcTimeout; private javax.swing.JFormattedTextField jFormattedTextFieldProcTimeOutHrs; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 137b398567..2f02791fb3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -44,10 +44,11 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op "ProfileSettingsPanel.editProfileButton.text=Edit Profile", "ProfileSettingsPanel.deleteProfileButton.text=Delete Profile", "ProfileSettingsPanel.messages.filterLoadFailed=Failed to load file ingest filter", + "# {0} - profile name", "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text=Profile with name {0} already exists." }) - private final DefaultListModel profilesListModel = new DefaultListModel<>(); + private final DefaultListModel profilesListModel; private TreeMap profiles; private ProfilePanel panel; private boolean filtersShouldBeRefreshed; @@ -55,6 +56,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op * Creates new form ProfileOptionsPanel */ ProfileSettingsPanel() { + this.profilesListModel = new DefaultListModel<>(); initComponents(); this.filtersShouldBeRefreshed = false; this.profileList.setModel(profilesListModel); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 2b378cb4f7..f2f707456e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -38,6 +38,8 @@ import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; +import org.sleuthkit.autopsy.ingest.IngestProfileMap; +import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; /** @@ -45,7 +47,9 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; */ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { - @NbBundle.Messages({ + @NbBundle.Messages({"# {0} - filter name", + "# {1} - profile name", + "FilesSetDefsPanel.ingest.fileFilterInUseError=The selected file filter, {0}, is being used by a profile, {1}, and cannot be deleted until after the profile.", "FilesSetDefsPanel.bytes=Bytes", "FilesSetDefsPanel.kiloBytes=Kilobytes", "FilesSetDefsPanel.megaBytes=Megabytes", @@ -87,7 +91,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp this.setsList.addListSelectionListener(new FilesSetDefsPanel.SetsListSelectionListener()); this.rulesList.setModel(rulesListModel); this.rulesList.addListSelectionListener(new FilesSetDefsPanel.RulesListSelectionListener()); - this.ingestWarningLabel.setVisible(false); + this.ingestWarningLabel.setVisible(false); if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { //Hide the mimetype settings when this is displaying FileSet rules instead of interesting item rules this.mimeTypeComboBox.setVisible(false); this.jLabel7.setVisible(false); @@ -998,9 +1002,19 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private void deleteSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteSetButtonActionPerformed FilesSet selectedSet = this.setsList.getSelectedValue(); + if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { + for (IngestProfile profile : new IngestProfileMap().getIngestProfileMap().values()) { + if (profile.getFileIngestFilter().equals(selectedSet.getName())) { + MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), + "FilesSetDefsPanel.ingest.fileFilterInUseError", + selectedSet.getName(), profile.toString())); + return; + } + } + + } this.filesSets.remove(selectedSet.getName()); this.setsListModel.removeElement(selectedSet); - // Select the first of the remaining set definitions. This will cause // the selection listeners to repopulate the subordinate components. if (!this.filesSets.isEmpty()) { From 5c2706cd179b8a31764b5ad2f8548060d60771d2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 17:39:28 -0500 Subject: [PATCH 46/73] 2197 - profile no longer has issues when there is a trailing space in name --- .../autopsy/ingest/ProfilePanel.java | 67 +++++++++++++++---- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 477ef6a974..84cb63bfff 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -19,6 +19,10 @@ package org.sleuthkit.autopsy.ingest; import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; @@ -32,12 +36,14 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Profile Description:", "ProfilePanel.profileNameLabel.text=Profile Name:", "ProfilePanel.newProfileText=NewEmptyProfile", - "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named."}) + "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.", + "ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character"}) private final IngestJobSettingsPanel ingestSettingsPanel; private final IngestJobSettings settings; private IngestProfile profile; private final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); + private static final List ILLEGAL_NAME_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", "/", ":", "*", "?", "\"", "<", ">"))); /** * Creates new form ProfilePanel @@ -62,17 +68,25 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { jPanel1.add(ingestSettingsPanel, 0); } - String getProfileName(){ - return profileNameField.getText(); + /** + * Get the name of the profile. + * + * The name will not contain any trailing or leading spaces. + * + * @return + */ + String getProfileName() { + return profileNameField.getText().trim(); } - - String getProfileDesc(){ + + String getProfileDesc() { return profileDescArea.getText(); } - - IngestJobSettings getSettings(){ + + IngestJobSettings getSettings() { return ingestSettingsPanel.getSettings(); } + /** * 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 @@ -165,13 +179,13 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { @Override public void saveSettings() { if (profile == null) { - IngestProfile.renameProfile(settings.getExecutionContext(), profileNameField.getText()); - } else if (!profile.getName().equals(profileNameField.getText())) { - IngestProfile.renameProfile(profile.getName(), profileNameField.getText()); + IngestProfile.renameProfile(settings.getExecutionContext(), getProfileName()); + } else if (!profile.getName().equals(getProfileName())) { + IngestProfile.renameProfile(profile.getName(), getProfileName()); } - profile = new IngestProfile(profileNameField.getText(), profileDescArea.getText(), ingestSettingsPanel.getSettings().getFileIngestFilter().getName()); + profile = new IngestProfile(getProfileName(), profileDescArea.getText(), ingestSettingsPanel.getSettings().getFileIngestFilter().getName()); IngestProfile.saveProfile(profile); - ingestSettingsPanel.getSettings().saveAs(profileNameField.getText()); + ingestSettingsPanel.getSettings().saveAs(getProfileName()); } /** @@ -186,17 +200,42 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { /** * Checks that information entered constitutes a valid ingest profile. + * * @return true for valid, false for invalid. */ boolean isValidDefinition() { - if (this.profileNameField.getText().isEmpty()) { + if (getProfileName().isEmpty()) { NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profilesMustBeNamed"), NotifyDescriptor.WARNING_MESSAGE); DialogDisplayer.getDefault().notify(notifyDesc); return false; } - + if (!containsOnlyLegalChars(getProfileName(), ILLEGAL_NAME_CHARS)){ + NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( + NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profileNameContainsIllegalCharacter"), + NotifyDescriptor.WARNING_MESSAGE); + DialogDisplayer.getDefault().notify(notifyDesc); + return false; + } + return true; + } + + /** + * Checks an input string for the use of illegal characters. + * + * @param toBeChecked The input string. + * @param illegalChars The characters deemed to be illegal. + * + * @return True if the string does not contain illegal characters, false + * otherwise. + */ + private static boolean containsOnlyLegalChars(String toBeChecked, List illegalChars) { + for (String illegalChar : illegalChars) { + if (toBeChecked.contains(illegalChar)) { + return false; + } + } return true; } } From 4701057c5707aae4b9348a188ce6a6e44c44dba9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 17:53:30 -0500 Subject: [PATCH 47/73] 2197-Fixed bug with making a profile with same name as one just deleted --- Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 2f02791fb3..f3e04e5058 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -258,6 +258,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private void deleteProfileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteProfileButtonActionPerformed IngestProfile selectedProfile = this.profileList.getSelectedValue(); this.profilesListModel.removeElement(selectedProfile); + profiles.remove(selectedProfile.getName()); IngestProfile.deleteProfile(selectedProfile); // Select the first of the remaining set definitions. This will cause From 8bde21f108f0ecda71f095f3de8094f1f21884c9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Feb 2017 18:44:09 -0500 Subject: [PATCH 48/73] 2198 fixed issue with Ingest Settings Panel when ok was chosen with nothing to save --- .../autopsy/ingest/IngestSettingsPanel.form | 16 +++++++-- .../autopsy/ingest/IngestSettingsPanel.java | 34 ++++++++++-------- .../autopsy/ingest/ProfileSettingsPanel.java | 35 +++++++++---------- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form index c6edecaca9..8434d1f38d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.form @@ -1,6 +1,11 @@ + + + + + @@ -16,7 +21,7 @@ - + @@ -36,6 +41,11 @@ + + + + + @@ -67,7 +77,7 @@ - + @@ -99,7 +109,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java index 918b93108b..2605ec0b0f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestSettingsPanel.java @@ -30,7 +30,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; /** * Options panel that allow users to set application preferences. */ -final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { +final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { IngestSettingsPanel() { initComponents(); @@ -108,23 +108,23 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { UserPreferences.setProcessTimeOutHrs((int) timeOutHrs); } } - + boolean valid() { return true; } /** * Enable or Disable buttons based on whether Ingest is running. - * - * @param isEnabled + * + * @param isEnabled */ - void enableButtons(boolean isEnabled){ + void enableButtons(boolean isEnabled) { numberOfFileIngestThreadsComboBox.setEnabled(isEnabled); jFormattedTextFieldProcTimeOutHrs.setEnabled(isEnabled); jCheckBoxEnableProcTimeout.setEnabled(isEnabled); - ingestWarningLabel.setVisible(!isEnabled); + ingestWarningLabel.setVisible(!isEnabled); } - + /** * 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 @@ -144,8 +144,12 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { jLabelProcessTimeOutUnits = new javax.swing.JLabel(); ingestWarningLabel = new javax.swing.JLabel(); + setPreferredSize(new java.awt.Dimension(693, 413)); + jScrollPane1.setBorder(null); + jPanel1.setPreferredSize(new java.awt.Dimension(664, 400)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelNumThreads, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.jLabelNumThreads.text")); // NOI18N numberOfFileIngestThreadsComboBox.addActionListener(new java.awt.event.ActionListener() { @@ -205,7 +209,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabelProcessTimeOutUnits))) .addGap(213, 213, 213))) - .addGap(215, 215, 215)) + .addContainerGap(52, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(ingestWarningLabel) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) @@ -229,7 +233,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { .addComponent(jLabelProcessTimeOutUnits))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(ingestWarningLabel) - .addContainerGap(277, Short.MAX_VALUE)) + .addContainerGap(257, Short.MAX_VALUE)) ); jScrollPane1.setViewportView(jPanel1); @@ -238,7 +242,7 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 691, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -246,18 +250,18 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { ); }// //GEN-END:initComponents - private void numberOfFileIngestThreadsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numberOfFileIngestThreadsComboBoxActionPerformed + private void jFormattedTextFieldProcTimeOutHrsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_numberOfFileIngestThreadsComboBoxActionPerformed + }//GEN-LAST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed private void jCheckBoxEnableProcTimeoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxEnableProcTimeoutActionPerformed jFormattedTextFieldProcTimeOutHrs.setEditable(jCheckBoxEnableProcTimeout.isSelected()); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_jCheckBoxEnableProcTimeoutActionPerformed - private void jFormattedTextFieldProcTimeOutHrsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed + private void numberOfFileIngestThreadsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numberOfFileIngestThreadsComboBoxActionPerformed firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed + }//GEN-LAST:event_numberOfFileIngestThreadsComboBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel ingestWarningLabel; @@ -274,6 +278,6 @@ final class IngestSettingsPanel extends IngestModuleGlobalSettingsPanel { @Override public void saveSettings() { - this.store(); + this.store(); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index ec6e4e6777..65128ca43c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -52,6 +52,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private TreeMap profiles; private ProfilePanel panel; private boolean filtersShouldBeRefreshed; + /** * Creates new form ProfileOptionsPanel */ @@ -273,19 +274,19 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op }//GEN-LAST:event_deleteProfileButtonActionPerformed /** - * Returns whether there were possible changes to the filter list since the last time - * this was called. - * - * Resets value to false after being called. - * + * Returns whether there were possible changes to the filter list since the + * last time this was called. + * + * Resets value to false after being called. + * * @return true or false */ - boolean shouldFiltersBeRefreshed(){ + boolean shouldFiltersBeRefreshed() { boolean shouldRefresh = filtersShouldBeRefreshed; filtersShouldBeRefreshed = false; return shouldRefresh; } - + /** * Enable / disable buttons, so they can be disabled while ingest is * running. @@ -358,16 +359,16 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op option = JOptionPane.showConfirmDialog(null, panel, Bundle.ProfileSettingsPanel_title(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); - // While adding new profile(selectedPRofile == null), if a profile with same name already exists, do not add to the profiles hashMap. - // In case of editing an existing profile(selectedProfile != null), following check is not performed. - if (this.profiles.containsKey(panel.getProfileName()) && selectedProfile == null) { - MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), - "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text", - panel.getProfileName())); - return; - } if (option == JOptionPane.OK_OPTION) { - this.saveSettings(); + // While adding new profile(selectedPRofile == null), if a profile with same name already exists, do not add to the profiles hashMap. + // In case of editing an existing profile(selectedProfile != null), following check is not performed. + if (this.profiles.containsKey(panel.getProfileName()) && selectedProfile == null) { + MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), + "ProfileSettingsPanel.doFileSetsDialog.duplicateProfile.text", + panel.getProfileName())); + return; + } + panel.saveSettings(); load(); } @@ -375,12 +376,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op @Override public void saveSettings() { - this.store(); } @Override public void store() { - panel.saveSettings(); } /** From bfa75149da0c19d85b87bdd1af73447206d81af4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 8 Feb 2017 10:58:13 -0500 Subject: [PATCH 49/73] 2198 default run ingest modules context renamed for backwards compatability --- .../ingest/runIngestModuleWizard/RunIngestModulesAction.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index d325e649e7..9834a26134 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -41,8 +41,9 @@ import org.sleuthkit.datamodel.Directory; public final class RunIngestModulesAction extends AbstractAction { @Messages("RunIngestModulesAction.name=Run Ingest Modules") - - private static final String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.runIngestModuleAction"; + + //'dialog' context name required so existing settings do not need to be reconfigured + private static final String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; /** * Returns the name of the default context which will be used when profiles are not available. From 74fea7bccea28781b66e48a343941ff533df3f01 Mon Sep 17 00:00:00 2001 From: Dmitry Charit Date: Thu, 9 Feb 2017 18:43:05 +0000 Subject: [PATCH 50/73] corrected the update --- docs/doxygen-user/images/javaproperties.PNG | Bin 13713 -> 8978 bytes docs/doxygen-user/images/solrinstall3.PNG | Bin 37961 -> 33389 bytes .../images/updatedServiceInstall.PNG | Bin 27877 -> 10907 bytes docs/doxygen-user/images/updatedSolr_cmd.PNG | Bin 0 -> 9115 bytes docs/doxygen-user/images/wherejava.PNG | Bin 4122 -> 1017 bytes docs/doxygen-user/images/zooDir.PNG | Bin 0 -> 25815 bytes docs/doxygen-user/images/zooPurge.PNG | Bin 0 -> 6919 bytes docs/doxygen-user/installSolr.dox | 166 +++++++++++------- 8 files changed, 101 insertions(+), 65 deletions(-) create mode 100644 docs/doxygen-user/images/updatedSolr_cmd.PNG create mode 100644 docs/doxygen-user/images/zooDir.PNG create mode 100644 docs/doxygen-user/images/zooPurge.PNG diff --git a/docs/doxygen-user/images/javaproperties.PNG b/docs/doxygen-user/images/javaproperties.PNG index 317092fa1869087ed5ce92154f1ec1b52715f302..360440d5c9bd2eede895497c1946b8079fe5a4db 100644 GIT binary patch literal 8978 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 diff --git a/docs/doxygen-user/images/solrinstall3.PNG b/docs/doxygen-user/images/solrinstall3.PNG index 542cfad3d5de000bad3f33de3242738c06d9ae5a..9692f503df7b3e054342007d1a49a39fc3b8ee1f 100644 GIT binary patch literal 33389 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

t zo%KYQrI?1}>nr2vUr7?7n}LT0I+$p`j)Vlt94-h!iOd!z2-gGZ>R?e1OTCC60*jua zdDZ+jAMxFBjioSO1D` zwj)Y}m!F5Er2%H31H3G?9xIIHb9Vif;E>rjve%a{X|+M|24G%Sxk*BAH!IM}@z_7o z5dtZloyKWK9MC{Mi0-gC9ow|{$8d3BsOBP~FvGdf zew%rXaYZl|h^jKO>_d23=a#mv&umyX^$w3wap^Q#7^6}TPr$0cqqB zzm0ePOd#IaMw(tmK445RwTX73@N-NFV$v%0)(!s+S4db#;+WJ>B&&alx?&i-7=1d8 zP-EicCZoY8f^B|2jKtm)xC2g@#$7)Xdd1h~=Wc<^`dAx&Mc!c<%>zSer(Q9SF8Un> zuEH(Rsu-C21kI|YtaUV1jrP~X->mzc2A5?|0FZ57qvHM_>fUE&Kzpf>CAeJ1W>?p< zK6m@I*g&ln8p~r)ISpgqi%L5MSf0yh8UCy;1)TQ@;9T=gGh-hAG(T0@<*5y6$>=KL zfr=viGdl8+)a*venwj4@=8;DC2G0Fr6<8tZ*P5nrkk<&u*W2T;?TaY*N8MYr?k^qZ zBSC7@(7iua@(vM+Jr+^+LV)f-IWB3UL)8~mIfoXoUti3ypStb0u~}UdoN+=4!if!a zIrKv-Z>C0?o zC}>aGdeUaH*}pZxEgLd{MAL9D6${wMfyE_>X<{@fid>-0sWJb>=8N zd%2WNc5F@K*EXtI1a!QJOF4i&*6t^x|06-4$O3Y_8j6y zrt^oyf?q71YWx()Q{j}*!h3fEOy65o85Q>?7G2wc?XnkC&T{<#^9su-#aYG)eSbS~ zYoN05sKCj|nf`uchR|sx*VwZZFWPkdYFy}I@_qxd=)Ymam9L3Nu{B4|qdIjOCuk}?#bY@i=bZ;nSC=TpZnnio43 zHcPkX>O=@#+o!{_T;s7N&s{Kgf8eS*!;fa-vX8YIeB(3(haGr>E;>fsbAc*;L-hMi z>n+!73P!XRN$O_iN(|aKlWsf5Xmr)xZoHls<92L0Q5jaA7;umIM#ZWL+@x4bZ?qej z+pK<4aHMnTb<^e0-XpI6(>$nb#z(;7Ia*|wF%tJ*8(XKg@7EK6SdWfOx^6ha=XdT-{;)~FuNv{mANVAkMaNc@zUQDP8SBMJ z!@p^dgg^iUvI7q$sGbe-#;CY@#*2xe!QBD^Wvk;byt4Q;qjrSJ8|`fHL1Ouf{qT=5 zsIfV5850`zx=VR05AlgOb@tDIg{qiy=v5*uoUzQxx;~{FbWxAe#%il2-j0tlJT%c? zot@Tn88Nx(aKj{noUnuICGTtP6aqcctn|iQWBOjXjgA}#tJ9OHgT1|~kO_qEHs)^*n=07Y%7n9uz ze}d`myLfP{FbLlYnYtW?fYZM(lxT7Air2%xq3?LE-Szds#w<~Z@gjPk5J^U(0Hs6f znEF(MIe;v~Iy-j|;DC}H^tl|94UmrDy7^8``{$|sucCvRrq>9KP9^$h!oqVxP_+#) zFORiIEcGXa0(_9$ck2|j9KY?5STMVoCGjm#cDVP|wqR{LxVt-y60o1*7#K_`tshs= z^B?Tc^0SdB)f@8G`4j^6mO4>cns zTbGs1?9uI@;s$q9bMg|q5uu9vrZhEx^~8k8qWEf7FP~seLW)s*%P@;nBQCNTvx_!Y zdSGN53PIgN%Y)X?gD7K>Bc$g~%RbqWu!FpQ-U&N|22YP2V7l@?F{`0OXZ>9W%53|V zplQ>7^99^Ml~a?Hl=n4Rw`1*yN%&Z2mCiNp@YuY6gax1(cPehknIx#%UgS3X>XzNy zuyDZ7MfbU!=5U$f4(}tGyo2xF_++JX@gRBhl@@CuCEc=sX0vUXnem#Gz{U-kCa9wG zl1~v|CBvPL4_E2{ko%4bneQUnhWz9Y>?Z@_78G+C6VJSkG*Y7axs;=2UxQB14f1+@ z5%tPL>_EEtJK948=x7sH@XA$4ca8+1{FnrKg@~I-iMnp=^s}=@k}KIx=}Zly&<=za ziMqdoVVnL`B`lCA(>e#KtGS5)*`a6`rnY+XbK74w1AKijk`XT0vxTTkM6jmn^wpi| zf9N6*U{Kb^dcay$;*p*!9T<37`PBc^08rMQN=fC_o&6pA_XXwFA^vT)xJ8x^yL8u8 zyB&c2w|`6lw~F##Is*0N&!eZfcl`+6%3!AmGt9eFk^7gy?!ep}qi^qS0f_r~=CPSN z1o1VtPnnAs^1K5~<{$5N=nHm$O;)kvqIo=A3{|*@`-vxoKa!Upw)2q$Sfzb3+>eiL zKgrgAvRnBp|6rB?a^Dt1-G^?H8w zV4Vj!;hga}J$7H5?nZsOV7Pj@4(FC`=Cd+x+eb2Orb1W%HUUyoxf%|wu6}7Y&bnMq z383r!Ue&fvP#<5Xc=@coU3ZXvo|K9KawDIO@9*PuIX8WERnC_8`&)nq`9PxTMnMZ8g;{8jJ)!SUSC8nnucn`-^TJw5*CtW ztdhjk##ffIMNaNBg%ytZ+ou)zU0R)0o#vdzzZ{akpJy88&J{zSSdbS0FnV(W2aChY z7OI;lX{Fc3weHn4H9|XmÐ7YVO#E=-+RX)u28-x4%_HZy-*SAR@_JSvDXf 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 A9RL6T literal 37961 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 ig1%S2IdOON`~M%R|20Q;uE5X$0000@q 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 literal 27877 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 literal 4122 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 diff --git a/docs/doxygen-user/images/zooDir.PNG b/docs/doxygen-user/images/zooDir.PNG new file mode 100644 index 0000000000000000000000000000000000000000..8240f3a7d3b77e7824c87017a9b1ab8ec5c58342 GIT binary patch literal 25815 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

&YQ#0m6QCIaISh~V4X9b&c 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 Y;?LGMiCxLapOHLMQP2ce$-NEvFU56f9smFU literal 0 HcmV?d00001 diff --git a/docs/doxygen-user/images/zooPurge.PNG b/docs/doxygen-user/images/zooPurge.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d8e8a8b3643f7097eca381e7f265bd0f1e38035c GIT binary patch literal 6919 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 s;{OZCzx2HS0`mU>Direct Download Link +- Download the Apache Solr 6.2.1 installation package from http://www.apache.org/dyn/closer.lua/lucene/solr/6.2.1-2 - Access to an installed version of Autopsy so that you can copy files from it. - A network-accessible machine to install Solr upon. Note that the Solr process will need to write data out to the main shared storage drive, and needs adequate permissions to write to this location, which may be across a network. \section install_solr_install Installation \subsection install_solr_install_java JRE Installation -Install the Java JRE if needed. You can test this by running _where java_ from the command line. If you see output like the yellow results below, you have a JRE. +1. Install the Java JRE if needed. You can test this by running _where java_ from the command line. If you see output like the yellow results below, you have a JRE.

-\image html wherejava.PNG +\image html symlinkjava.PNG

If you need the JRE, install it with the default settings. +2. Create a Windows environment variable for your JavaHome with the path to your 64-bit version of the JRE. If you do not know the path, the correct _JavaHome_ path can be obtained by running the command _where java_ from the Windows command line. An example is shown below. Do not include the "bin" folder in the path you place into the _JavaHome_ variable. A correct example of the final result will look something like this:    + JavaHome="C:\Program Files\Java\jre1.8.0_111" +

+ \image html wherejava.PNG +

+

+ Note that if you get something like the following when running the "where java" command, it is a symbolic link to the Java installation and you need to trace it to the proper folder as explained below. +

+ \image html symlinkjava.PNG +

+ To trace a symbolic link to the proper folder, use Windows Explorer to navigate to the path shown (C:\\ProgramData\\Oracle\\Java\\javapath for the example above), then right click on _java.exe_ and Click on _Properties_. You will see the path you should use in the _Location_ field, shown in the screenshot below. Do not include the "bin" folder in the path you place into the _JavaHome_ variable. +

+ \image html javaproperties.PNG +

\subsection install_solr_install_solr Solr Installation The following steps will configure Solr to run using an account that will have access to the network storage. -1. Run the Bitnami installer, bitnami-solr-4.10.3-0-windows-installer.exe +1. Run the Bitnami installer, "bitnami-solr-6.2.1-2-windows-installer.exe" 2. If Windows prompts with User Account Control, click _Yes_ -3. Follow the prompts through to completion. You do not need to "Learn more about Bitnami cloud hosting" so you can clear the check box. +3. Follow the prompts through to completion. You do not need to "Learn more about Bitnami cloud hosting" so you can clear the check box. 4. If you see an error dialog like the following, you may safely ignore it.

\image html apachebadmessage.PNG
-5. When the installation completes, clear the "Launch Bitnami Apache Solr Stack Now?" checkbox and click _Finish_. +5. When the installation completes, clear the "Launch Bitnami Apache Solr Stack Now?" checkbox and click _Finish_. \subsection install_solr_config Solr Configuration 1. Stop the _solrJetty_ service by pressing _Start_, typing _services.msc_, pressing _Enter_, and locating the _solrJetty_ Windows service. Select the service and press _Stop the service_. If the service is already stopped and there is no _Stop the service_ available, this is okay. -2. Edit the C:\\Bitnami\\solr-4.10.3-0\\apache-solr\\scripts\\serviceinstall.bat script. You need administrator permission to change this file. The easiest way around this is to save a copy on the Desktop, edit the Desktop version, and copy the new one back over the top of the old. Windows will ask for permission to overwrite the old file; allow it. You should make the following changes to this file: +2. Edit the "C:\Bitnami\solr-6.2.1-2\apache-solr\scripts\serviceinstall.bat" script. You need administrator permission to change this file. The easiest way around this is to save a copy on the Desktop, edit the Desktop version, and copy the new one back over the top of the old. Windows will ask for permission to overwrite the old file; allow it. You should make the following changes to this file:

- - Add the following options in the _JvmOptions_ section of the line that begins with "C:\Bitnami\solr-4.10.3-0/apache-solr\scripts\prunsrv.exe" : - + ++JvmOptions=-Dcollection.configName=AutopsyConfig - + ++JvmOptions=-Dbootstrap_confdir="C:\Bitnami\solr-4.10.3-0\apache-solr\solr\configsets\AutopsyConfig\conf" - - Replace the path to JavaHome with the path to your 64-bit version of the JRE. If you do not know the path, the correct _JavaHome_ path can be obtained by running the command "where java" from the Windows command line. An example is shown below. The text in yellow is what we are interested in. Do not include the "bin" folder in the path you place into the _JavaHome_ variable. A correct example of the final result will look something like this:   --JavaHome="C:\Program Files\Java\jre1.8.0_45" -

- \image html wherejava.PNG -

- Note that if you get something like the following when running the "where java" command, it is a symbolic link to the Java installation and you need to trace it to the proper folder as explained below. -

- \image html symlinkjava.PNG -

- To trace a symbolic link to the proper folder, use Windows Explorer to navigate to the path shown (C:\\ProgramData\\Oracle\\Java\\javapath for the example above), then right click on _java.exe_ and Click on _Properties_. You will see the path you should use in the _Target_ field, shown in the screenshot below. Do not include the "bin" folder in the path you place into the _JavaHome_ variable. -

- \image html javaproperties.PNG -

- A portion of an updated _serviceinstall.bat_ is shown below, with the changes marked in yellow. -

- \image html updatedServiceInstall.PNG -

-3. Edit "C:\Bitnami\solr-4.10.3-0\apache-solr\solr\solr.xml" to set the _transientCacheSize_ to the maximum number of cases expected to be open concurrently. If you expect ten concurrent cases, the text to add is -\10\ -

-The added part is highlighted in yellow below. Ensure that it is inside the \ tag as follows: -
-\image html transientcache.PNG -

-4. Edit "C:\Bitnami\solr-4.10.3-0\apache-solr\resources/log4j.properties" to configure Solr log settings: - - Increase the log rotation size threshold (_log4j\.appender\.file\.MaxFileSize_) from 4MB to 100MB. - - Remove the _CONSOLE_ appender from the _log4j\.rootLogger_ line. -

-Again you may have trouble saving to the file in the current location. If so, just save it out to the desktop and copy the edited file back over the top of the original. -

-The log file should end up looking like this (modified lines are highlighted in yellow): -

-\image html log4j.PNG -

-5. From an Autopsy installation, copy the folder "C:\Program Files\Autopsy-4.1\autopsy\solr\solr\configsets" to "C:\Bitnami\solr-4.10.3-0\apache-solr\solr". -6. From an Autopsy installation, copy the folder "C:\Program Files\Autopsy-4.1\autopsy\solr\solr\lib" to "C:\Bitnami\solr-4.10.3-0\apache-solr\solr". -7. Start a Windows command prompt as administrator by pressing _Start_, typing _command_, right clicking on _Command Prompt_, and clicking on _Run as administrator_. Then run the following command to install the _solrJetty_ service: -

- cmd /c C:\\Bitnami\\solr-4.10.3-0\\apache-solr\\scripts\\serviceinstall.bat INSTALL -

- Note the argument "INSTALL" is case sensitive. Your command prompt should look like the screenshot below. Very likely it will say "The solrJetty service could not be started." This is okay. -

-\image html solrinstall1.PNG -

-8. Press _Start_, type _services.msc_, and press _Enter_. Find _solrJetty_. If the service is running, press _Stop the service_, then double click it, and switch to the _Log On_ tab to change the logon credentials to a user who will have access to read and write the primary shared drive. Note that selecting "Local System account" will work only if Solr service and case output folders are on the same machine. Using "Local System account" to run Solr service and having case output folders on a different machine will result in Solr being unable to create index files. -
If the machine is on a domain, the Account Name will be in the form of _DOMAINNAME\\username_ as shown in the example below. Note that in the screenshot below, the domain name is _DOMAIN_ and the user name is _username_. These are just examples, not real values. -

-\image html solrinstall2.PNG -
-If the machine is on a domain, **make sure** to select the domain with the mouse by going to the _Log On_ tab, clicking _Browse_, then clicking _Locations_ and selecting the domain of interest. Then enter the user name desired and press _Check Names_. When that completes, press _OK_, type in the password once for each box and press _OK_. You may see "The user has been granted the log on as a service right." + - Add the following options in the line that begins with "-StartParams" : + + -StartParams="start;-c;-Dbootstrap_confdir=C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\AutopsyConfig\conf;-Dcollection.configName=AutopsyConfig" ^ +
+ A portion of an updated _serviceinstall.bat_ is shown below, with the changes marked in yellow. +

+ \image html updatedServiceInstall.PNG +

+3. Edit "C:\Bitnami\solr-6.2.1-2\apache-solr\bin\solr.cmd" and point _JAVA_HOME_ to _JavaHome_ path on your machine. + Changes in _solr.cmd_ are highlighted in yellow +

+ \image html updatedSolr_cmd.PNG +

+4. Edit "C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\solr.xml" to set the _transientCacheSize_ to the maximum number of cases expected to be open concurrently. If you expect ten concurrent cases, the text to add is + \10\ +

+ The added part is highlighted in yellow below. Ensure that it is inside the \ tag as follows: +
+ \image html transientcache.PNG +

+5. Edit "C:\Bitnami\solr-6.2.1-2\apache-solr\server\resources\log4j.properties" to configure Solr log settings: + - Increase the log rotation size threshold (_log4j\.appender\.file\.MaxFileSize_) from 4MB to 100MB. + - Remove the _CONSOLE_ appender from the _log4j\.rootLogger_ line. +

+ The log file should end up looking like this (modified lines are highlighted in yellow +

+ \image html log4j.PNG +

+6. From an Autopsy installation, copy the folder "C:\Program Files\Autopsy-XXX(current version)\autopsy\solr\solr\configsets" to "C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets". +7. From an Autopsy installation, copy the folder "C:\Program Files\Autopsy-XXX(current version)\autopsy\solr\solr\lib" to "C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\lib". +\subsection configure_Zookeeper Zookeeper Configuration -9. You should be able to see the Solr service in a web browser via the URL http://localhost:8983/solr/#/ as shown in the screenshot below. -

-\image html solrinstall3.PNG -

+ The following steps will configure Zookeper. + 1. Stop the solrJetty service by pressing Start, typing services.msc, pressing Enter, and locating the solrJetty Windows service. Select the service and press Stop the service. If the service is already stopped and there is no Stop the service available, this is okay. + 2. Start a Windows command prompt as administrator by pressing Start, typing command, right clicking on Command Prompt, and clicking on Run as administrator. Then run the following command to uninstall the solrJetty service: + + cmd /c C:\Bitnami\solr-6.2.1-2\apache-solr\scripts\serviceinstall.bat UNINSTALL + + You will very likely see a result that says "The solrJetty service is not started." This is okay. + + 3. Create a folder "C:\Bitnami\zookeeper" if it does not exist. + 4. Edit "C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\zoo.cfg" to include the text dataDir=C:/Bitnami/zookeeper as shown in the screenshot below +

+ \image html zooDir.PNG +
+ 5. Edit "C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\zoo.cfg" to include the text +
+
+ - autopurge.snapRetainCount=3 +
# ZooKeeper auto purge feature retains the autopurge.snapRetainCount most recent snapshots and the corresponding transaction logs in the dataDir and dataLogDir respectively and deletes the rest. Defaults to 3. Minimum value is 3. +
+ - autopurge.purgeInterval=24 +
# The time interval in hours for which the purge task has to be triggered. Set to a positive integer (1 and above) to enable the auto purging. Defaults to 0. +
+
+ as shown in yellow in the screenshot below +

+ \image html zooPurge.PNG +
+ 6. Start a Windows command prompt as administrator by pressing Start, typing command, right clicking on Command Prompt, and clicking on Run as administrator. Then run the following command to install the solrJetty service: + + cmd /c C:\Bitnami\solr-6.2.1-2\apache-solr\scripts\serviceinstall.bat INSTALL +
Note the argument "INSTALL" is case sensitive. Your command prompt should look like the screenshot below. Very likely your command prompt will say "The solrJetty service could not be started." This is okay. +

+ \image html solrinstall1.PNG +

+\subsection start_solr Start Solr +1. You should be able to see the Solr service in a web browser via the URL http://localhost:8983/solr/#/ as shown in the screenshot below. If you can, you should skip the next step. If you cannot, proceed to the next step. + +2. Press _Start_, type _services.msc_, and press _Enter_. Find _solrJetty_. If the service is running, press _Stop the service_, then double click it, and switch to the _Log On_ tab to change the logon credentials to a user who will have access to read and write the primary shared drive. Note that selecting "Local System account" will work only if Solr service and case output folders are on the same machine. Using "Local System account" to run Solr service and having case output folders on a different machine will result in Solr being unable to create index files. +
If the machine is on a domain, the Account Name will be in the form of _DOMAINNAME\\username_ as shown in the example below. Note that in the screenshot below, the domain name is _DOMAIN_ and the user name is _username_. These are just examples, not real values. +

+ \image html solrinstall2.PNG +
+ If the machine is on a domain, **make sure** to select the domain with the mouse by going to the _Log On_ tab, clicking _Browse_, then clicking _Locations_ and selecting the domain of interest. Then enter the user name desired and press _Check Names_. When that completes, press _OK_, type in the password once for each box and press _OK_. You may see "The user has been granted the log on as a service right." + +3. You should be able to see the Solr service in a web browser via the URL http://localhost:8983/solr/#/ as shown in the screenshot below. +

+ \image html solrinstall3.PNG +

If the service is appropriately started and you are unable to see the screenshot above, contact your network administrator to open ports in the firewall.

Warning: The Solr process must have adequate permissions to write data to the main shared storage drive where case output will be stored. From 37e3656bb6cae089e35862f1e948eef48b1f89a7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 11:21:32 -0500 Subject: [PATCH 51/73] 2197 integrated fix for null pointer exception from 2199 --- .../sleuthkit/autopsy/ingest/IngestOptionsPanel.java | 12 ++++++------ .../autopsy/ingest/ProfileSettingsPanel.java | 4 +--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 0ddb4e0df6..0125e9b37a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -40,7 +40,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti "IngestOptionsPanel.fileFiltersTab.toolTipText=Settings for creating and editing ingest file filters.", "IngestOptionsPanel.profilesTab.text=Profiles", "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles.", - "IngestOptionsPanel.title.text=Ingest Options" + "IngestOptionsPanel.title.text=Ingest" }) private FilesSetDefsPanel filterPanel; private IngestSettingsPanel settingsPanel; @@ -63,12 +63,13 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); settingsPanel = new IngestSettingsPanel(); profilePanel = new ProfileSettingsPanel(); - tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text"), null, - settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 0); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.text"), null, - filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 1); + filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 0); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, - profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 2); + profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 1); + tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text"), null, + settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 2); //Listener for when tabbed panes are switched, because we can have two file filter definitions panels open at the same time //we may wind up in a situation where the user has created and saved one in the profiles panel //so we need to refresh the filterPanel in those cases before proceeding. @@ -159,7 +160,6 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti } filterPanel.store(); settingsPanel.store(); - profilePanel.store(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index f3e04e5058..86e7bf7869 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -362,7 +362,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op return; } if (option == JOptionPane.OK_OPTION) { - this.saveSettings(); + panel.saveSettings(); load(); } @@ -370,12 +370,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op @Override public void saveSettings() { - this.store(); } @Override public void store() { - panel.saveSettings(); } /** From 515b84f5bcb5859634d9cf4e184a59b9cca7aeac Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 11:31:56 -0500 Subject: [PATCH 52/73] 2197 enable edit and delete profile buttons with listener --- .../autopsy/ingest/ProfileSettingsPanel.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 86e7bf7869..8500ffaa69 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -52,6 +52,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private TreeMap profiles; private ProfilePanel panel; private boolean filtersShouldBeRefreshed; + /** * Creates new form ProfileOptionsPanel */ @@ -62,6 +63,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op this.profileList.setModel(profilesListModel); this.profileList.addListSelectionListener(new ProfileSettingsPanel.ProfileListSelectionListener()); ingestWarningLabel.setVisible(false); + editProfileButton.setEnabled(false); + deleteProfileButton.setEnabled(false); } /** @@ -268,19 +271,19 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op }//GEN-LAST:event_deleteProfileButtonActionPerformed /** - * Returns whether there were possible changes to the filter list since the last time - * this was called. - * - * Resets value to false after being called. - * + * Returns whether there were possible changes to the filter list since the + * last time this was called. + * + * Resets value to false after being called. + * * @return true or false */ - boolean shouldFiltersBeRefreshed(){ + boolean shouldFiltersBeRefreshed() { boolean shouldRefresh = filtersShouldBeRefreshed; filtersShouldBeRefreshed = false; return shouldRefresh; } - + /** * Enable / disable buttons, so they can be disabled while ingest is * running. @@ -407,6 +410,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op if (selectedProfile != null) { profileDescArea.setText(selectedProfile.getDescription()); filterNameText.setText(selectedProfile.getFileIngestFilter()); + editProfileButton.setEnabled(true); + deleteProfileButton.setEnabled(true); try { Map fileIngestFilters = FilesSetsManager.getInstance().getCustomFileIngestFilters(); for (FilesSet fSet : FilesSetsManager.getStandardFileIngestFilters()) { @@ -420,6 +425,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op for (String moduleName : selectedProfile.getModuleNames(IngestProfile.getEnabledModulesKey())) { selectedModulesArea.append(moduleName + "\n"); } + + } else { + editProfileButton.setEnabled(false); + deleteProfileButton.setEnabled(false); } } } From 4cefd7534570d6fb3510c3d64506611a835996fa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 12:28:09 -0500 Subject: [PATCH 53/73] 2197 removed copy past code from IngestProfiles --- .../autopsy/ingest/IngestJobSettings.java | 66 +++++++++--------- ...estProfileMap.java => IngestProfiles.java} | 68 +++---------------- .../autopsy/ingest/ProfilePanel.java | 12 ++-- .../autopsy/ingest/ProfileSettingsPanel.java | 8 +-- .../interestingitems/FilesSetDefsPanel.java | 6 +- 5 files changed, 58 insertions(+), 102 deletions(-) rename Core/src/org/sleuthkit/autopsy/ingest/{IngestProfileMap.java => IngestProfiles.java} (74%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index 03fa136a80..cbb98512d3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -57,15 +57,6 @@ public class IngestJobSettings { private static final String MODULE_SETTINGS_FOLDER_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), IngestJobSettings.MODULE_SETTINGS_FOLDER).toAbsolutePath().toString(); private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS private static final Logger LOGGER = Logger.getLogger(IngestJobSettings.class.getName()); - - /** - * @return the ENABLED_MODULES_KEY - */ - static String getEnabledModulesKey() { - return ENABLED_MODULES_KEY; - } - - private FilesSet fileIngestFilter; private String executionContext; private final IngestType ingestType; @@ -75,15 +66,15 @@ public class IngestJobSettings { private final List warnings; /** - * Gets the last selected FileIngestFilter saved in settings which is represented - * by a FilesSet, if the last selected filter is null - * the default filter will be returned. + * Gets the last selected FileIngestFilter saved in settings which is + * represented by a FilesSet, if the last selected filter is null the + * default filter will be returned. * * @return FilesSet which represents the FileIngestFilter */ FilesSet getFileIngestFilter() { - if (fileIngestFilter==null){ - fileIngestFilter=FilesSetsManager.getDefaultFilter(); + if (fileIngestFilter == null) { + fileIngestFilter = FilesSetsManager.getDefaultFilter(); } return fileIngestFilter; } @@ -120,7 +111,7 @@ public class IngestJobSettings { /** * Constructs an ingest job settings object for a given execution context. * Examples of execution contexts include the add data source wizard and the - * run ingest modules dialog. Different execution conterxts may have + * run ingest modules dialog. Different execution contexts may have * different ingest job settings. * * @param executionContext The ingest execution context identifier. @@ -137,7 +128,7 @@ public class IngestJobSettings { /** * Constructs an ingest job settings object for a given context. Examples of * execution contexts include the add data source wizard and the run ingest - * modules dialog. Different execution conterxts may have different ingest + * modules dialog. Different execution contexts may have different ingest * job settings. * * @param context The context identifier string. @@ -167,20 +158,22 @@ public class IngestJobSettings { } /** - * Saves the settings with a new context name removing the old profile folder - * - * @param executionContext will be used to name the new folder for storing the settings + * Saves the settings with a new context name removing the old profile + * folder + * + * @param executionContext will be used to name the new folder for storing + * the settings */ void saveAs(String executionContext) { this.executionContext = executionContext; this.createSavedModuleSettingsFolder(); this.store(); } - + /** * Gets the ingest execution context identifier. Examples of execution * contexts include the add data source wizard and the run ingest modules - * dialog. Different execution conterxts may have different ingest job + * dialog. Different execution contexts may have different ingest job * settings. * * @return The execution context identifier. @@ -266,16 +259,18 @@ public class IngestJobSettings { return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, executionContext); } - /** - * Returns the path to the ingest module settings folder from a static manner. + /** + * Returns the path to the ingest module settings folder from a static + * manner. * * @param context specify the context of the folder you wish to get + * * @return path to the module settings folder */ static Path getSavedModuleSettingsFolder(String context) { return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, context); } - + /** * Creates the folder for saving the individual ingest module settings part * of these ingest job settings. @@ -322,8 +317,8 @@ public class IngestJobSettings { * Get the enabled/disabled ingest modules settings for this context. By * default, all loaded modules are enabled. */ - HashSet enabledModuleNames = getModulesNamesFromSetting(IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(loadedModuleNames)); - HashSet disabledModuleNames = getModulesNamesFromSetting(IngestJobSettings.DISABLED_MODULES_KEY, ""); //NON-NLS + HashSet enabledModuleNames = getModulesNamesFromSetting(executionContext, IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(loadedModuleNames)); + HashSet disabledModuleNames = getModulesNamesFromSetting(executionContext, IngestJobSettings.DISABLED_MODULES_KEY, ""); //NON-NLS /** * Check for missing modules and create warnings if any are found. @@ -382,9 +377,9 @@ public class IngestJobSettings { ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_KEY, FilesSetsManager.getDefaultFilter().getName()); } try { - Map fileIngestFilters = FilesSetsManager.getInstance() + Map fileIngestFilters = FilesSetsManager.getInstance() .getCustomFileIngestFilters(); - for (FilesSet fSet : FilesSetsManager.getStandardFileIngestFilters()){ + for (FilesSet fSet : FilesSetsManager.getStandardFileIngestFilters()) { fileIngestFilters.put(fSet.getName(), fSet); } this.fileIngestFilter = fileIngestFilters.get(ModuleSettings.getConfigSetting( @@ -403,12 +398,12 @@ public class IngestJobSettings { * * @return The list of module names associated with the key. */ - HashSet getModulesNamesFromSetting(String key, String defaultSetting) { - if (ModuleSettings.settingExists(this.executionContext, key) == false) { - ModuleSettings.setConfigSetting(this.executionContext, key, defaultSetting); + static HashSet getModulesNamesFromSetting(String context, String key, String defaultSetting) { + if (ModuleSettings.settingExists(context, key) == false) { + ModuleSettings.setConfigSetting(context, key, defaultSetting); } HashSet moduleNames = new HashSet<>(); - String modulesSetting = ModuleSettings.getConfigSetting(this.executionContext, key); + String modulesSetting = ModuleSettings.getConfigSetting(context, key); if (!modulesSetting.isEmpty()) { String[] settingNames = modulesSetting.split(", "); for (String name : settingNames) { @@ -436,6 +431,13 @@ public class IngestJobSettings { return moduleNames; } + /** + * @return the ENABLED_MODULES_KEY + */ + static HashSet getEnabledModules(String context, String defaultSetting) { + return getModulesNamesFromSetting(context, ENABLED_MODULES_KEY, defaultSetting); + } + /** * Determines if the moduleSettingsFilePath is that of a serialized jython * instance. Serialized Jython instances (settings saved on the disk) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java similarity index 74% rename from Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java rename to Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index 82dcedb1ff..329b38d124 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfileMap.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -22,20 +22,23 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.HashSet; +import java.util.Map; import java.util.TreeMap; import org.apache.commons.io.FileUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -public class IngestProfileMap { +/** + * Class for managing the access to the + */ +public final class IngestProfiles { private static final String PROFILE_FOLDER = "IngestProfiles"; private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; - private TreeMap profileMap = null; + private Map profileMap = null; private static final Object PROFILE_LOCK = new Object(); /** @@ -43,7 +46,7 @@ public class IngestProfileMap { * * @return profileList */ - public TreeMap getIngestProfileMap() { + public Map getIngestProfileMap() { if (profileMap == null) { loadProfileList(); } @@ -93,26 +96,17 @@ public class IngestProfileMap { * FileIngestFilter. The name can be used to find the ModuleSettings for * this profile. */ - public static class IngestProfile { + public static final class IngestProfile { private final String name; private final String description; private final String fileIngestFilter; - /** - * The key for Enabled ingest modules - * - * @return the ENABLED_MODULES_KEY - */ - static String getEnabledModulesKey() { - return IngestJobSettings.getEnabledModulesKey(); - } - /** * Creates a new IngestProfile - * - * @param name - unique name of the profile - * @param desc - optional description of profile + * + * @param name - unique name of the profile + * @param desc - optional description of profile * @param selectedFilter - the File Ingest Filter used for this profile */ IngestProfile(String name, String desc, String selectedFilter) { @@ -197,46 +191,6 @@ public class IngestProfileMap { } } - /** - * Gets the module names for a given key. - * - * @param key The key string. - */ - HashSet getModuleNames(String key) { - synchronized (PROFILE_LOCK) { - if (ModuleSettings.settingExists(this.getName(), key) == false) { - ModuleSettings.setConfigSetting(this.getName(), key, ""); - } - HashSet moduleNames = new HashSet<>(); - String modulesSetting = ModuleSettings.getConfigSetting(this.getName(), key); - if (!modulesSetting.isEmpty()) { - String[] settingNames = modulesSetting.split(", "); - for (String name : settingNames) { - // Map some old core module names to the current core module names. - switch (name) { - case "Thunderbird Parser": //NON-NLS - case "MBox Parser": //NON-NLS - moduleNames.add("Email Parser"); //NON-NLS - break; - case "File Extension Mismatch Detection": //NON-NLS - moduleNames.add("Extension Mismatch Detector"); //NON-NLS - break; - case "EWF Verify": //NON-NLS - case "E01 Verify": //NON-NLS - moduleNames.add("E01 Verifier"); //NON-NLS - break; - case "Archive Extractor": //NON-NLS - moduleNames.add("Embedded File Extractor"); //NON-NLS - break; - default: - moduleNames.add(name); - } - } - } - return moduleNames; - } - } - /** * Save a Ingest profile file in the profile folder. * diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 84cb63bfff..b9e48b1043 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -26,7 +26,7 @@ import java.util.List; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; +import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; /** * Panel to display options for profile creation and editing. @@ -70,10 +70,10 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { /** * Get the name of the profile. - * + * * The name will not contain any trailing or leading spaces. - * - * @return + * + * @return */ String getProfileName() { return profileNameField.getText().trim(); @@ -211,8 +211,8 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { DialogDisplayer.getDefault().notify(notifyDesc); return false; } - if (!containsOnlyLegalChars(getProfileName(), ILLEGAL_NAME_CHARS)){ - NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( + if (!containsOnlyLegalChars(getProfileName(), ILLEGAL_NAME_CHARS)) { + NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profileNameContainsIllegalCharacter"), NotifyDescriptor.WARNING_MESSAGE); DialogDisplayer.getDefault().notify(notifyDesc); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 8500ffaa69..4a393acfad 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -28,7 +28,7 @@ import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; +import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; @@ -49,7 +49,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op }) private final DefaultListModel profilesListModel; - private TreeMap profiles; + private Map profiles; private ProfilePanel panel; private boolean filtersShouldBeRefreshed; @@ -386,7 +386,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op public void load() { int currentIndex = this.profileList.getSelectedIndex(); this.profilesListModel.clear(); - this.profiles = new IngestProfileMap().getIngestProfileMap(); + this.profiles = (TreeMap) new IngestProfiles().getIngestProfileMap(); for (IngestProfile profile : this.profiles.values()) { profilesListModel.addElement(profile); } @@ -422,7 +422,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op filterDescArea.setText(NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.messages.filterLoadFailed")); } selectedModulesArea.setText(""); - for (String moduleName : selectedProfile.getModuleNames(IngestProfile.getEnabledModulesKey())) { + for (String moduleName : IngestJobSettings.getEnabledModules(selectedProfile.getName(), "")) { selectedModulesArea.append(moduleName + "\n"); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index f2f707456e..4ba0b16553 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -38,8 +38,8 @@ import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -import org.sleuthkit.autopsy.ingest.IngestProfileMap; -import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; +import org.sleuthkit.autopsy.ingest.IngestProfiles; +import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; /** @@ -1003,7 +1003,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private void deleteSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteSetButtonActionPerformed FilesSet selectedSet = this.setsList.getSelectedValue(); if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { - for (IngestProfile profile : new IngestProfileMap().getIngestProfileMap().values()) { + for (IngestProfile profile : new IngestProfiles().getIngestProfileMap().values()) { if (profile.getFileIngestFilter().equals(selectedSet.getName())) { MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.ingest.fileFilterInUseError", From aa2be4b68159689925e6d13b411893d000b2979e Mon Sep 17 00:00:00 2001 From: Dmitry Charit Date: Tue, 14 Feb 2017 18:25:40 +0000 Subject: [PATCH 54/73] corrected --- docs/doxygen-user/installSolr.dox | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/doxygen-user/installSolr.dox b/docs/doxygen-user/installSolr.dox index 000dc2012f..20f2953a93 100755 --- a/docs/doxygen-user/installSolr.dox +++ b/docs/doxygen-user/installSolr.dox @@ -1,5 +1,5 @@ -/*! \page install_solr Install and Configure Solr and Zookeper -A central Solr server is needed to store keyword indexes. Zoookeeper is used to keep Solr configuartions. It is installed as part of Bitnami Solr package, but has to be configured separetly. To install Solr, perform the following steps: +/*! \page install_solr Install and Configure Solr and Zookeeper +A central Solr server is needed to store keyword indexes. Zookeeper is used to manage Solr configuration and as a coordination service for Autopsy. It is installed as part of Bitnami Solr package, but has to be configured separately. To install Solr, perform the following steps: @@ -7,7 +7,7 @@ A central Solr server is needed to store keyword indexes. Zoookeeper is used to You will need: - 64-bit version of the Java Runtime Environment (JRE) from http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html. -- Download the Apache Solr 6.2.1 installation package from http://www.apache.org/dyn/closer.lua/lucene/solr/6.2.1-2 +- Download the latest Solr 6 installation package from https://bitnami.com/stack/solr/installer#windows. For the purposes of this guide that was the Bitnami Solr 6.2.1-2. - Access to an installed version of Autopsy so that you can copy files from it. - A network-accessible machine to install Solr upon. Note that the Solr process will need to write data out to the main shared storage drive, and needs adequate permissions to write to this location, which may be across a network. @@ -84,7 +84,7 @@ The following steps will configure Solr to run using an account that will have a 7. From an Autopsy installation, copy the folder "C:\Program Files\Autopsy-XXX(current version)\autopsy\solr\solr\lib" to "C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\lib". \subsection configure_Zookeeper Zookeeper Configuration - The following steps will configure Zookeper. + The following steps will configure Zookeeper. 1. Stop the solrJetty service by pressing Start, typing services.msc, pressing Enter, and locating the solrJetty Windows service. Select the service and press Stop the service. If the service is already stopped and there is no Stop the service available, this is okay. 2. Start a Windows command prompt as administrator by pressing Start, typing command, right clicking on Command Prompt, and clicking on Run as administrator. Then run the following command to uninstall the solrJetty service: From b42b4c128c316d022d36077d3dbe4a8b730a0f6f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 13:47:44 -0500 Subject: [PATCH 55/73] 2197 fixed formatting in all files which were modified --- .../services/TagsOptionsPanelController.java | 40 ++++++------ .../DirectoryTreeTopComponent.java | 3 +- .../autopsy/ingest/IngestJobSettings.java | 8 ++- .../ingest/IngestJobSettingsPanel.java | 6 +- .../autopsy/ingest/IngestOptionsPanel.java | 6 +- .../ingest/IngestOptionsPanelController.java | 2 +- .../autopsy/ingest/IngestProfiles.java | 18 +++--- .../autopsy/ingest/ProfileSettingsPanel.java | 5 +- .../interestingitems/FilesSetDefsPanel.java | 2 +- ...omArtifactsCreatorIngestModuleFactory.java | 12 ++-- .../AutoIngestSettingsPanel.java | 64 ++++++++++--------- 11 files changed, 87 insertions(+), 79 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java index 2ee820433b..39daa7419f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java @@ -1,21 +1,21 @@ /* -* Autopsy Forensic Browser -* -* Copyright 2011-2016 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. -*/ + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule.services; import java.beans.PropertyChangeEvent; @@ -38,7 +38,7 @@ public final class TagsOptionsPanelController extends OptionsPanelController { private TagOptionsPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; - + /** * Component should load its data here. */ @@ -105,7 +105,7 @@ public final class TagsOptionsPanelController extends OptionsPanelController { public void removePropertyChangeListener(PropertyChangeListener l) { pcs.removePropertyChangeListener(l); } - + private TagOptionsPanel getPanel() { if (panel == null) { panel = new TagOptionsPanel(); @@ -117,7 +117,7 @@ public final class TagsOptionsPanelController extends OptionsPanelController { } return panel; } - + void changed() { if (!changed) { changed = true; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 20ce2db7e8..64cd419024 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -799,7 +799,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Set the selected node using a path to a previously selected node. * * @param previouslySelectedNodePath Path to a previously selected node. - * @param rootNodeName Name of the root node to match, may be null. + * @param rootNodeName Name of the root node to match, may be + * null. */ private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) { if (previouslySelectedNodePath == null) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index cbb98512d3..f3c9f520d2 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -432,7 +432,13 @@ public class IngestJobSettings { } /** - * @return the ENABLED_MODULES_KEY + * Get a set which contains all the names of enabled modules for the + * specified context. + * + * @param defaultSetting - The default list of module names. + * @param context -the execution context (profile name) to check + * + * @return the names of the enabled modules */ static HashSet getEnabledModules(String context, String defaultSetting) { return getModulesNamesFromSetting(context, ENABLED_MODULES_KEY, defaultSetting); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index ea9f5b52cf..0bb16b90f9 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -184,11 +184,11 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { */ pastJobsButton.setEnabled(!dataSources.isEmpty() && !ingestJobs.isEmpty()); } - - void setPastJobsButtonVisible(boolean isVisible){ + + void setPastJobsButtonVisible(boolean isVisible) { pastJobsButton.setVisible(isVisible); } - + /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 0125e9b37a..42d94674e9 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -67,7 +67,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.text"), null, filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 0); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, - profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 1); + profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 1); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text"), null, settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 2); //Listener for when tabbed panes are switched, because we can have two file filter definitions panels open at the same time @@ -84,7 +84,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti } } }); - + addIngestJobEventsListener(); enableTabs(); } @@ -156,7 +156,7 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti public void saveSettings() { //if a new filter was created in the profilePanel we don't want to save over it accidently if (profilePanel.shouldFiltersBeRefreshed()) { - filterPanel.load(); + filterPanel.load(); } filterPanel.store(); settingsPanel.store(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java index ec086ba9b4..b9c4ea9546 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java @@ -51,7 +51,7 @@ public class IngestOptionsPanelController extends OptionsPanelController { /** * Get the IngestOptionsPanel which is contained inside this controller. - * + * * @return panel */ private IngestOptionsPanel getPanel() { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index 329b38d124..2f62ac2633 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -22,8 +22,8 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Map; -import java.util.TreeMap; +import java.util.ArrayList; +import java.util.List; import org.apache.commons.io.FileUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -38,7 +38,7 @@ public final class IngestProfiles { private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; - private Map profileMap = null; + private List profileList = null; private static final Object PROFILE_LOCK = new Object(); /** @@ -46,11 +46,11 @@ public final class IngestProfiles { * * @return profileList */ - public Map getIngestProfileMap() { - if (profileMap == null) { + public List getIngestProfiles() { + if (profileList == null) { loadProfileList(); } - return profileMap; + return profileList; } /** @@ -61,14 +61,14 @@ public final class IngestProfiles { File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); File[] directoryListing = dir.listFiles(); - profileMap = new TreeMap<>(); + profileList = new ArrayList<>(); if (directoryListing != null) { for (File child : directoryListing) { String name = child.getName().split("\\.")[0]; String context = PROFILE_FOLDER + File.separator + name; String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); String fileIngestFilter = ModuleSettings.getConfigSetting(context, PROFILE_FILTER_KEY); - profileMap.put(name, new IngestProfile(name, desc, fileIngestFilter)); + profileList.add(new IngestProfile(name, desc, fileIngestFilter)); } } } @@ -86,7 +86,7 @@ public final class IngestProfiles { */ void saveProfileList() { //save last used profile - for (IngestProfile profile : getIngestProfileMap().values()) { + for (IngestProfile profile : getIngestProfiles()) { IngestProfile.saveProfile(profile); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 4a393acfad..9e15f0bb47 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -386,9 +386,10 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op public void load() { int currentIndex = this.profileList.getSelectedIndex(); this.profilesListModel.clear(); - this.profiles = (TreeMap) new IngestProfiles().getIngestProfileMap(); - for (IngestProfile profile : this.profiles.values()) { + this.profiles = new TreeMap(); + for (IngestProfile profile : new IngestProfiles().getIngestProfiles()) { profilesListModel.addElement(profile); + profiles.put(profile.getName(), profile); } if (currentIndex < 0 || currentIndex >= profilesListModel.getSize()) { currentIndex = 0; diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 4ba0b16553..6509f4f6c8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -1003,7 +1003,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private void deleteSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteSetButtonActionPerformed FilesSet selectedSet = this.setsList.getSelectedValue(); if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { - for (IngestProfile profile : new IngestProfiles().getIngestProfileMap().values()) { + for (IngestProfile profile : new IngestProfiles().getIngestProfiles()) { if (profile.getFileIngestFilter().equals(selectedSet.getName())) { MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.ingest.fileFilterInUseError", diff --git a/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java index 766a3260dd..90bae4fc9e 100644 --- a/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/report/testfixtures/CustomArtifactsCreatorIngestModuleFactory.java @@ -18,10 +18,8 @@ */ package org.sleuthkit.autopsy.report.testfixtures; -import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.ingest.FileIngestModule; -import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; @@ -31,8 +29,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; * annotation to activate this test fixture. */ //@ServiceProvider(service = IngestModuleFactory.class) -public final class CustomArtifactsCreatorIngestModuleFactory extends IngestModuleFactoryAdapter { - +public final class CustomArtifactsCreatorIngestModuleFactory extends IngestModuleFactoryAdapter { + @Override public String getModuleDisplayName() { return getModuleName(); @@ -57,8 +55,8 @@ public final class CustomArtifactsCreatorIngestModuleFactory extends IngestModu public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { return new CustomArtifactsCreatorIngestModule(); } - - static String getModuleName() { + + static String getModuleName() { return "Custom Artifacts Creator"; - } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 0377a704b8..8ba7e76a2e 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -114,7 +114,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { * @param inStartup True if we're doing the initial population of the UI */ final void load(boolean inStartup) { - + // multi user mode must be enabled if (!UserPreferences.getIsMultiUserModeEnabled()) { tbOops.setText(MULTI_USER_SETTINGS_MUST_BE_ENABLED); @@ -123,23 +123,25 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } cbJoinAutoIngestCluster.setSelected(AutoIngestUserPreferences.getJoinAutoModeCluster()); cbJoinAutoIngestCluster.setEnabled(UserPreferences.getIsMultiUserModeEnabled()); - + if (inStartup) { AutoIngestUserPreferences.SelectedMode storedMode = AutoIngestUserPreferences.getMode(); inputPathTextField.requestFocusInWindow(); - if (null != storedMode) switch (storedMode) { - case REVIEW: - jRadioButtonReview.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - break; - case AUTOMATED: - jRadioButtonAutomated.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.AIM); - break; - default: - cbJoinAutoIngestCluster.setSelected(false); - enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); - break; + if (null != storedMode) { + switch (storedMode) { + case REVIEW: + jRadioButtonReview.setSelected(true); + enableOptionsBasedOnMode(OptionsUiMode.REVIEW); + break; + case AUTOMATED: + jRadioButtonAutomated.setSelected(true); + enableOptionsBasedOnMode(OptionsUiMode.AIM); + break; + default: + cbJoinAutoIngestCluster.setSelected(false); + enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); + break; + } } } @@ -206,11 +208,11 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { void store() { boolean needsRestart = false; AutoIngestUserPreferences.SelectedMode storedMode = AutoIngestUserPreferences.getMode(); - + if (AutoIngestUserPreferences.getJoinAutoModeCluster() != cbJoinAutoIngestCluster.isSelected()) { needsRestart = true; } - + AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected()); if (!cbJoinAutoIngestCluster.isSelected()) { AutoIngestUserPreferences.setMode(AutoIngestUserPreferences.SelectedMode.STANDALONE); @@ -224,8 +226,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { }); } return; - } - + } + if (jRadioButtonAutomated.isSelected()) { if (storedMode != AutoIngestUserPreferences.SelectedMode.AUTOMATED) { needsRestart = true; @@ -261,7 +263,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { AutoIngestUserPreferences.setMode(AutoIngestUserPreferences.SelectedMode.REVIEW); String resultsFolderPath = getNormalizedFolderPath(outputPathTextField.getText().trim()); - AutoIngestUserPreferences.setAutoModeResultsFolder(resultsFolderPath); + AutoIngestUserPreferences.setAutoModeResultsFolder(resultsFolderPath); } if (needsRestart) { SwingUtilities.invokeLater(() -> { @@ -303,11 +305,11 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { * Validate current panel settings. */ boolean valid() { - + if (!cbJoinAutoIngestCluster.isSelected()) { return true; } - + boolean isValidNodePanel = true; switch (getModeFromRadioButtons()) { @@ -333,13 +335,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { break; default: break; - } - + } + if (jRadioButtonAutomated.isSelected()) { if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { isValidNodePanel = false; } - } + } return isValidNodePanel; } @@ -593,10 +595,10 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } private void enableOptionsBasedOnMode(OptionsUiMode mode) { - if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { + if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); - + jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM); inputPathTextField.setEnabled(mode == OptionsUiMode.AIM); browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM); @@ -629,7 +631,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { if (!cbJoinAutoIngestCluster.isSelected()) { return OptionsUiMode.STANDALONE; } - + if (jRadioButtonAutomated.isSelected()) { return OptionsUiMode.AIM; } else if (jRadioButtonReview.isSelected()) { @@ -1269,9 +1271,9 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void bnAdvancedSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnAdvancedSettingsActionPerformed AdvancedAutoIngestSettingsPanel advancedAutoIngestSettingsPanel = new AdvancedAutoIngestSettingsPanel(getModeFromRadioButtons()); if (JOptionPane.showConfirmDialog(null, advancedAutoIngestSettingsPanel, - NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { - advancedAutoIngestSettingsPanel.store(); + NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { + advancedAutoIngestSettingsPanel.store(); } }//GEN-LAST:event_bnAdvancedSettingsActionPerformed From 3eda78669b3168bb23567c67b7565563dfb09157 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 15:27:51 -0500 Subject: [PATCH 56/73] 2197 IngestProfiles getter now static and synchronized --- .../autopsy/ingest/IngestProfiles.java | 92 +++++++------------ .../autopsy/ingest/ProfileSettingsPanel.java | 5 +- .../interestingitems/FilesSetDefsPanel.java | 2 +- 3 files changed, 36 insertions(+), 63 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index 2f62ac2633..8c4d9e0b58 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -38,55 +38,33 @@ public final class IngestProfiles { private static final String PROFILE_NAME_KEY = "Profile_Name"; private static final String PROFILE_DESC_KEY = "Profile_Description"; private static final String PROFILE_FILTER_KEY = "Profile_Filter"; - private List profileList = null; - private static final Object PROFILE_LOCK = new Object(); /** * Gets the collection of profiles which currently exist. * * @return profileList */ - public List getIngestProfiles() { - if (profileList == null) { - loadProfileList(); + public synchronized static List getIngestProfiles() { + File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); + File[] directoryListing = dir.listFiles(); + List profileList = new ArrayList<>(); + if (directoryListing != null) { + for (File child : directoryListing) { + String name = child.getName().split("\\.")[0]; + String context = PROFILE_FOLDER + File.separator + name; + String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); + String fileIngestFilter = ModuleSettings.getConfigSetting(context, PROFILE_FILTER_KEY); + profileList.add(new IngestProfile(name, desc, fileIngestFilter)); + } } return profileList; } - /** - * Read the stored profile definitions from their directory. - */ - private void readFilesFromDirectory() { - synchronized (PROFILE_LOCK) { - File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); - File[] directoryListing = dir.listFiles(); - - profileList = new ArrayList<>(); - if (directoryListing != null) { - for (File child : directoryListing) { - String name = child.getName().split("\\.")[0]; - String context = PROFILE_FOLDER + File.separator + name; - String desc = ModuleSettings.getConfigSetting(context, PROFILE_DESC_KEY); - String fileIngestFilter = ModuleSettings.getConfigSetting(context, PROFILE_FILTER_KEY); - profileList.add(new IngestProfile(name, desc, fileIngestFilter)); - } - } - } - } - - /** - * Loads the list of profiles from disk. - */ - void loadProfileList() { - readFilesFromDirectory(); - } - /** * Saves the list of profiles which currently exist to disk. */ - void saveProfileList() { - //save last used profile - for (IngestProfile profile : getIngestProfiles()) { + synchronized static void setProfiles(List profiles) { + for (IngestProfile profile : profiles) { IngestProfile.saveProfile(profile); } } @@ -157,15 +135,13 @@ public final class IngestProfiles { * * @param selectedProfile */ - static void deleteProfile(IngestProfile selectedProfile) { - synchronized (PROFILE_LOCK) { - try { - Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, selectedProfile.getName() + ".properties")); - Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), selectedProfile.getName() + ".properties")); - FileUtils.deleteDirectory(IngestJobSettings.getSavedModuleSettingsFolder(selectedProfile.getName() + File.separator).toFile()); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } + synchronized static void deleteProfile(IngestProfile selectedProfile) { + try { + Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, selectedProfile.getName() + ".properties")); + Files.deleteIfExists(Paths.get(PlatformUtil.getUserConfigDirectory(), selectedProfile.getName() + ".properties")); + FileUtils.deleteDirectory(IngestJobSettings.getSavedModuleSettingsFolder(selectedProfile.getName() + File.separator).toFile()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); } } @@ -175,19 +151,17 @@ public final class IngestProfiles { * @param oldName the name of the profile you want to rename * @param newName the name which you want the profile to have */ - static void renameProfile(String oldName, String newName) { + synchronized static void renameProfile(String oldName, String newName) { if (!oldName.equals(newName)) { //if renameProfile was called with the new name being the same as the old name, it is complete already - synchronized (PROFILE_LOCK) { - File oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, oldName + ".properties").toFile(); - File newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, newName + ".properties").toFile(); - oldFile.renameTo(newFile); - oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), oldName + ".properties").toFile(); - newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), newName + ".properties").toFile(); - oldFile.renameTo(newFile); - oldFile = IngestJobSettings.getSavedModuleSettingsFolder(oldName + File.separator).toFile(); - newFile = IngestJobSettings.getSavedModuleSettingsFolder(newName + File.separator).toFile(); - oldFile.renameTo(newFile); - } + File oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, oldName + ".properties").toFile(); + File newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER, newName + ".properties").toFile(); + oldFile.renameTo(newFile); + oldFile = Paths.get(PlatformUtil.getUserConfigDirectory(), oldName + ".properties").toFile(); + newFile = Paths.get(PlatformUtil.getUserConfigDirectory(), newName + ".properties").toFile(); + oldFile.renameTo(newFile); + oldFile = IngestJobSettings.getSavedModuleSettingsFolder(oldName + File.separator).toFile(); + newFile = IngestJobSettings.getSavedModuleSettingsFolder(newName + File.separator).toFile(); + oldFile.renameTo(newFile); } } @@ -196,13 +170,11 @@ public final class IngestProfiles { * * @param profile */ - static void saveProfile(IngestProfile profile) { - synchronized (PROFILE_LOCK) { + synchronized static void saveProfile(IngestProfile profile) { String context = PROFILE_FOLDER + File.separator + profile.getName(); ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName()); ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription()); ModuleSettings.setConfigSetting(context, PROFILE_FILTER_KEY, profile.getFileIngestFilter()); - } } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 9e15f0bb47..50e0a818ab 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -377,6 +377,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op @Override public void store() { + saveSettings(); } /** @@ -386,8 +387,8 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op public void load() { int currentIndex = this.profileList.getSelectedIndex(); this.profilesListModel.clear(); - this.profiles = new TreeMap(); - for (IngestProfile profile : new IngestProfiles().getIngestProfiles()) { + this.profiles = new TreeMap<>(); + for (IngestProfile profile : IngestProfiles.getIngestProfiles()) { profilesListModel.addElement(profile); profiles.put(profile.getName(), profile); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 6509f4f6c8..184b5d8b46 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -1003,7 +1003,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private void deleteSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteSetButtonActionPerformed FilesSet selectedSet = this.setsList.getSelectedValue(); if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { - for (IngestProfile profile : new IngestProfiles().getIngestProfiles()) { + for (IngestProfile profile : IngestProfiles.getIngestProfiles()) { if (profile.getFileIngestFilter().equals(selectedSet.getName())) { MessageNotifyUtil.Message.error(NbBundle.getMessage(this.getClass(), "FilesSetDefsPanel.ingest.fileFilterInUseError", From 043db65453efd8b8c1834a7ad209c04493a5a7dd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 15:37:19 -0500 Subject: [PATCH 57/73] 2197 fixed doc version number accidently reverted --- Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index b7a7349148..51e0ac87d3 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -27,7 +27,7 @@ Format_OperatingSystem_Value={0} version {1} running on {2} LBL_Copyright=

Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2016.
URL_ON_IMG=http://www.sleuthkit.org/ -URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.2/ +URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.3/ FILE_FOR_LOCAL_HELP=file:/// INDEX_FOR_LOCAL_HELP=/docs/index.html From 8b4b2b2fb5ca61df284a6cc4917518d2e9fab85b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 15:56:21 -0500 Subject: [PATCH 58/73] 2198 resolve some additional conflicts from IngestProfiles rename --- .../autopsy/ingest/IngestProfiles.java | 2 +- .../IngestProfileSelectionPanel.java | 35 ++++++++++--------- .../RunIngestModulesWizardIterator.java | 7 ++-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index 8c4d9e0b58..f952ff54ac 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -117,7 +117,7 @@ public final class IngestProfiles { * * @return the description */ - String getDescription() { + public String getDescription() { return description; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 7486d74c99..b98169bab5 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -31,8 +31,8 @@ import javax.swing.JScrollPane; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; import org.sleuthkit.autopsy.ingest.IngestOptionsPanel; -import org.sleuthkit.autopsy.ingest.IngestProfileMap; -import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; +import org.sleuthkit.autopsy.ingest.IngestProfiles; +import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; /** * Visual panel for the choosing of ingest profiles by the user when running @@ -40,12 +40,12 @@ import org.sleuthkit.autopsy.ingest.IngestProfileMap.IngestProfile; */ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { - @Messages({"IngestProfileSelectionPanel.customSettings.name=Custom Settings", + @Messages({"IngestProfileSelectionPanel.customSettings.name=Custom Settings", "IngestProfileSelectionPanel.name=Ingest Profile Selection", "IngestProfileSelectionPanel.customSettings.description=configure individual module settings in next step of wizard"}) - + private static final String CUSTOM_SETTINGS_DISPLAY_NAME = Bundle.IngestProfileSelectionPanel_customSettings_name(); - private static final String CUSTOM_SETTINGS_DESCRIPTION = Bundle.IngestProfileSelectionPanel_customSettings_description(); + private static final String CUSTOM_SETTINGS_DESCRIPTION = Bundle.IngestProfileSelectionPanel_customSettings_description(); private final IngestProfileSelectionWizardPanel wizardPanel; private String selectedProfile; private List profiles = Collections.emptyList(); @@ -61,9 +61,12 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { wizardPanel = panel; selectedProfile = lastSelectedProfile; populateListOfCheckboxes(); - this.setName(Bundle.IngestProfileSelectionPanel_name()); + customizePanel(); } + private void customizePanel(){ + this.setName(Bundle.IngestProfileSelectionPanel_name()); + } /** * Returns the profile that is currently selected in this panel * @@ -111,6 +114,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { /** * Getter for the list of profiles + * * @return profiles */ private List getProfiles() { @@ -189,9 +193,9 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { }// //GEN-END:initComponents /** - * Opens up a dialog with an IngestOptionsPanel so the user can modify any - * settings from that options panel. - * + * Opens up a dialog with an IngestOptionsPanel so the user can modify any + * settings from that options panel. + * * @param evt the button press */ private void ingestSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ingestSettingsButtonActionPerformed @@ -222,11 +226,11 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { // End of variables declaration//GEN-END:variables /** - * Listens for changes and checks the currently selected radio button - * if custom settings button is enabled it enables the next button, - * otherwise it enables the Finish button. - * - * @param e + * Listens for changes and checks the currently selected radio button if + * custom settings button is enabled it enables the next button, otherwise + * it enables the Finish button. + * + * @param e */ @Override public void itemStateChanged(ItemEvent e) { @@ -247,7 +251,6 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { * Get all the currently existing ingest profiles. */ private void fetchProfileList() { - profiles = new ArrayList<>(); - profiles.addAll(new IngestProfileMap().getIngestProfileMap().values()); + profiles = IngestProfiles.getIngestProfiles(); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index 7354255456..f5e3daa60b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -22,11 +22,10 @@ import java.awt.Component; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; -import java.util.TreeMap; import javax.swing.JComponent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; -import org.sleuthkit.autopsy.ingest.IngestProfileMap; +import org.sleuthkit.autopsy.ingest.IngestProfiles; /** * Iterator class for creating a wizard for run ingest modules. @@ -47,8 +46,8 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< private List> getPanels() { if (panels == null) { panels = new ArrayList<>(); - TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); - if (!profileMap.isEmpty()) { + List profiles = IngestProfiles.getIngestProfiles(); + if (!profiles.isEmpty()) { panels.add(new IngestProfileSelectionWizardPanel()); } From 064df7fedf49b5242f43da56f25213a73b4e8481 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 16:07:27 -0500 Subject: [PATCH 59/73] 2197 removing Options from the options panel name --- Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 333d179c74..e2d25014e3 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -114,8 +114,8 @@ IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings IngestJobSettingsPanel.pastJobsButton.text=History IngestJobSettingsPanel.fileIngestFilterLabel.text=Run ingest modules on: -OptionsCategory_Name_IngestOptions=Ingest Options -OptionsCategory_Keywords_IngestOptions=IngestOptions +OptionsCategory_Name_IngestOptions=Ingest +OptionsCategory_Keywords_IngestOptions=Ingest IngestSettingsPanel.jLabelProcessTimeOutUnits.text=hour(s) IngestSettingsPanel.jFormattedTextFieldProcTimeOutHrs.text=60 IngestSettingsPanel.jCheckBoxEnableProcTimeout.text= From c4c7cbb9f8c52b7aa09e9e4f83ecbfe599dd2254 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 16:25:10 -0500 Subject: [PATCH 60/73] 2198 formatting fixes to all modified files --- .../autopsy/datamodel/ImageNode.java | 2 +- .../datamodel/VirtualDirectoryNode.java | 10 +++--- .../DirectoryTreeFilterNode.java | 4 +-- .../ingest/IngestJobSettingsPanel.java | 2 +- .../autopsy/ingest/IngestProfiles.java | 8 ++--- .../ingest/IngestProgressSnapshotDialog.java | 10 +++--- .../autopsy/ingest/RunIngestSubMenu.java | 22 ++++++------ .../IngestModulesConfigWizardPanel.java | 2 +- .../IngestProfileSelectionPanel.java | 5 +-- .../IngestProfileSelectionWizardPanel.java | 2 +- .../RunIngestModulesAction.java | 35 ++++++++++--------- .../RunIngestModulesWizardIterator.java | 5 ++- .../AddFileTypeSignatureDialog.java | 8 ++--- 13 files changed, 58 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 5a4f99dae0..682a3fa225 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 2dcb6fce3d..40f14bf63a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011-2014 Basis Technology Corp. + * + * Copyright 2011-2017 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. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index 257e81f378..d5786333aa 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -72,7 +72,7 @@ class DirectoryTreeFilterNode extends FilterNode { if (file != null) { try { final int numChildren = file.getChildrenCount(); - + // left-to-right marks here are necessary to keep the count and parens together // for mixed right-to-left and left-to-right names name = name + " \u200E(\u200E" + numChildren + ")\u200E"; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index d06e60a2fe..9d5e845721 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index f952ff54ac..101d5bb0b1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -171,10 +171,10 @@ public final class IngestProfiles { * @param profile */ synchronized static void saveProfile(IngestProfile profile) { - String context = PROFILE_FOLDER + File.separator + profile.getName(); - ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName()); - ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription()); - ModuleSettings.setConfigSetting(context, PROFILE_FILTER_KEY, profile.getFileIngestFilter()); + String context = PROFILE_FOLDER + File.separator + profile.getName(); + ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName()); + ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription()); + ModuleSettings.setConfigSetting(context, PROFILE_FILTER_KEY, profile.getFileIngestFilter()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java index 3323240a88..69416bf6c7 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProgressSnapshotDialog.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2014 Basis Technology Corp. + * + * Copyright 2011-2017 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. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java index a8fabc1f31..0900e3041d 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,29 +31,30 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; /** - * This class is used to populate the list of open dataSources to run ingest on them + * This class is used to populate the list of open dataSources to run ingest on + * them */ final class RunIngestSubMenu extends JMenuItem implements DynamicMenuContent { - + /** - * Creates main menu/popup menu items. It's called each time a popup menu - * is constructed and just once for the main menu. - * Main menu updates happen through the synchMenuPresenters() method. + * Creates main menu/popup menu items. It's called each time a popup menu is + * constructed and just once for the main menu. Main menu updates happen + * through the synchMenuPresenters() method. * * @return */ @Override public JComponent[] getMenuPresenters() { List dataSources = new ArrayList<>(); - - try { + + try { dataSources = Case.getCurrentCase().getDataSources(); } catch (IllegalStateException ex) { // No open Cases, create a disabled empty menu return getEmpty(); } catch (TskCoreException e) { System.out.println("Exception getting images: " + e.getMessage()); //NON-NLS - } + } JComponent[] comps = new JComponent[dataSources.size()]; // Add Images to the component list @@ -70,7 +71,7 @@ final class RunIngestSubMenu extends JMenuItem implements DynamicMenuContent { } return comps; } - + // returns a disabled empty menu private JComponent[] getEmpty() { JComponent[] comps = new JComponent[1]; @@ -95,5 +96,4 @@ final class RunIngestSubMenu extends JMenuItem implements DynamicMenuContent { return getMenuPresenters(); } - } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java index 5244eeaaf3..0d2e20ba55 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java @@ -73,7 +73,7 @@ class IngestModulesConfigWizardPanel implements WizardDescriptor.FinishablePanel public void storeSettings(WizardDescriptor wiz) { IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); ingestJobSettings.save(); - wiz.putProperty("executionContext", RunIngestModulesAction.getDefaultContext()); //NON-NLS + wiz.putProperty("executionContext", RunIngestModulesAction.getDefaultContext()); //NON-NLS } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index b98169bab5..cb0868d068 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -64,9 +64,10 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { customizePanel(); } - private void customizePanel(){ - this.setName(Bundle.IngestProfileSelectionPanel_name()); + private void customizePanel() { + this.setName(Bundle.IngestProfileSelectionPanel_name()); } + /** * Returns the profile that is currently selected in this panel * diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index bfa8b035cf..980dc5af94 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -60,7 +60,7 @@ class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePa } return component; } - + @Override public HelpCtx getHelp() { // Show no Help button for this panel: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index 9834a26134..4636ff72f4 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -39,29 +39,29 @@ import org.sleuthkit.datamodel.Directory; * modules. */ public final class RunIngestModulesAction extends AbstractAction { - + @Messages("RunIngestModulesAction.name=Run Ingest Modules") - + //'dialog' context name required so existing settings do not need to be reconfigured private static final String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; /** - * Returns the name of the default context which will be used when profiles are not available. - * + * Returns the name of the default context which will be used when profiles + * are not available. + * * @return the DEFAULT_CONTEXT */ static String getDefaultContext() { return DEFAULT_CONTEXT; } - private final List dataSources = new ArrayList<>(); private final IngestJobSettings.IngestType ingestType; - + /** - * Creates an action which will make a run ingest modules wizard when it - * is performed. - * + * Creates an action which will make a run ingest modules wizard when it is + * performed. + * * @param dataSources - the data sources you want to run ingest on */ public RunIngestModulesAction(List dataSources) { @@ -69,11 +69,11 @@ public final class RunIngestModulesAction extends AbstractAction { this.dataSources.addAll(dataSources); this.ingestType = IngestJobSettings.IngestType.ALL_MODULES; } - + /** - * Creates an action which will make a run ingest modules wizard when it - * is performed. - * + * Creates an action which will make a run ingest modules wizard when it is + * performed. + * * @param dir - the directory you want to run ingest on */ public RunIngestModulesAction(Directory dir) { @@ -81,6 +81,7 @@ public final class RunIngestModulesAction extends AbstractAction { this.dataSources.add(dir); this.ingestType = IngestJobSettings.IngestType.FILES_ONLY; } + /** * Opens a run ingest modules wizard with the list of data sources. * @@ -92,9 +93,9 @@ public final class RunIngestModulesAction extends AbstractAction { // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle(Bundle.RunIngestModulesAction_name()); - + if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { - String executionContext = (String)wiz.getProperty("executionContext"); //NON-NLS + String executionContext = (String) wiz.getProperty("executionContext"); //NON-NLS IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext, this.ingestType); showWarnings(ingestJobSettings); IngestManager.getInstance().queueIngestJob(this.dataSources, ingestJobSettings); @@ -103,8 +104,8 @@ public final class RunIngestModulesAction extends AbstractAction { /** * Display any warnings that the ingestJobSettings have. - * - * @param ingestJobSettings + * + * @param ingestJobSettings */ private static void showWarnings(IngestJobSettings ingestJobSettings) { List warnings = ingestJobSettings.getWarnings(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index f5e3daa60b..c02b2153f4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -38,9 +38,9 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< private List> panels; /** - * Gets the list of panels used by this wizard for iterating over. + * Gets the list of panels used by this wizard for iterating over. * Constructing it when it is null. - * + * * @return panels - the list of of WizardDescriptor panels */ private List> getPanels() { @@ -80,7 +80,6 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< return index + 1 + ". from " + getPanels().size(); } - @Override public boolean hasNext() { return (index < getPanels().size() - 1) && !current().isFinishPanel(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java index d5cade3571..3d63742c2e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/AddFileTypeSignatureDialog.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2017 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. From 8cb855e39ee86ea38c69d315b14151fa177c9d0e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 16:44:54 -0500 Subject: [PATCH 61/73] 2197 fixed unchecked conversion in getIngestProfiles --- Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index 8c4d9e0b58..5890c6bc90 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -47,7 +47,7 @@ public final class IngestProfiles { public synchronized static List getIngestProfiles() { File dir = Paths.get(PlatformUtil.getUserConfigDirectory(), PROFILE_FOLDER).toFile(); File[] directoryListing = dir.listFiles(); - List profileList = new ArrayList<>(); + List profileList = new ArrayList<>(); if (directoryListing != null) { for (File child : directoryListing) { String name = child.getName().split("\\.")[0]; From 181cca420e59941c974d959a9d65eb603e4a37f2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 16:45:53 -0500 Subject: [PATCH 62/73] 2197 formating of ingestProfiles --- Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java index 5890c6bc90..3eebf068fe 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestProfiles.java @@ -171,10 +171,10 @@ public final class IngestProfiles { * @param profile */ synchronized static void saveProfile(IngestProfile profile) { - String context = PROFILE_FOLDER + File.separator + profile.getName(); - ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName()); - ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription()); - ModuleSettings.setConfigSetting(context, PROFILE_FILTER_KEY, profile.getFileIngestFilter()); + String context = PROFILE_FOLDER + File.separator + profile.getName(); + ModuleSettings.setConfigSetting(context, PROFILE_NAME_KEY, profile.getName()); + ModuleSettings.setConfigSetting(context, PROFILE_DESC_KEY, profile.getDescription()); + ModuleSettings.setConfigSetting(context, PROFILE_FILTER_KEY, profile.getFileIngestFilter()); } } } From 2e28f72d85f859c52d710c36c2f640c39e99045f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 17:07:37 -0500 Subject: [PATCH 63/73] 2198 removed netbeans warning regarding method which could be overridden --- .../org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 9d5e845721..b3e445daa8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -60,6 +60,8 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; */ public final class IngestJobSettingsPanel extends javax.swing.JPanel { + @Messages("IngestJobSettingsPanel.name.text=Configure Ingest Modules") + private static final long serialVersionUID = 1L; private static ImageIcon warningIcon = new ImageIcon(IngestJobSettingsPanel.class.getResource("/org/sleuthkit/autopsy/images/warning_triangle.png")); private static ImageIcon infoIcon = new ImageIcon(IngestJobSettingsPanel.class.getResource("/org/sleuthkit/autopsy/images/information-frame.png")); @@ -84,7 +86,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { initComponents(); customizeComponents(); fileIngestFilterComboBox.setSelectedItem(settings.getFileIngestFilter().getName()); - this.setName("Configure Ingest Modules"); } /** @@ -184,6 +185,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { * and jobs for which to display the history. */ pastJobsButton.setEnabled(!dataSources.isEmpty() && !ingestJobs.isEmpty()); + this.setName(Bundle.IngestJobSettingsPanel_name_text()); } void setPastJobsButtonVisible(boolean isVisible) { From cd82f49d45a15e9869b60fded558b657eae929d6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 17:12:15 -0500 Subject: [PATCH 64/73] 2199 resolve conflicts from merge and fix formatting on modified files --- .../AddImageWizardAddingProgressPanel.java | 2 +- .../AddImageWizardChooseDataSourcePanel.java | 2 +- .../AddImageWizardIngestConfigPanel.java | 3 +- .../casemodule/AddImageWizardIterator.java | 29 ++++++-------- .../ingest/IngestJobSettingsPanel.java | 2 +- .../IngestProfileSelectionWizardPanel.java | 15 ++++--- .../RunIngestModulesWizardIterator.java | 13 ++---- .../ShortcutWizardDescriptorPanel.java | 40 ++++++++++--------- 8 files changed, 49 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 50134fa88a..c39e541f25 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 259cb4f4d3..65847a6eba 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index a37df4227a..e137875e1a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -216,7 +216,6 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { } } - @Override public void processThisPanelBeforeSkipped() { if (!(ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()) == null) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index 51aaab6313..8616f5bc67 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,12 +22,11 @@ import java.awt.Component; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; -import java.util.TreeMap; import javax.swing.JComponent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.ingest.IngestProfileMap; +import org.sleuthkit.autopsy.ingest.IngestProfiles; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.IngestProfileSelectionWizardPanel; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; @@ -42,7 +41,7 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator profileMap = new IngestProfileMap().getIngestProfileMap(); - if (!profileMap.isEmpty()) { - panels.add(profileSelectionPanel); + List profiles = IngestProfiles.getIngestProfiles(); + if (!profiles.isEmpty()) { + panels.add(new IngestProfileSelectionWizardPanel(AddImageWizardIngestConfigPanel.class.getCanonicalName(), getPropLastprofileName())); } panels.add(ingestConfigPanel); panels.add(progressPanel); @@ -100,25 +98,24 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator listeners = new HashSet<>(1); private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS /** @@ -57,15 +55,16 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP String getDefaultContext() { return defaultContext; } - + /** * Gets the name of the file which stores the last profile used properties. - * + * * @return the LAST_PROFILE_PROPERTIES_FILE */ public static String getLastProfilePropertiesFile() { return LAST_PROFILE_PROPERTIES_FILE; } + // Get the visual component for the panel. In this template, the component // is kept separate. This can be more efficient: if the wizard is created // but never displayed, or not all panels are displayed, it is better to @@ -139,9 +138,9 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP public boolean skipNextPanel() { return component.isLastPanel; } - + @Override - public boolean panelEnablesSkipping(){ - return true; - } + public boolean panelEnablesSkipping() { + return true; + } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index 21db01eb8b..ca242095fd 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -46,16 +46,9 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< private List getPanels() { if (panels == null) { panels = new ArrayList<>(); -<<<<<<< HEAD - IngestProfileSelectionWizardPanel profilePanel = new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext(), PROP_LASTPROFILE_NAME); - TreeMap profileMap = new IngestProfileMap().getIngestProfileMap(); - if (!profileMap.isEmpty()) { - panels.add(profilePanel); -======= List profiles = IngestProfiles.getIngestProfiles(); if (!profiles.isEmpty()) { - panels.add( new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext(), PROP_LASTPROFILE_NAME)); ->>>>>>> c4c7cbb9f8c52b7aa09e9e4f83ecbfe599dd2254 + panels.add(new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext(), PROP_LASTPROFILE_NAME)); } panels.add(new IngestModulesConfigWizardPanel()); @@ -89,8 +82,8 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< @Override public boolean hasNext() { - return (index < getPanels().size() - 1 && - !(current().panelEnablesSkipping() && current().skipNextPanel())); + return (index < getPanels().size() - 1 + && !(current().panelEnablesSkipping() && current().skipNextPanel())); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java index 35c9cf7705..589ebdee14 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/ShortcutWizardDescriptorPanel.java @@ -21,44 +21,48 @@ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; import org.openide.WizardDescriptor; /** - * An abstract class providing a methods which can be checked by - * the iterator containing panels of this type. So that Wizards containing these - * panels can skip panels, but still call necessary methods of those panels. + * An abstract class providing a methods which can be checked by the iterator + * containing panels of this type. So that Wizards containing these panels can + * skip panels, but still call necessary methods of those panels. */ public abstract class ShortcutWizardDescriptorPanel implements WizardDescriptor.Panel { - + /** - * Whether or not this panel under the correct conditions can enable the skipping of the panel after it. + * Whether or not this panel under the correct conditions can enable the + * skipping of the panel after it. + * * @return true or false */ - public boolean panelEnablesSkipping(){ - /* - * This method should be overriden by any panel that might want to + public boolean panelEnablesSkipping() { + /* + * This method should be overriden by any panel that might want to * enable the iterator to skip the panel that comes after it. */ return false; } - + /** - * Whether or not the panel immediately following this one should be skipped . - * + * Whether or not the panel immediately following this one should be skipped + * . + * * @return true or false */ - public boolean skipNextPanel(){ + public boolean skipNextPanel() { /* - * This method should be overriden by any panel that might want to + * This method should be overriden by any panel that might want to * enable the iterator to skip the panel that comes after it. */ return false; } - + /** - * Provides a method which will allow code to be executed in a panel you plan to skip + * Provides a method which will allow code to be executed in a panel you + * plan to skip */ - public void processThisPanelBeforeSkipped(){ + public void processThisPanelBeforeSkipped() { /* - * If you need to perform some actions of this panel before it is skipped - * override this method to have it call the necessary code. + * If you need to perform some actions of this panel before it is + * skipped override this method to have it call the necessary code. */ } } From b9b02e1beddff1907f1c74f2ce189439223c75ee Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 19:08:43 -0500 Subject: [PATCH 65/73] 2197 fixed encapsulation issue regarding enabled modules list --- .../org/sleuthkit/autopsy/ingest/IngestJobSettings.java | 9 ++++----- .../org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java | 6 ++---- .../sleuthkit/autopsy/ingest/ProfileSettingsPanel.java | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index f3c9f520d2..9fc5442371 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -398,7 +398,7 @@ public class IngestJobSettings { * * @return The list of module names associated with the key. */ - static HashSet getModulesNamesFromSetting(String context, String key, String defaultSetting) { + private static HashSet getModulesNamesFromSetting(String context, String key, String defaultSetting) { if (ModuleSettings.settingExists(context, key) == false) { ModuleSettings.setConfigSetting(context, key, defaultSetting); } @@ -435,13 +435,12 @@ public class IngestJobSettings { * Get a set which contains all the names of enabled modules for the * specified context. * - * @param defaultSetting - The default list of module names. - * @param context -the execution context (profile name) to check + * @param context -the execution context (profile name) to check * * @return the names of the enabled modules */ - static HashSet getEnabledModules(String context, String defaultSetting) { - return getModulesNamesFromSetting(context, ENABLED_MODULES_KEY, defaultSetting); + static List getEnabledModules(String context) { + return new ArrayList<>(getModulesNamesFromSetting(context, ENABLED_MODULES_KEY, "")); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 42d94674e9..ca1ee1f498 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -39,9 +39,8 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti "IngestOptionsPanel.fileFiltersTab.text=File Filters", "IngestOptionsPanel.fileFiltersTab.toolTipText=Settings for creating and editing ingest file filters.", "IngestOptionsPanel.profilesTab.text=Profiles", - "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles.", - "IngestOptionsPanel.title.text=Ingest" - }) + "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles."}) + private FilesSetDefsPanel filterPanel; private IngestSettingsPanel settingsPanel; private ProfileSettingsPanel profilePanel; @@ -59,7 +58,6 @@ class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implements Opti } private void customizeComponents() { - setName(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.title.text")); filterPanel = new FilesSetDefsPanel(PANEL_TYPE.FILE_INGEST_FILTERS); settingsPanel = new IngestSettingsPanel(); profilePanel = new ProfileSettingsPanel(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 50e0a818ab..7cac1db1e1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -424,7 +424,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op filterDescArea.setText(NbBundle.getMessage(ProfileSettingsPanel.class, "ProfileSettingsPanel.messages.filterLoadFailed")); } selectedModulesArea.setText(""); - for (String moduleName : IngestJobSettings.getEnabledModules(selectedProfile.getName(), "")) { + for (String moduleName : IngestJobSettings.getEnabledModules(selectedProfile.getName())) { selectedModulesArea.append(moduleName + "\n"); } From efef1b80771cef4d6aad4305f22e741858ef477a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Feb 2017 19:33:18 -0500 Subject: [PATCH 66/73] 2198 changed overridable methods to be used outside of constructor --- .../autopsy/casemodule/AddImageWizardIngestConfigPanel.java | 5 ++++- .../sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java | 3 --- .../IngestModulesConfigWizardPanel.java | 5 ++++- .../runIngestModuleWizard/IngestProfileSelectionPanel.java | 6 ------ .../IngestProfileSelectionWizardPanel.java | 4 ++++ 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 6291ff7521..d217e740ec 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -30,8 +30,10 @@ import javax.swing.JButton; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeListener; +import org.omg.CORBA.BAD_CONTEXT; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; @@ -47,7 +49,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager; * 3rd panel( {@link AddImageWizardAddingProgressPanel}) separate class -jm */ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - + @Messages("AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules") private final IngestJobSettingsPanel ingestJobSettingsPanel; /** @@ -79,6 +81,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - + + @NbBundle.Messages("IngestModulesConfigWizardPanel.name.text=Configure Ingest Modules") /** * The visual ingestJobSettingsPanel that displays this panel. If you need * to access the ingestJobSettingsPanel from this class, just use @@ -42,6 +44,7 @@ class IngestModulesConfigWizardPanel implements WizardDescriptor.FinishablePanel if (ingestJobSettingsPanel == null) { ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModulesAction.getDefaultContext())); } + ingestJobSettingsPanel.setName(Bundle.IngestModulesConfigWizardPanel_name_text()); return ingestJobSettingsPanel; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index cb0868d068..469ac94791 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; final class IngestProfileSelectionPanel extends JPanel implements ItemListener { @Messages({"IngestProfileSelectionPanel.customSettings.name=Custom Settings", - "IngestProfileSelectionPanel.name=Ingest Profile Selection", "IngestProfileSelectionPanel.customSettings.description=configure individual module settings in next step of wizard"}) private static final String CUSTOM_SETTINGS_DISPLAY_NAME = Bundle.IngestProfileSelectionPanel_customSettings_name(); @@ -61,11 +60,6 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { wizardPanel = panel; selectedProfile = lastSelectedProfile; populateListOfCheckboxes(); - customizePanel(); - } - - private void customizePanel() { - this.setName(Bundle.IngestProfileSelectionPanel_name()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index 980dc5af94..ed164a585b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -24,6 +24,7 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** @@ -33,6 +34,8 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePanel { + @Messages("IngestProfileWizardPanel.panelName=Ingest Profile Selection") + private final Set listeners = new HashSet<>(1); private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS @@ -57,6 +60,7 @@ class IngestProfileSelectionWizardPanel implements WizardDescriptor.FinishablePa lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, PROP_LASTPROFILE_NAME); } component = new IngestProfileSelectionPanel(this, lastProfileUsed); + component.setName(Bundle.IngestProfileWizardPanel_panelName()); } return component; } From 6c3d2804243f607a02d2cd37a9d0d1bfac28b42d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 15 Feb 2017 11:19:10 -0500 Subject: [PATCH 67/73] 2199 fixed bug with highlighting of proper step in AddImageWizard --- .../AddImageWizardIngestConfigPanel.java | 33 +++++++++---------- .../IngestModulesConfigWizardPanel.java | 3 +- .../IngestProfileSelectionPanel.java | 1 - .../IngestProfileSelectionWizardPanel.java | 23 ++++++------- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 9e970ffd97..ce4aa13c89 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -30,7 +30,6 @@ import javax.swing.JButton; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeListener; -import org.omg.CORBA.BAD_CONTEXT; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; @@ -55,7 +54,6 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { @Messages("AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules") private IngestJobSettingsPanel ingestJobSettingsPanel; - /** * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). @@ -80,11 +78,12 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { this.addImageAction = action; this.progressPanel = proPanel; this.dataSourcePanel = dsPanel; - - IngestJobSettings ingestJobSettings = new IngestJobSettings(lastProfileUsed); + IngestJobSettings ingestJobSettings = new IngestJobSettings(AddImageWizardIngestConfigPanel.class.getCanonicalName()); showWarnings(ingestJobSettings); + //When this panel is viewed by the user it will always be displaying the + //IngestJobSettingsPanel with the AddImageWizardIngestConfigPanel.class.getCanonicalName(); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); - this.ingestJobSettingsPanel.setName(Bundle.AddImageWizardIngestConfigPanel_name_text()); + } /** @@ -99,6 +98,7 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { public Component getComponent() { if (component == null) { component = new AddImageWizardIngestConfigVisual(this.ingestJobSettingsPanel); + component.setName(Bundle.AddImageWizardIngestConfigPanel_name_text()); } return component; } @@ -166,23 +166,13 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { */ @Override public void readSettings(WizardDescriptor settings) { - if (!(ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()) == null) - && !ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()).isEmpty()) { - lastProfileUsed = ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()); - } - IngestJobSettings ingestJobSettings = new IngestJobSettings(lastProfileUsed); - showWarnings(ingestJobSettings); - this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); - component = new AddImageWizardIngestConfigVisual(this.ingestJobSettingsPanel); JButton cancel = new JButton( NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text")); cancel.setEnabled(false); settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, cancel}); cleanupTask = null; readyToIngest = false; - newContents.clear(); - // Start processing the data source by handing it off to the selected DSP, // so it gets going in the background while the user is still picking the Ingest modules startDataSourceProcessing(); @@ -199,8 +189,7 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { */ @Override public void storeSettings(WizardDescriptor settings) { - - IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); + IngestJobSettings ingestJobSettings = ingestJobSettingsPanel.getSettings(); ingestJobSettings.save(); showWarnings(ingestJobSettings); @@ -220,15 +209,23 @@ class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { } } + /** + * Loads the proper settings for this panel to use the previously selected + * Ingest profile when this panel would be skipped due to a profile being + * chosen. + */ @Override public void processThisPanelBeforeSkipped() { if (!(ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()) == null) && !ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()).isEmpty()) { lastProfileUsed = ModuleSettings.getConfigSetting(IngestProfileSelectionWizardPanel.getLastProfilePropertiesFile(), AddImageWizardIterator.getPropLastprofileName()); } + //Because this panel kicks off ingest during the wizard we need to + //swap out the ingestJobSettings for the ones of the chosen profile before + //we start processing IngestJobSettings ingestJobSettings = new IngestJobSettings(lastProfileUsed); + ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); showWarnings(ingestJobSettings); - this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); component = new AddImageWizardIngestConfigVisual(this.ingestJobSettingsPanel); readyToIngest = true; startDataSourceProcessing(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java index 1ed524998b..0124db327b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; +import java.awt.Component; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; @@ -42,7 +43,7 @@ class IngestModulesConfigWizardPanel extends ShortcutWizardDescriptorPanel { // but never displayed, or not all panels are displayed, it is better to // create only those which really need to be visible. @Override - public IngestJobSettingsPanel getComponent() { + public Component getComponent() { if (ingestJobSettingsPanel == null) { ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModulesAction.getDefaultContext())); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 70c0d8056d..30c137e99d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -22,7 +22,6 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JPanel; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index b30f878733..08c416998e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; +import java.awt.Component; import java.util.HashSet; import java.util.Set; import javax.swing.event.ChangeEvent; @@ -39,10 +40,10 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP private final Set listeners = new HashSet<>(1); private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS /** - * The visual component that displays this panel. If you need to access the - * component from this class, just use getComponent(). + * The visual ingestProfileSelectionPanel that displays this panel. If you need to access the + ingestProfileSelectionPanel from this class, just use getComponent(). */ - private IngestProfileSelectionPanel component; + private IngestProfileSelectionPanel ingestProfileSelectionPanel; private String lastProfileUsed; private final String lastProfilePropertyName; private final String defaultContext; @@ -68,23 +69,23 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP return LAST_PROFILE_PROPERTIES_FILE; } - // Get the visual component for the panel. In this template, the component + // Get the visual ingestProfileSelectionPanel for the panel. In this template, the ingestProfileSelectionPanel // is kept separate. This can be more efficient: if the wizard is created // but never displayed, or not all panels are displayed, it is better to // create only those which really need to be visible. @Override - public IngestProfileSelectionPanel getComponent() { - if (component == null) { + public Component getComponent() { + if (ingestProfileSelectionPanel == null) { if (!(ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName) == null) && !ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName).isEmpty()) { lastProfileUsed = ModuleSettings.getConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName); } else { lastProfileUsed = getDefaultContext(); } - component = new IngestProfileSelectionPanel(this, lastProfileUsed); - component.setName(Bundle.IngestProfileWizardPanel_panelName()); + ingestProfileSelectionPanel = new IngestProfileSelectionPanel(this, lastProfileUsed); + ingestProfileSelectionPanel.setName(Bundle.IngestProfileWizardPanel_panelName()); } - return component; + return ingestProfileSelectionPanel; } @Override @@ -133,14 +134,14 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP @Override public void storeSettings(WizardDescriptor wiz) { - lastProfileUsed = component.getLastSelectedProfile(); + lastProfileUsed = ingestProfileSelectionPanel.getLastSelectedProfile(); wiz.putProperty("executionContext", lastProfileUsed); //NON-NLS ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName, lastProfileUsed); } @Override public boolean skipNextPanel() { - return component.isLastPanel; + return ingestProfileSelectionPanel.isLastPanel; } @Override From 773cf2619898289e6950e7325ea27a752b543cfa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 15 Feb 2017 12:18:35 -0500 Subject: [PATCH 68/73] 2199 Formatting, copyright, and netbeans tips resolution --- .../AddImageWizardAddingProgressPanel.java | 4 ++-- .../AddImageWizardChooseDataSourcePanel.java | 8 +++----- .../casemodule/AddImageWizardIterator.java | 4 ++-- .../MultiUserSettingsPanelController.java | 2 +- .../datamodel/VirtualDirectoryNode.java | 2 +- .../DirectoryTreeTopComponent.java | 8 ++++++-- .../ExternalViewerOptionsPanelController.java | 10 +++++----- .../ingest/IngestOptionsPanelController.java | 2 +- .../autopsy/ingest/IngestTasksScheduler.java | 3 +-- .../IngestModulesConfigWizardPanel.java | 3 +-- .../IngestProfileSelectionWizardPanel.java | 5 +++-- ...FileExtMismatchOptionsPanelController.java | 18 ++++++++++++++++-- .../FileTypeIdOptionsPanelController.java | 19 ++++++++++++++++--- .../HashDatabaseOptionsPanelController.java | 2 +- .../modules/interestingitems/FilesSet.java | 2 +- .../interestingitems/FilesSetDefsPanel.java | 2 +- ...restingItemDefsOptionsPanelController.java | 2 +- 17 files changed, 62 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index c39e541f25..8b1a4dd1e0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -54,7 +54,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { private AddImageWizardAddingProgressVisual component; private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 - private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl(); + private final DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl(); public DSPProgressMonitorImpl getDSPProgressMonitorImpl() { return dspProgressMonitorImpl; @@ -193,7 +193,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { protected final void fireChangeEvent() { Iterator it; synchronized (listeners) { - it = new HashSet(listeners).iterator(); + it = new HashSet<>(listeners).iterator(); } ChangeEvent ev = new ChangeEvent(this); while (it.hasNext()) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 65847a6eba..3d58017ecb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -45,7 +45,7 @@ class AddImageWizardChooseDataSourcePanel extends ShortcutWizardDescriptorPanel * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). */ - private AddImageWizardAddingProgressPanel progressPanel; + private final AddImageWizardAddingProgressPanel progressPanel; private AddImageWizardChooseDataSourceVisual component; private boolean isNextEnable = false; private static final String PROP_LASTDATASOURCE_PATH = "LBL_LastDataSource_PATH"; //NON-NLS @@ -123,7 +123,7 @@ class AddImageWizardChooseDataSourcePanel extends ShortcutWizardDescriptorPanel isNextEnable = isEnabled; fireChangeEvent(); } - private final Set listeners = new HashSet(1); // or can use ChangeSupport in NB 6.0 + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 /** * Adds a listener to changes of the panel's validity. @@ -156,7 +156,7 @@ class AddImageWizardChooseDataSourcePanel extends ShortcutWizardDescriptorPanel protected final void fireChangeEvent() { Iterator it; synchronized (listeners) { - it = new HashSet(listeners).iterator(); + it = new HashSet<>(listeners).iterator(); } ChangeEvent ev = new ChangeEvent(this); while (it.hasNext()) { @@ -219,8 +219,6 @@ class AddImageWizardChooseDataSourcePanel extends ShortcutWizardDescriptorPanel */ @Override public void storeSettings(WizardDescriptor settings) { - - return; } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index 8616f5bc67..3dafa75479 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -38,7 +38,7 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator panels; - private AddImageAction action; + private final AddImageAction action; private int progressPanelIndex; private final static String PROP_LASTPROFILE_NAME = "AIW_LASTPROFILE_NAME"; //NON-NLS @@ -74,7 +74,7 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 40f14bf63a..8a056b2318 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -48,7 +48,7 @@ import org.sleuthkit.datamodel.VirtualDirectory; */ public class VirtualDirectoryNode extends AbstractAbstractFileNode { - private static Logger logger = Logger.getLogger(VirtualDirectoryNode.class.getName()); + private static final Logger logger = Logger.getLogger(VirtualDirectoryNode.class.getName()); //prefix for special VirtualDirectory root nodes grouping local files public final static String LOGICAL_FILE_SET_PREFIX = "LogicalFileSet"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 22b4677c36..4cbf5fa283 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -297,6 +297,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * only, i.e. deserialization routines; otherwise you could get a * non-deserialized instance. To obtain the singleton instance, use * {@link #findInstance}. + * + * @return instance - the default instance */ public static synchronized DirectoryTreeTopComponent getDefault() { if (instance == null) { @@ -308,6 +310,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat /** * Obtain the DirectoryTreeTopComponent instance. Never call * {@link #getDefault} directly! + * + * @return getDefault() - the default instance */ public static synchronized DirectoryTreeTopComponent findInstance() { WindowManager winManager = WindowManager.getDefault(); @@ -667,7 +671,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat try { displayName = content.getUniquePath(); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: " + originNode); //NON-NLS + LOGGER.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: {0}", originNode); //NON-NLS } } else if (originNode.getLookup().lookup(String.class) != null) { displayName = originNode.getLookup().lookup(String.class); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java index 5df5b89e56..ee65dfbf1c 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerOptionsPanelController.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011-2016 Basis Technology Corp. + * + * Copyright 2011-2017 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. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java index b9c4ea9546..9c908d9ebb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanelController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java index f7c32930c0..a9ad8c7634 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2016 Basis Technology Corp. + * Copyright 2012-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,6 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java index 0124db327b..c330df974e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java @@ -26,9 +26,8 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; - class IngestModulesConfigWizardPanel extends ShortcutWizardDescriptorPanel { - + @NbBundle.Messages("IngestModulesConfigWizardPanel.name.text=Configure Ingest Modules") /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index 08c416998e..207e577bf1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -40,8 +40,9 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP private final Set listeners = new HashSet<>(1); private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS /** - * The visual ingestProfileSelectionPanel that displays this panel. If you need to access the - ingestProfileSelectionPanel from this class, just use getComponent(). + * The visual ingestProfileSelectionPanel that displays this panel. If you + * need to access the ingestProfileSelectionPanel from this class, just use + * getComponent(). */ private IngestProfileSelectionPanel ingestProfileSelectionPanel; private String lastProfileUsed; diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java index 93eef3c0a0..be5d476c5b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchOptionsPanelController.java @@ -1,6 +1,20 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.modules.fileextmismatch; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java index 434e17d463..624cdb747c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.modules.filetypeid; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java index c2c52a4097..cd320258ce 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDatabaseOptionsPanelController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java index cbb3576b41..6fb44839b5 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 184b5d8b46..b4743bd360 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java index 7280f3b7ab..3a579d7b51 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemDefsOptionsPanelController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 8909d4e1a17f35bdb2152446deb77dfc199e8e92 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 15 Feb 2017 14:51:42 -0500 Subject: [PATCH 69/73] 2198 multi line descriptions enabled for radio button scroll window --- .../IngestProfileSelectionPanel.form | 6 +- .../IngestProfileSelectionPanel.java | 60 +++++++++++++++---- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form index 76c5f52c5d..b5442660c1 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.form @@ -1,6 +1,6 @@ - + @@ -87,9 +87,7 @@ - - - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 469ac94791..7be4dcdc5f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -18,16 +18,21 @@ */ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; +import java.awt.Color; import java.awt.Component; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static javax.swing.Box.createVerticalGlue; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; +import javax.swing.JTextArea; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; import org.sleuthkit.autopsy.ingest.IngestOptionsPanel; @@ -59,6 +64,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { initComponents(); wizardPanel = panel; selectedProfile = lastSelectedProfile; + populateListOfCheckboxes(); } @@ -77,10 +83,30 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { */ private void populateListOfCheckboxes() { profiles = getProfiles(); - addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModulesAction.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION); + GridBagLayout gridBagLayout = new GridBagLayout(); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weighty = .0; + constraints.anchor = GridBagConstraints.FIRST_LINE_START; + + addRadioButton(CUSTOM_SETTINGS_DISPLAY_NAME, RunIngestModulesAction.getDefaultContext(), CUSTOM_SETTINGS_DESCRIPTION, gridBagLayout, constraints); for (IngestProfile profile : profiles) { - addRadioButton(profile.toString(), profile.toString(), profile.getDescription()); + constraints.weightx = 0; + constraints.gridy++; + constraints.gridx = 0; + addRadioButton(profile.toString(), profile.toString(), profile.getDescription(), gridBagLayout, constraints); } + //Add vertical glue at the bottom of the scroll panel so spacing + //between elements is less dependent on the number of elements + constraints.gridy++; + constraints.gridx = 0; + constraints.weighty = 1; + Component vertGlue = createVerticalGlue(); + profileListPanel.add(vertGlue); + gridBagLayout.setConstraints(vertGlue, constraints); + profileListPanel.setLayout(gridBagLayout); } /** @@ -92,19 +118,29 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { * programmatically * @param profileDesc - the description of the profile */ - private void addRadioButton(String profileDisplayName, String profileContextName, String profileDesc) { + private void addRadioButton(String profileDisplayName, String profileContextName, String profileDesc, GridBagLayout layout, GridBagConstraints constraints) { String displayText = profileDisplayName + " - " + profileDesc; - JRadioButton myRadio = new JRadioButton(displayText); + JRadioButton myRadio = new JRadioButton(); + //Using a JTextArea as though it is a label in order to get multi-line support + JTextArea myLabel = new JTextArea(displayText); + Color gray = new Color(240, 240, 240); //matches background of panel + myLabel.setBackground(gray); + myLabel.setEditable(false); + myLabel.setWrapStyleWord(true); + myLabel.setLineWrap(true); myRadio.setName(profileContextName); myRadio.setToolTipText(profileDesc); myRadio.addItemListener(this); if (profileContextName.equals(selectedProfile)) { myRadio.setSelected(true); } - profileListButtonGroup.add(myRadio); profileListPanel.add(myRadio); - + layout.setConstraints(myRadio, constraints); + constraints.gridx++; + constraints.weightx = 1; + profileListPanel.add(myLabel); + layout.setConstraints(myLabel, constraints); } /** @@ -154,7 +190,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { profileListScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); profileListPanel.setAutoscrolls(true); - profileListPanel.setLayout(new javax.swing.BoxLayout(profileListPanel, javax.swing.BoxLayout.PAGE_AXIS)); + profileListPanel.setLayout(new java.awt.GridBagLayout()); profileListScrollPane.setViewportView(profileListPanel); org.openide.awt.Mnemonics.setLocalizedText(profileListLabel, org.openide.util.NbBundle.getMessage(IngestProfileSelectionPanel.class, "IngestProfileSelectionPanel.profileListLabel.text")); // NOI18N @@ -230,10 +266,12 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { @Override public void itemStateChanged(ItemEvent e) { for (Component rButton : profileListPanel.getComponents()) { + if (rButton instanceof JRadioButton){ JRadioButton jrb = (JRadioButton) rButton; - if (jrb.isSelected()) { - selectedProfile = jrb.getName(); - break; + if (jrb.isSelected()) { + selectedProfile = jrb.getName(); + break; + } } } boolean wasLastPanel = isLastPanel; From 7b634fbad9f4353aad4ec00a0648c53b723404f7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 15 Feb 2017 16:38:00 -0500 Subject: [PATCH 70/73] 2198- made Ingest Options panel save and load filters in a more logical manner --- .../autopsy/ingest/IngestOptionsPanel.java | 26 +++++++++++-------- .../autopsy/ingest/ProfileSettingsPanel.java | 16 ------------ 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 7ee74a726e..28bf7a623e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -42,8 +42,11 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen "IngestOptionsPanel.profilesTab.toolTipText=Settings for creating and editing profiles."}) private FilesSetDefsPanel filterPanel; + private final static int INDEX_OF_FILTER_PANEL = 0; private IngestSettingsPanel settingsPanel; + private final static int INDEX_OF_SETTINGS_PANEL = 2; private ProfileSettingsPanel profilePanel; + private final static int INDEX_OF_PROFILE_PANEL = 1; /** * This panel implements a property change listener that listens to ingest * job events so it can disable the buttons on the panel if ingest is @@ -63,11 +66,11 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen profilePanel = new ProfileSettingsPanel(); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.text"), null, - filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), 0); + filterPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.fileFiltersTab.toolTipText"), INDEX_OF_FILTER_PANEL); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.text"), null, - profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), 1); + profilePanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.profilesTab.toolTipText"), INDEX_OF_PROFILE_PANEL); tabbedPane.insertTab(NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.text"), null, - settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), 2); + settingsPanel, NbBundle.getMessage(IngestOptionsPanel.class, "IngestOptionsPanel.settingsTab.toolTipText"), INDEX_OF_SETTINGS_PANEL); //Listener for when tabbed panes are switched, because we can have two file filter definitions panels open at the same time //we may wind up in a situation where the user has created and saved one in the profiles panel //so we need to refresh the filterPanel in those cases before proceeding. @@ -75,10 +78,15 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen @Override public void stateChanged(ChangeEvent e) { if (e.getSource() instanceof JTabbedPane) { - profilePanel.shouldFiltersBeRefreshed(); - { - filterPanel.load(); - } + //because we can have two filterPanels open at the same time + //we need to save the settings when we change tabs otherwise + //they could be overwritten with out of date + if (tabbedPane.getSelectedIndex() == INDEX_OF_FILTER_PANEL) { + filterPanel.load(); + } + else { + filterPanel.saveSettings(); + } } } }); @@ -152,10 +160,6 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen */ @Override public void saveSettings() { - //if a new filter was created in the profilePanel we don't want to save over it accidently - if (profilePanel.shouldFiltersBeRefreshed()) { - filterPanel.load(); - } filterPanel.store(); settingsPanel.store(); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index 1b1fbc40c0..1db29f0b5f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -51,7 +51,6 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op private final DefaultListModel profilesListModel; private Map profiles; private ProfilePanel panel; - private boolean filtersShouldBeRefreshed; /** * Creates new form ProfileOptionsPanel @@ -59,7 +58,6 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op ProfileSettingsPanel() { this.profilesListModel = new DefaultListModel<>(); initComponents(); - this.filtersShouldBeRefreshed = false; this.profileList.setModel(profilesListModel); this.profileList.addListSelectionListener(new ProfileSettingsPanel.ProfileListSelectionListener()); ingestWarningLabel.setVisible(false); @@ -275,20 +273,6 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteProfileButtonActionPerformed - /** - * Returns whether there were possible changes to the filter list since the - * last time this was called. - * - * Resets value to false after being called. - * - * @return true or false - */ - boolean shouldFiltersBeRefreshed() { - boolean shouldRefresh = filtersShouldBeRefreshed; - filtersShouldBeRefreshed = false; - return shouldRefresh; - } - /** * Enable / disable buttons, so they can be disabled while ingest is * running. From 53d687a740a443328f788acae5caa5318f100ad8 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 15 Feb 2017 17:46:40 -0500 Subject: [PATCH 71/73] Fix logging error message for PhotoRecCarver --- .../modules/photoreccarver/PhotoRecCarverOutputParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java index ca42256063..01d19b84d1 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java @@ -157,7 +157,7 @@ class PhotoRecCarverOutputParser { } return fileManager.addCarvedFiles(new CarvingResult(af, carvedFiles)); } catch (NumberFormatException | TskCoreException ex) { - logger.log(Level.SEVERE, "Error parsing PhotoRec output and inserting it into the database: {0}", ex); //NON-NLS + logger.log(Level.SEVERE, "Error parsing PhotoRec output and inserting it into the database", ex); //NON-NLS } List empty = Collections.emptyList(); From d98d80f031f46be0aad4a92c2e5266504acbc44a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 17 Feb 2017 15:32:24 -0500 Subject: [PATCH 72/73] 2306 File Types Tree will no longer blow up and disappear with non standard mimeTypes --- .../org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index cbe842ec70..7a040847ef 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -147,7 +147,9 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi final String mime_type = resultSet.getString("mime_type"); //NON-NLS if (!mime_type.isEmpty()) { String mimeType[] = mime_type.split("/"); - if (!mimeType[0].isEmpty() && !mimeType[1].isEmpty()) { + //Note: Users are able to define custom mime types in Autopsy that do not + //contain a "/" or possibly have multiple slashes + if (mimeType.length > 1 && !mimeType[0].isEmpty() && !mimeType[1].isEmpty()) { if (!existingMimeTypes.containsKey(mimeType[0])) { existingMimeTypes.put(mimeType[0], new ArrayList<>()); } From 3a6738324c783a44fb16e7f605ccc247279e3206 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 17 Feb 2017 16:09:05 -0500 Subject: [PATCH 73/73] Fix Run Ingest Module wizard bugs --- .../DirectoryTreeFilterNode.java | 96 +++++++------------ .../IngestModulesConfigWizardPanel.java | 52 ++++++---- .../IngestProfileSelectionPanel.java | 68 ++++++------- .../IngestProfileSelectionWizardPanel.java | 35 ++++--- .../RunIngestModulesAction.java | 57 +++++++---- .../RunIngestModulesWizardIterator.java | 83 ++++++++-------- .../HashLookupModuleSettingsPanel.java | 8 +- 7 files changed, 208 insertions(+), 191 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index d5786333aa..8c2595969a 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.directorytree; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.Action; @@ -29,7 +30,6 @@ import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractContentNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -39,69 +39,75 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.VirtualDirectory; /** - * This class sets the actions for the nodes in the directory tree and creates - * the children filter so that files and such are hidden from the tree. - * + * A node filter (decorator) that sets the actions for the nodes in the + * directory tree and wraps the node children with a + * DirectoryTreeFilterChildren. */ class DirectoryTreeFilterNode extends FilterNode { - private static final Action collapseAll = new CollapseAction( - NbBundle.getMessage(DirectoryTreeFilterNode.class, "DirectoryTreeFilterNode.action.collapseAll.text")); - private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName()); + private static final Action collapseAllAction = new CollapseAction(NbBundle.getMessage(DirectoryTreeFilterNode.class, "DirectoryTreeFilterNode.action.collapseAll.text")); /** - * the constructor + * A node filter (decorator) that sets the actions for the nodes in the + * directory tree and wraps the node children with a + * DirectoryTreeFilterChildren. + * + * @param nodeToWrap The node to wrap. + * @param createChildren Whether to create the children of the wrapped node + * or treat it a a leaf node. */ - DirectoryTreeFilterNode(Node arg, boolean createChildren) { - super(arg, DirectoryTreeFilterChildren.createInstance(arg, createChildren), - new ProxyLookup(Lookups.singleton(new OriginalNode(arg)), - arg.getLookup())); + DirectoryTreeFilterNode(Node nodeToWrap, boolean createChildren) { + super(nodeToWrap, + DirectoryTreeFilterChildren.createInstance(nodeToWrap, createChildren), + new ProxyLookup(Lookups.singleton(new OriginalNode(nodeToWrap)), nodeToWrap.getLookup())); } + /** + * Gets the display name for the node, possibly including a child count in + * parentheses. + * + * @return The display name for the node. + */ @Override public String getDisplayName() { final Node orig = getOriginal(); - String name = orig.getDisplayName(); - - //do not show children counts for non content nodes if (orig instanceof AbstractContentNode) { - //show only for file content nodes AbstractFile file = getLookup().lookup(AbstractFile.class); if (file != null) { try { final int numChildren = file.getChildrenCount(); + /* + * Left-to-right marks here are necessary to keep the count + * and parens together for mixed right-to-left and + * left-to-right names. + */ + name = name + " \u200E(\u200E" + numChildren + ")\u200E"; //NON-NLS - // left-to-right marks here are necessary to keep the count and parens together - // for mixed right-to-left and left-to-right names - name = name + " \u200E(\u200E" + numChildren + ")\u200E"; } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting children count to display for file: " + file, ex); //NON-NLS } - } } - return name; } /** - * Right click action for the nodes in the directory tree. + * Gets the context mneu (right click menu) actions for the node. * - * @param popup + * @param context Whether to find actions for context meaning or for the + * node itself. * * @return */ @Override - public Action[] getActions(boolean popup) { + public Action[] getActions(boolean context) { List actions = new ArrayList<>(); - final Content content = this.getLookup().lookup(Content.class); if (content != null) { - actions.addAll(DirectoryTreeFilterNode.getDetailActions(content)); + actions.addAll(ExplorerNodeActionVisitor.getActions(content)); - //extract dir action Directory dir = this.getLookup().lookup(Directory.class); if (dir != null) { actions.add(ExtractAction.getInstance()); @@ -109,9 +115,7 @@ class DirectoryTreeFilterNode extends FilterNode { } final Image img = this.getLookup().lookup(Image.class); - - VirtualDirectory virtualDirectory = this.getLookup().lookup(VirtualDirectory.class); - // determine if the virtualDireory is at root-level (Logical File Set). + final VirtualDirectory virtualDirectory = this.getLookup().lookup(VirtualDirectory.class); boolean isRootVD = false; if (virtualDirectory != null) { try { @@ -122,41 +126,15 @@ class DirectoryTreeFilterNode extends FilterNode { logger.log(Level.WARNING, "Error determining the parent of the virtual directory", ex); // NON-NLS } } - - // 'run ingest' action and 'file search' action are added only if the - // selected node is img node or a root level virtual directory. if (img != null || isRootVD) { - actions.add(new FileSearchAction( - NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.openFileSrcByAttr.text"))); - actions.add(new RunIngestModulesAction(dir)); + actions.add(new FileSearchAction(NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.openFileSrcByAttr.text"))); + actions.add(new RunIngestModulesAction(Collections.singletonList(content))); } } - - //check if delete actions should be added - final Node orig = getOriginal(); - //TODO add a mechanism to determine if DisplayableItemNode - if (orig instanceof DisplayableItemNode) { - actions.addAll(getDeleteActions((DisplayableItemNode) orig)); - } - - actions.add(collapseAll); + actions.add(collapseAllAction); return actions.toArray(new Action[actions.size()]); } - private static List getDeleteActions(DisplayableItemNode original) { - List actions = new ArrayList<>(); - //actions.addAll(original.accept(getDeleteActionVisitor)); - return actions; - } - - private static List getDetailActions(Content c) { - List actions = new ArrayList<>(); - - actions.addAll(ExplorerNodeActionVisitor.getActions(c)); - - return actions; - } - //FIXME: this seems like a big hack -jm public static class OriginalNode { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java index c330df974e..7f77ce2b40 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestModulesConfigWizardPanel.java @@ -26,25 +26,45 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; +/** + * A wizard panel for configuring an ingest job. + */ class IngestModulesConfigWizardPanel extends ShortcutWizardDescriptorPanel { - @NbBundle.Messages("IngestModulesConfigWizardPanel.name.text=Configure Ingest Modules") - - /** - * The visual ingestJobSettingsPanel that displays this panel. If you need - * to access the ingestJobSettingsPanel from this class, just use - * getComponent(). - */ + private final String executionContext; + private final IngestJobSettings.IngestType ingestType; private IngestJobSettingsPanel ingestJobSettingsPanel; - // Get the visual ingestJobSettingsPanel for the panel. In this template, the ingestJobSettingsPanel - // is kept separate. This can be more efficient: if the wizard is created - // but never displayed, or not all panels are displayed, it is better to - // create only those which really need to be visible. + /** + * Constructs a wizard panel for configuring an ingest job. + * + * @param executionContest The execution context for the wizard. + * @param ingestType The ingest type. + */ + IngestModulesConfigWizardPanel(String executionContest, IngestJobSettings.IngestType ingestType) { + this.executionContext = executionContest; + this.ingestType = ingestType; + } + + /** + * Gets the ingest job settings associated with this wizard panel. + * + * @return The settings, will be null if the panel has not been used in the + * wizard. + */ + IngestJobSettings getIngestJobSettings() { + return ingestJobSettingsPanel.getSettings(); + } + + @NbBundle.Messages("IngestModulesConfigWizardPanel.name.text=Configure Ingest Modules") @Override public Component getComponent() { - if (ingestJobSettingsPanel == null) { - ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(RunIngestModulesAction.getDefaultContext())); + if (null == ingestJobSettingsPanel) { + /* + * Creating an ingest job settings object is expensive, so it is + * deferred until this panel is actually used in the wizard. + */ + ingestJobSettingsPanel = new IngestJobSettingsPanel(new IngestJobSettings(executionContext, ingestType)); } ingestJobSettingsPanel.setName(Bundle.IngestModulesConfigWizardPanel_name_text()); return ingestJobSettingsPanel; @@ -52,13 +72,11 @@ class IngestModulesConfigWizardPanel extends ShortcutWizardDescriptorPanel { @Override public HelpCtx getHelp() { - // Show no Help button for this panel: return HelpCtx.DEFAULT_HELP; } @Override public boolean isValid() { - // If it is always OK to press Next or Finish, then: return true; } @@ -76,9 +94,7 @@ class IngestModulesConfigWizardPanel extends ShortcutWizardDescriptorPanel { @Override public void storeSettings(WizardDescriptor wiz) { - IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings(); - ingestJobSettings.save(); - wiz.putProperty("executionContext", RunIngestModulesAction.getDefaultContext()); //NON-NLS + ingestJobSettingsPanel.getSettings().save(); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java index 46ee8370bf..2d19de0bea 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionPanel.java @@ -47,11 +47,13 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { @Messages({"IngestProfileSelectionPanel.customSettings.name=Custom Settings", "IngestProfileSelectionPanel.customSettings.description=configure individual module settings in next step of wizard"}) + private static final long serialVersionUID = 1L; private static final String CUSTOM_SETTINGS_DISPLAY_NAME = Bundle.IngestProfileSelectionPanel_customSettings_name(); private static final String CUSTOM_SETTINGS_DESCRIPTION = Bundle.IngestProfileSelectionPanel_customSettings_description(); private final IngestProfileSelectionWizardPanel wizardPanel; private String selectedProfile; private List profiles = Collections.emptyList(); + boolean isLastPanel = false; /** * Creates new IngestProfileSelectionPanel @@ -162,6 +164,37 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { profileListPanel.removeAll(); } + /** + * Listens for changes and checks the currently selected radio button if + * custom settings button is enabled it enables the next button, otherwise + * it enables the Finish button. + * + * @param e + */ + @Override + public void itemStateChanged(ItemEvent e) { + for (Component rButton : profileListPanel.getComponents()) { + if (rButton instanceof JRadioButton){ + JRadioButton jrb = (JRadioButton) rButton; + if (jrb.isSelected()) { + selectedProfile = jrb.getName(); + break; + } + } + } + boolean wasLastPanel = isLastPanel; + isLastPanel = !selectedProfile.equals(wizardPanel.getDefaultContext()); + wizardPanel.fireChangeEvent(); + this.firePropertyChange("LAST_ENABLED", wasLastPanel, isLastPanel); //NON-NLS + } + + /** + * Get all the currently existing ingest profiles. + */ + private void fetchProfileList() { + profiles = IngestProfiles.getIngestProfiles(); + } + /** * 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 @@ -245,8 +278,7 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { ); dialog.display(ingestOptions); }//GEN-LAST:event_ingestSettingsButtonActionPerformed - - boolean isLastPanel = false; + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton ingestSettingsButton; private javax.swing.ButtonGroup profileListButtonGroup; @@ -255,34 +287,4 @@ final class IngestProfileSelectionPanel extends JPanel implements ItemListener { private javax.swing.JScrollPane profileListScrollPane; // End of variables declaration//GEN-END:variables - /** - * Listens for changes and checks the currently selected radio button if - * custom settings button is enabled it enables the next button, otherwise - * it enables the Finish button. - * - * @param e - */ - @Override - public void itemStateChanged(ItemEvent e) { - for (Component rButton : profileListPanel.getComponents()) { - if (rButton instanceof JRadioButton){ - JRadioButton jrb = (JRadioButton) rButton; - if (jrb.isSelected()) { - selectedProfile = jrb.getName(); - break; - } - } - } - boolean wasLastPanel = isLastPanel; - isLastPanel = !selectedProfile.equals(wizardPanel.getDefaultContext()); - wizardPanel.fireChangeEvent(); - this.firePropertyChange("LAST_ENABLED", wasLastPanel, isLastPanel); //NON-NLS - } - - /** - * Get all the currently existing ingest profiles. - */ - private void fetchProfileList() { - profiles = IngestProfiles.getIngestProfiles(); - } -} + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java index 207e577bf1..7fea8bbbad 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/IngestProfileSelectionWizardPanel.java @@ -27,6 +27,7 @@ import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; /** * The first wizard panel of the run ingest modules wizard. Displays the profile @@ -37,28 +38,33 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP @Messages("IngestProfileWizardPanel.panelName=Ingest Profile Selection") - private final Set listeners = new HashSet<>(1); private final static String LAST_PROFILE_PROPERTIES_FILE = "IngestProfileSelectionPanel"; //NON-NLS - /** - * The visual ingestProfileSelectionPanel that displays this panel. If you - * need to access the ingestProfileSelectionPanel from this class, just use - * getComponent(). - */ + private final String executionContext; + private final String lastProfilePropertyName; + private final Set listeners = new HashSet<>(1); private IngestProfileSelectionPanel ingestProfileSelectionPanel; private String lastProfileUsed; - private final String lastProfilePropertyName; - private final String defaultContext; - public IngestProfileSelectionWizardPanel(String defaultContext, String lastProfilePropertyName) { + public IngestProfileSelectionWizardPanel(String executionContext, String lastProfilePropertyName) { this.lastProfilePropertyName = lastProfilePropertyName; - this.defaultContext = defaultContext; + this.executionContext = executionContext; } + /** + * Gets the ingest job settings associated with this wizard panel. + * + * @return The settings, will be null if the panel has not been used in the + * wizard. + */ + IngestJobSettings getIngestJobSettings() { + return new IngestJobSettings(lastProfileUsed); + } + /** * @return the defaultContext */ String getDefaultContext() { - return defaultContext; + return executionContext; } /** @@ -70,10 +76,6 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP return LAST_PROFILE_PROPERTIES_FILE; } - // Get the visual ingestProfileSelectionPanel for the panel. In this template, the ingestProfileSelectionPanel - // is kept separate. This can be more efficient: if the wizard is created - // but never displayed, or not all panels are displayed, it is better to - // create only those which really need to be visible. @Override public Component getComponent() { if (ingestProfileSelectionPanel == null) { @@ -91,13 +93,11 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP @Override public HelpCtx getHelp() { - // Show no Help button for this panel: return HelpCtx.DEFAULT_HELP; } @Override public boolean isValid() { - // If it is always OK to press Next or Finish, then: return true; } @@ -136,7 +136,6 @@ public class IngestProfileSelectionWizardPanel extends ShortcutWizardDescriptorP @Override public void storeSettings(WizardDescriptor wiz) { lastProfileUsed = ingestProfileSelectionPanel.getLastSelectedProfile(); - wiz.putProperty("executionContext", lastProfileUsed); //NON-NLS ModuleSettings.setConfigSetting(LAST_PROFILE_PROPERTIES_FILE, lastProfilePropertyName, lastProfileUsed); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index 4636ff72f4..01ab11e7d6 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -18,16 +18,19 @@ */ package org.sleuthkit.autopsy.ingest.runIngestModuleWizard; +import java.awt.Cursor; import java.awt.event.ActionEvent; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; -import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JOptionPane; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; +import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.Content; @@ -38,23 +41,16 @@ import org.sleuthkit.datamodel.Directory; * When the data source is pressed, it should open the wizard for ingest * modules. */ -public final class RunIngestModulesAction extends AbstractAction { +public final class RunIngestModulesAction extends CallableSystemAction { @Messages("RunIngestModulesAction.name=Run Ingest Modules") + private static final long serialVersionUID = 1L; - //'dialog' context name required so existing settings do not need to be reconfigured - private static final String DEFAULT_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; - - /** - * Returns the name of the default context which will be used when profiles - * are not available. - * - * @return the DEFAULT_CONTEXT + /* + * Note that the execution context is the name of the dialog that used to be + * used instead of this wizard and is retained for backwards compatibility. */ - static String getDefaultContext() { - return DEFAULT_CONTEXT; - } - + private static final String EXECUTION_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; private final List dataSources = new ArrayList<>(); private final IngestJobSettings.IngestType ingestType; @@ -89,14 +85,19 @@ public final class RunIngestModulesAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { - WizardDescriptor wiz = new WizardDescriptor(new RunIngestModulesWizardIterator()); - // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() + /** + * Create and display a Run Ingest Modules wizard. Note that the + * argument in the title format string will be supplied by + * WizardDescriptor.Panel.getComponent().getName(). + */ + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + RunIngestModulesWizardIterator wizard = new RunIngestModulesWizardIterator(EXECUTION_CONTEXT, this.ingestType); + WizardDescriptor wiz = new WizardDescriptor(wizard); wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle(Bundle.RunIngestModulesAction_name()); - + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { - String executionContext = (String) wiz.getProperty("executionContext"); //NON-NLS - IngestJobSettings ingestJobSettings = new IngestJobSettings(executionContext, this.ingestType); + IngestJobSettings ingestJobSettings = wizard.getIngestJobSettings(); showWarnings(ingestJobSettings); IngestManager.getInstance().queueIngestJob(this.dataSources, ingestJobSettings); } @@ -110,11 +111,27 @@ public final class RunIngestModulesAction extends AbstractAction { private static void showWarnings(IngestJobSettings ingestJobSettings) { List warnings = ingestJobSettings.getWarnings(); if (warnings.isEmpty() == false) { - StringBuilder warningMessage = new StringBuilder(); + StringBuilder warningMessage = new StringBuilder(1024); for (String warning : warnings) { warningMessage.append(warning).append("\n"); } JOptionPane.showMessageDialog(null, warningMessage.toString()); } } + + @Override + public void performAction() { + actionPerformed(null); + } + + @Override + public String getName() { + return Bundle.RunIngestModulesAction_name(); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java index ca242095fd..8fb0b9ba4a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesWizardIterator.java @@ -25,70 +25,78 @@ import java.util.NoSuchElementException; import javax.swing.JComponent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestProfiles; /** - * Iterator class for creating a wizard for run ingest modules. - * + * A wizard that allows a user to configure an ingest job. */ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator { - private int index; private final static String PROP_LASTPROFILE_NAME = "RIMW_LASTPROFILE_NAME"; //NON-NLS - private List panels; + private final IngestJobSettings.IngestType ingestType; + private final List panels; + private int currentPanelIndex; /** - * Gets the list of panels used by this wizard for iterating over. - * Constructing it when it is null. + * Constructs a wizard that allows a user to configure an ingest job. * - * @return panels - the list of of WizardDescriptor panels + * @param executionContext The execution context for this wizard. Ingest job + * settings can differ by execution context. + * @param ingestType The type of ingest to be configured. */ - private List getPanels() { - if (panels == null) { - panels = new ArrayList<>(); - List profiles = IngestProfiles.getIngestProfiles(); - if (!profiles.isEmpty()) { - panels.add(new IngestProfileSelectionWizardPanel(RunIngestModulesAction.getDefaultContext(), PROP_LASTPROFILE_NAME)); - } + RunIngestModulesWizardIterator(String executionContext, IngestJobSettings.IngestType ingestType) { + this.ingestType = ingestType; + panels = new ArrayList<>(); + List profiles = IngestProfiles.getIngestProfiles(); + if (!profiles.isEmpty() && IngestJobSettings.IngestType.FILES_ONLY != this.ingestType) { + panels.add(new IngestProfileSelectionWizardPanel(executionContext, PROP_LASTPROFILE_NAME)); + } - panels.add(new IngestModulesConfigWizardPanel()); - String[] steps = new String[panels.size()]; - for (int i = 0; i < panels.size(); i++) { - Component c = panels.get(i).getComponent(); - // Default step name to component name of panel. - steps[i] = c.getName(); - if (c instanceof JComponent) { // assume Swing components - JComponent jc = (JComponent) c; - jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i); - jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps); - jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true); - jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true); - jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true); - } + panels.add(new IngestModulesConfigWizardPanel(executionContext, this.ingestType)); + String[] steps = new String[panels.size()]; + for (int i = 0; i < panels.size(); i++) { + Component c = panels.get(i).getComponent(); + steps[i] = c.getName(); + if (c instanceof JComponent) { + JComponent jc = (JComponent) c; + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i); + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps); + jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true); + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true); + jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true); } } - return panels; + } + + IngestJobSettings getIngestJobSettings() { + ShortcutWizardDescriptorPanel panel = current(); + if (panel instanceof IngestProfileSelectionWizardPanel) { + return ((IngestProfileSelectionWizardPanel) panel).getIngestJobSettings(); + } else { + return ((IngestModulesConfigWizardPanel) panel).getIngestJobSettings(); + } } @Override public ShortcutWizardDescriptorPanel current() { - return getPanels().get(index); + return panels.get(currentPanelIndex); } @Override public String name() { - return index + 1 + ". from " + getPanels().size(); + return currentPanelIndex + 1 + ". from " + panels.size(); } @Override public boolean hasNext() { - return (index < getPanels().size() - 1 + return (currentPanelIndex < panels.size() - 1 && !(current().panelEnablesSkipping() && current().skipNextPanel())); } @Override public boolean hasPrevious() { - return index > 0; + return currentPanelIndex > 0; } @Override @@ -96,7 +104,7 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< if (!hasNext()) { throw new NoSuchElementException(); } - index++; + currentPanelIndex++; } @Override @@ -104,10 +112,9 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< if (!hasPrevious()) { throw new NoSuchElementException(); } - index--; + currentPanelIndex--; } - // If nothing unusual changes in the middle of the wizard, simply: @Override public void addChangeListener(ChangeListener l) { } @@ -115,9 +122,5 @@ final class RunIngestModulesWizardIterator implements WizardDescriptor.Iterator< @Override public void removeChangeListener(ChangeListener l) { } - // If something changes dynamically (besides moving between panels), e.g. - // the number of panels changes in response to user input, then use - // ChangeSupport to implement add/removeChangeListener and call fireChange - // when needed } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 00eb729aad..2a78b2b5b5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,16 +30,17 @@ import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.datamodel.TskCoreException; /** * Ingest job settings panel for hash lookup file ingest modules. */ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSettingsPanel implements PropertyChangeListener { + private static final long serialVersionUID = 1L; private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final List knownHashSetModels = new ArrayList<>(); private final HashSetsTableModel knownHashSetsTableModel = new HashSetsTableModel(knownHashSetModels); @@ -216,6 +217,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private static final class HashSetsTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; private final List hashSets; HashSetsTableModel(List hashSets) {