diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index b4c15cc0e2..4476083f1d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -54,7 +54,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { private JPanel currentPanel; private Map datasourceProcessorsMap = new HashMap<>(); - + List coreDSPTypes = new ArrayList<>(); /** @@ -83,8 +83,14 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { // make a list of core DSPs // ensure that the core DSPs are at the top and in a fixed order - coreDSPTypes.add(ImageDSProcessor.getType()); - coreDSPTypes.add(LocalDiskDSProcessor.getType()); + coreDSPTypes.add(ImageDSProcessor.getType()); + // Local disk processing is not allowed for multi-user cases + if (Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE){ + coreDSPTypes.add(LocalDiskDSProcessor.getType()); + } else { + // remove LocalDiskDSProcessor from list of DSPs + datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType()); + } coreDSPTypes.add(LocalFilesDSProcessor.getType()); for (String dspType : coreDSPTypes) { @@ -127,7 +133,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { logger.log(Level.SEVERE, "discoverDataSourceProcessors(): A DataSourceProcessor already exists for type = {0}", dsProcessor.getDataSourceType()); //NON-NLS } } - } + } private void dspSelectionChanged() { // update the current panel to selection diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 1251b2d194..8afd1f5cdb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -231,3 +231,8 @@ AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel NewCaseVisualPanel1.rbSingleUserCase.text=Single-user NewCaseVisualPanel1.rbMultiUserCase.text=Multi-user NewCaseVisualPanel1.lbBadMultiUserSettings.text= +ImageFilePanel.errorLabel.text=Error Label +DataSourceOnCDriveError.text=Path to multi-user data source is on \"C:\" drive +NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Path to multi-user case folder is on \"C:\" drive +LocalFilesPanel.errorLabel.text=Error Label +NewCaseVisualPanel1.errorLabel.text=Error Label diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 0d2bd7e942..a3d3832f82 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -215,3 +215,6 @@ XMLCaseManagement.open.msgDlg.notAutCase.title=\u30a8\u30e9\u30fc ImageFilePanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996 LocalDiskPanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996 AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb +ImageFilePanel.errorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb +LocalFilesPanel.errorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb +NewCaseVisualPanel1.errorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index b4dbaafd63..bfccc9bdd9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -43,6 +43,7 @@ + @@ -57,7 +58,9 @@ - + + + @@ -66,7 +69,7 @@ - + @@ -131,5 +134,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 045fe691a4..e9f518eb80 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PathValidator; /** * ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc. @@ -62,6 +63,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); + errorLabel.setVisible(false); + boolean firstFilter = true; for (FileFilter filter: fileChooserFilters ) { if (firstFilter) { // set the first on the list as the default selection @@ -76,7 +79,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { this.contextName = context; pcs = new PropertyChangeSupport(this); - createTimeZoneList(); + createTimeZoneList(); } /** @@ -98,7 +101,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } - /** * 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 @@ -115,6 +117,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { timeZoneComboBox = new javax.swing.JComboBox(); noFatOrphansCheckbox = new javax.swing.JCheckBox(); descLabel = new javax.swing.JLabel(); + errorLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -139,6 +142,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.descLabel.text")); // NOI18N + errorLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.errorLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -158,7 +164,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(noFatOrphansCheckbox) .addGroup(layout.createSequentialGroup() .addGap(21, 21, 21) - .addComponent(descLabel))) + .addComponent(descLabel)) + .addComponent(errorLabel)) .addGap(0, 20, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -169,7 +176,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(browseButton) .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) + .addGap(3, 3, 3) + .addComponent(errorLabel) + .addGap(1, 1, 1) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(timeZoneLabel) .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -177,7 +186,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(13, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -211,6 +220,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; private javax.swing.JLabel descLabel; + private javax.swing.JLabel errorLabel; private javax.swing.JCheckBox noFatOrphansCheckbox; private javax.swing.JLabel pathLabel; private javax.swing.JTextField pathTextField; @@ -255,19 +265,33 @@ public class ImageFilePanel extends JPanel implements DocumentListener { * @return true if a proper image has been selected, false otherwise */ public boolean validatePanel() { + errorLabel.setVisible(false); String path = getContentPaths(); if (path == null || path.isEmpty()) { return false; } + // display warning if there is one (but don't disable "next" button) + warnIfPathIsInvalid(path); + boolean isExist = Case.pathExists(path); boolean isPhysicalDrive = Case.isPhysicalDrive(path); boolean isPartition = Case.isPartition(path); return (isExist || isPhysicalDrive || isPartition); } - - + + /** + * Validates path to selected data source and displays warning if it is invalid. + * @param path Absolute path to the selected data source + */ + private void warnIfPathIsInvalid(String path){ + if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) { + errorLabel.setVisible(true); + errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text")); + } + } + public void storeSettings() { String imagePathName = getContentPaths(); if (null != imagePathName ) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form index d71086457c..55707d9f0c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form @@ -61,7 +61,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 38d067c153..3cf6b40bc6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -92,11 +92,11 @@ final class LocalDiskPanel extends JPanel { model = new LocalDiskModel(); diskComboBox.setModel(model); diskComboBox.setRenderer(model); - + + errorLabel.setVisible(false); errorLabel.setText(""); diskComboBox.setEnabled(false); - - } + } /** * This method is called from within the constructor to initialize the form. @@ -167,7 +167,7 @@ final class LocalDiskPanel extends JPanel { .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(21, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables @@ -224,7 +224,7 @@ final class LocalDiskPanel extends JPanel { * @return true */ //@Override - public boolean validatePanel() { + public boolean validatePanel() { return enableNext; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form index cf08c9c38f..eb9d6182bb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.form @@ -60,6 +60,10 @@ + + + + @@ -67,15 +71,16 @@ - + + - + - - + + @@ -136,5 +141,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index 256276809b..f2c1d7d82f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.casemodule; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; +import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.JFileChooser; @@ -30,7 +32,9 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PathValidator; /** * Add input wizard subpanel for adding local files / dirs to the case */ @@ -42,6 +46,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; private static LocalFilesPanel instance; public static final String FILES_SEP = ","; private static final Logger logger = Logger.getLogger(LocalFilesPanel.class.getName()); + /** * Creates new form LocalFilesPanel */ @@ -59,9 +64,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; private void customInit() { localFileChooser.setMultiSelectionEnabled(true); + errorLabel.setVisible(false); selectedPaths.setText(""); - - } + } //@Override public String getContentPaths() { @@ -91,8 +96,32 @@ import org.sleuthkit.autopsy.coreutils.Logger; //@Override public boolean validatePanel() { + + // display warning if there is one (but don't disable "next" button) + warnIfPathIsInvalid(getContentPaths()); + return enableNext; } + + /** + * Validates path to selected data source and displays warning if it is invalid. + * @param path Absolute path to the selected data source + */ + private void warnIfPathIsInvalid(String path) { + errorLabel.setVisible(false); + + // Path variable for "Local files" module is a coma separated string containg multiple paths + List pathsList = Arrays.asList(path.split(",")); + CaseType currentCaseType = Case.getCurrentCase().getCaseType(); + + for (String currentPath : pathsList) { + if (!PathValidator.isValid(currentPath, currentCaseType)) { + errorLabel.setVisible(true); + errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text")); + return; + } + } + } //@Override public void select() { @@ -104,6 +133,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; currentFiles.clear(); selectedPaths.setText(""); enableNext = false; + errorLabel.setVisible(false); //pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); } @@ -149,6 +179,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; clearButton = new javax.swing.JButton(); jScrollPane2 = new javax.swing.JScrollPane(); selectedPaths = new javax.swing.JTextArea(); + errorLabel = new javax.swing.JLabel(); localFileChooser.setApproveButtonText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.localFileChooser.approveButtonText")); // NOI18N localFileChooser.setApproveButtonToolTipText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.localFileChooser.approveButtonToolTipText")); // NOI18N @@ -184,6 +215,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; selectedPaths.setToolTipText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.selectedPaths.toolTipText")); // NOI18N jScrollPane2.setViewportView(selectedPaths); + errorLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.errorLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -198,19 +232,23 @@ import org.sleuthkit.autopsy.coreutils.Logger; .addComponent(selectButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(clearButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGap(2, 2, 2)) + .addGroup(layout.createSequentialGroup() + .addComponent(errorLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(infoLabel) .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addComponent(selectButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 17, Short.MAX_VALUE) - .addComponent(clearButton)) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) - .addGap(0, 0, 0)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(clearButton))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel)) ); }// //GEN-END:initComponents @@ -258,6 +296,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton clearButton; + private javax.swing.JLabel errorLabel; private javax.swing.JLabel infoLabel; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form index 37314730b4..dc370e00cd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form @@ -23,33 +23,49 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + - - + - @@ -73,12 +89,14 @@ - + - + + + @@ -158,6 +176,9 @@ + + + @@ -168,6 +189,9 @@ + + + @@ -182,5 +206,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index 4dd63ca497..0ca9173fee 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -29,6 +29,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.datamodel.CaseDbConnectionInfo; import org.sleuthkit.datamodel.TskData.DbType; @@ -40,10 +41,11 @@ import org.sleuthkit.datamodel.TskData.DbType; final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { private JFileChooser fc = new JFileChooser(); - private NewCaseWizardPanel1 wizPanel; + private NewCaseWizardPanel1 wizPanel; NewCaseVisualPanel1(NewCaseWizardPanel1 wizPanel) { initComponents(); + errorLabel.setVisible(false); lbBadMultiUserSettings.setText(""); this.wizPanel = wizPanel; caseNameTextField.getDocument().addDocumentListener(this); @@ -145,6 +147,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { rbSingleUserCase = new javax.swing.JRadioButton(); rbMultiUserCase = new javax.swing.JRadioButton(); lbBadMultiUserSettings = new javax.swing.JLabel(); + errorLabel = new javax.swing.JLabel(); jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N @@ -171,14 +174,27 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { caseTypeButtonGroup.add(rbSingleUserCase); org.openide.awt.Mnemonics.setLocalizedText(rbSingleUserCase, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.rbSingleUserCase.text")); // NOI18N + rbSingleUserCase.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + rbSingleUserCaseActionPerformed(evt); + } + }); caseTypeButtonGroup.add(rbMultiUserCase); org.openide.awt.Mnemonics.setLocalizedText(rbMultiUserCase, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.rbMultiUserCase.text")); // NOI18N + rbMultiUserCase.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + rbMultiUserCaseActionPerformed(evt); + } + }); lbBadMultiUserSettings.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N lbBadMultiUserSettings.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(lbBadMultiUserSettings, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.lbBadMultiUserSettings.text")); // NOI18N + errorLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.errorLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -186,27 +202,37 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 58, Short.MAX_VALUE) + .addComponent(lbBadMultiUserSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 372, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(jLabel1) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(caseDirLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(caseParentDirTextField)) + .addGroup(layout.createSequentialGroup() + .addComponent(caseNameLabel) + .addGap(26, 26, 26) + .addComponent(caseNameTextField))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(caseDirBrowseButton))) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() .addComponent(rbSingleUserCase) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(rbMultiUserCase)) - .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(caseDirLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(caseParentDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(caseNameLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbBadMultiUserSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 372, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(caseDirBrowseButton))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(errorLabel)) + .addGap(0, 0, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -226,11 +252,13 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(caseDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(rbSingleUserCase) .addComponent(rbMultiUserCase)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel) + .addGap(1, 1, 1) .addComponent(lbBadMultiUserSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -261,6 +289,16 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { } }//GEN-LAST:event_caseDirBrowseButtonActionPerformed + private void rbSingleUserCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbSingleUserCaseActionPerformed + this.wizPanel.fireChangeEvent(); + updateUI(null); // DocumentEvent is not used inside updateUI + }//GEN-LAST:event_rbSingleUserCaseActionPerformed + + private void rbMultiUserCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbMultiUserCaseActionPerformed + this.wizPanel.fireChangeEvent(); + updateUI(null); // DocumentEvent is not used inside updateUI + }//GEN-LAST:event_rbMultiUserCaseActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton caseDirBrowseButton; private javax.swing.JLabel caseDirLabel; @@ -269,6 +307,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { private javax.swing.JTextField caseNameTextField; private javax.swing.JTextField caseParentDirTextField; private javax.swing.ButtonGroup caseTypeButtonGroup; + private javax.swing.JLabel errorLabel; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel lbBadMultiUserSettings; @@ -320,10 +359,13 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { * @param e the document event */ public void updateUI(DocumentEvent e) { + + // Note: DocumentEvent e can be null when called from rbSingleUserCaseActionPerformed() + // and rbMultiUserCaseActionPerformed(). String caseName = getCaseName(); String parentDir = getCaseParentDir(); - + if (!caseName.equals("") && !parentDir.equals("")) { caseDirTextField.setText(parentDir + caseName); wizPanel.setIsFinish(true); @@ -331,5 +373,21 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { caseDirTextField.setText(""); wizPanel.setIsFinish(false); } + + // display warning if there is one (but don't disable "next" button) + warnIfPathIsInvalid(parentDir); } + + /** + * Validates path to selected case output folder. Displays warning if path is invalid. + * + * @param path Absolute path to the selected case folder + */ + private void warnIfPathIsInvalid(String path) { + errorLabel.setVisible(false); + if (!PathValidator.isValid(path, getCaseType())) { + errorLabel.setVisible(true); + errorLabel.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.CaseFolderOnCDriveError.text")); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java index 92bad320dd..ccdb48b951 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java @@ -35,7 +35,6 @@ import org.openide.WizardDescriptor; import org.openide.WizardValidationException; import org.openide.util.HelpCtx; import org.sleuthkit.autopsy.casemodule.Case.CaseType; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/PathValidator.java b/Core/src/org/sleuthkit/autopsy/coreutils/PathValidator.java new file mode 100644 index 0000000000..b4d842fd88 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/PathValidator.java @@ -0,0 +1,57 @@ +/* + * 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.coreutils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.sleuthkit.autopsy.casemodule.Case; + +/** + * Validates absolute path (e.g. to a data source or case output folder) depending on case type. + */ +public final class PathValidator { + + private static final Pattern driveLetterPattern = Pattern.compile("^[Cc]:.*$"); + public static boolean isValid(String path, Case.CaseType caseType) { + + if (caseType == Case.CaseType.MULTI_USER_CASE) { + // check that path is not on "C:" drive + if (pathOnCDrive(path)) { + return false; + } + } else { + // single user case - no validation needed + } + + return true; + } + + + /** + * Checks whether a file path contains drive letter defined by pattern. + * + * @param filePath Input file absolute path + * @return true if path matches the pattern, false otherwise. + */ + private static boolean pathOnCDrive(String filePath) { + Matcher m = driveLetterPattern.matcher(filePath); + return m.find(); + } +} \ No newline at end of file