/* * Autopsy Forensic Browser * * Copyright 2011-2018 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.experimental.autoingest; import java.io.File; import java.util.List; import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.filechooser.FileFilter; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import static org.sleuthkit.autopsy.experimental.autoingest.Bundle.*; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; /** * Panel for adding an archive file which is supported by 7zip library (e.g. * "zip", "rar", "arj", "7z", "7zip", "gzip, etc). Allows the user to select a * file. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives class ArchiveFilePanel extends JPanel implements DocumentListener { private static final Logger logger = Logger.getLogger(ArchiveFilePanel.class.getName()); private static final String PROP_LAST_ARCHIVE_PATH = "LBL_LastImage_PATH"; //NON-NLS private final JFileChooser fileChooser = new JFileChooser(); /** * Externally supplied name is used to store settings */ private final String contextName; /** * Creates new form ArchiveFilePanel * * @param context A string context name used to read/store last * used settings. * @param fileChooserFilters A list of filters to be used with the * FileChooser. */ private ArchiveFilePanel(String context, List fileChooserFilters) { this.contextName = context; initComponents(); errorLabel.setVisible(false); fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setMultiSelectionEnabled(false); fileChooserFilters.forEach(fileChooser::addChoosableFileFilter); if (fileChooserFilters.isEmpty() == false) { fileChooser.setFileFilter(fileChooserFilters.get(0)); } } /** * Creates and returns an instance of a ArchiveFilePanel. * * @param context A string context name used to read/store last * used settings. * @param fileChooserFilters A list of filters to be used with the * FileChooser. * * @return instance of the ArchiveFilePanel */ public static synchronized ArchiveFilePanel createInstance(String context, List fileChooserFilters) { ArchiveFilePanel instance = new ArchiveFilePanel(context, fileChooserFilters); // post-constructor initialization of listener support without leaking references of uninitialized objects instance.pathTextField.getDocument().addDocumentListener(instance); return instance; } /** * 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() { pathLabel = new javax.swing.JLabel(); browseButton = new javax.swing.JButton(); pathTextField = new javax.swing.JTextField(); errorLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.browseButton.text")); // NOI18N browseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); } }); pathTextField.setText(org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathTextField.text")); // NOI18N errorLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.errorLabel.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() .addComponent(pathTextField) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(browseButton) .addGap(2, 2, 2)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(pathLabel) .addComponent(errorLabel)) .addGap(0, 277, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(pathLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .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(3, 3, 3) .addComponent(errorLabel) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed String oldText = getContentPaths(); // set the current directory of the FileChooser if the ArchivePath Field is valid File currentDir = new File(oldText); if (currentDir.exists()) { fileChooser.setCurrentDirectory(currentDir); } if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { String path = fileChooser.getSelectedFile().getPath(); setContentPath(path); } updateHelper(); }//GEN-LAST:event_browseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; private javax.swing.JLabel errorLabel; private javax.swing.JLabel pathLabel; private javax.swing.JTextField pathTextField; // End of variables declaration//GEN-END:variables /** * Get the path of the user selected archive. * * @return the archive path */ public String getContentPaths() { return pathTextField.getText(); } /** * Set the path of the archive file. * * @param s path of the archive file */ public void setContentPath(String s) { pathTextField.setText(s); } public void reset() { //reset the UI elements to default pathTextField.setText(null); } /** * Should we enable the next button of the wizard? * * @return true if a proper archive has been selected, false otherwise */ @NbBundle.Messages({"DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive", "DataSourceOnCDriveError.noOpenCase.errMsg=Warning: Exception while getting open case." }) public boolean validatePanel() { errorLabel.setVisible(false); String path = getContentPaths(); if (StringUtils.isBlank(path)) { return false; } // display warning if there is one (but don't disable "next" button) try { if (false == PathValidator.isValidForMultiUserCase(path, Case.getCurrentCaseThrows().getCaseType())) { errorLabel.setVisible(true); errorLabel.setText(Bundle.DataSourceOnCDriveError_text()); } } catch (NoCurrentCaseException ex) { errorLabel.setVisible(true); errorLabel.setText(Bundle.DataSourceOnCDriveError_noOpenCase_errMsg()); } return new File(path).isFile() || DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path); } public void storeSettings() { String archivePathName = getContentPaths(); if (null != archivePathName) { String archivePath = archivePathName.substring(0, archivePathName.lastIndexOf(File.separator) + 1); ModuleSettings.setConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH, archivePath); } } public void readSettings() { String lastArchivePath = ModuleSettings.getConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH); if (StringUtils.isNotBlank(lastArchivePath)) { setContentPath(lastArchivePath); } } @Override public void insertUpdate(DocumentEvent e) { updateHelper(); } @Override public void removeUpdate(DocumentEvent e) { updateHelper(); } @Override public void changedUpdate(DocumentEvent e) { updateHelper(); } /** * Update functions are called by the pathTextField which has this set as * it's DocumentEventListener. Each update function fires a property change * to be caught by the parent panel. * */ @NbBundle.Messages({"ArchiveFilePanel.moduleErr=Module Error", "ArchiveFilePanel.moduleErr.msg=A module caused an error listening to ArchiveFilePanel updates." + " See log to determine which module. Some data could be incomplete.\n"}) private void updateHelper() { try { firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } catch (Exception e) { logger.log(Level.SEVERE, "ArchiveFilePanel listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.error(ArchiveFilePanel_moduleErr(), ArchiveFilePanel_moduleErr_msg()); } } /** * Set the focus to the pathTextField. */ public void select() { pathTextField.requestFocusInWindow(); } }