Merge pull request #351 from raman-bt/flexiwizard

Flexiwizard
This commit is contained in:
Brian Carrier 2013-11-22 09:09:08 -08:00
commit 9f50dd1860
27 changed files with 2211 additions and 1149 deletions

View File

@ -0,0 +1,356 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;
/*
* A background task (swingworker) that adds the given image to
* database using the Sleuthkit JNI interface.
*
* It updates the given ProgressMonitor as it works through adding the image,
* and et the end, calls the specified Callback.
*/
public class AddImageTask implements Runnable {
private Logger logger = Logger.getLogger(AddImageTask.class.getName());
private Case currentCase;
// true if the process was requested to stop
private volatile boolean cancelled = false;
//true if revert has been invoked.
private boolean reverted = false;
private boolean hasCritError = false;
private volatile boolean addImageDone = false;
private List<String> errorList = new ArrayList<String>();
private DSPProgressMonitor progressMonitor;
private DSPCallback callbackObj;
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess;
private Thread dirFetcher;
private String imagePath;
private String dataSourcetype;
String timeZone;
boolean noFatOrphans;
/*
* A Swingworker that updates the progressMonitor with the name of the
* directory currently being processed by the AddImageTask
*/
private class CurrentDirectoryFetcher implements Runnable {
DSPProgressMonitor progressMonitor;
SleuthkitJNI.CaseDbHandle.AddImageProcess process;
CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) {
this.progressMonitor = aProgressMonitor;
this.process = proc;
}
/**
* @return the currently processing directory
*/
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
String currDir = process.currentDirectory();
if (currDir != null) {
if (!currDir.isEmpty() ) {
progressMonitor.setProgressText("Adding: " + currDir);
}
}
Thread.sleep(2 * 1000);
}
return;
} catch (InterruptedException ie) {
return;
}
}
}
protected AddImageTask(String imgPath, String tz, boolean noOrphans, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) {
currentCase = Case.getCurrentCase();
this.imagePath = imgPath;
this.timeZone = tz;
this.noFatOrphans = noOrphans;
this.callbackObj = cbObj;
this.progressMonitor = aProgressMonitor;
}
/**
* Starts the addImage process, but does not commit the results.
*
* @return
*
* @throws Exception
*/
@Override
public void run() {
errorList.clear();
//lock DB for writes in this thread
SleuthkitCase.dbWriteLock();
addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
try {
progressMonitor.setIndeterminate(true);
progressMonitor.setProgress(0);
dirFetcher.start();
addImageProcess.run(new String[]{this.imagePath});
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex);
//critical core/system error and process needs to be interrupted
hasCritError = true;
errorList.add(ex.getMessage());
} catch (TskDataException ex) {
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex);
errorList.add(ex.getMessage());
}
finally {
}
// handle addImage done
postProcess();
// unclock the DB
SleuthkitCase.dbWriteUnlock();
return;
}
/**
* Commit the newly added image to DB
*
*
* @throws Exception if commit or adding the image to the case failed
*/
private void commitImage() throws Exception {
long imageId = 0;
try {
imageId = addImageProcess.commit();
} catch (TskException e) {
logger.log(Level.WARNING, "Errors occured while committing the image", e);
errorList.add(e.getMessage());
} finally {
if (imageId != 0) {
// get the newly added Image so we can return to caller
Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
//while we have the image, verify the size of its contents
String verificationErrors = newImage.verifyImageSize();
if (verificationErrors.equals("") == false) {
//data error (non-critical)
errorList.add(verificationErrors);
}
// Add the image to the list of new content
newContents.add(newImage);
}
logger.log(Level.INFO, "Image committed, imageId: " + imageId);
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
}
}
/**
* Post processing after the addImageProcess is done.
*
*/
private void postProcess() {
// cancel the directory fetcher
dirFetcher.interrupt();
addImageDone = true;
// attempt actions that might fail and force the process to stop
if (cancelled || hasCritError) {
logger.log(Level.INFO, "Handling errors or interruption that occured in add image process");
revert();
}
if (!errorList.isEmpty()) {
logger.log(Level.INFO, "Handling non-critical errors that occured in add image process");
}
// When everything happens without an error:
if (!(cancelled || hasCritError)) {
try {
// Tell the progress monitor we're done
progressMonitor.setProgress(100);
if (newContents.isEmpty()) {
if (addImageProcess != null) { // and if we're done configuring ingest
// commit anything
try {
commitImage();
} catch (Exception ex) {
errorList.add(ex.getMessage());
// Log error/display warning
logger.log(Level.SEVERE, "Error adding image to case.", ex);
}
} else {
logger.log(Level.SEVERE, "Missing image process object");
}
}
else { //already commited?
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
}
} catch (Exception ex) {
//handle unchecked exceptions post image add
errorList.add(ex.getMessage());
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
logger.log(Level.SEVERE, "Error adding image to case", ex);
} finally {
}
}
// invoke the callBack, unless the caller cancelled
if (!cancelled) {
doCallBack();
}
return;
}
/*
* Call the callback with results, new content, and errors, if any
*/
private void doCallBack()
{
DSPCallback.DSP_Result result;
if (hasCritError) {
result = DSPCallback.DSP_Result.CRITICAL_ERRORS;
}
else if (!errorList.isEmpty()) {
result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS;
}
else {
result = DSPCallback.DSP_Result.NO_ERRORS;
}
// invoke the callcak, passing it the result, list of new contents, and list of errors
callbackObj.done(result, errorList, newContents);
}
/*
* cancel the image addition, if possible
*/
public void cancelTask() {
cancelled = true;
if (!addImageDone) {
try {
interrupt();
}
catch (Exception ex) {
logger.log(Level.SEVERE, "Failed to interrup the add image task...");
}
}
else {
try {
revert();
}
catch(Exception ex) {
logger.log(Level.SEVERE, "Failed to revert the add image task...");
}
}
}
/*
* Interrurp the add image process if it is still running
*/
private void interrupt() throws Exception {
try {
logger.log(Level.INFO, "interrupt() add image process");
addImageProcess.stop(); //it might take time to truly stop processing and writing to db
} catch (TskException ex) {
throw new Exception("Error stopping add-image process.", ex);
}
}
/*
* Revert - if image has already been added but not committed yet
*/
void revert() {
if (!reverted) {
try {
logger.log(Level.INFO, "Revert after add image process");
try {
addImageProcess.revert();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error reverting add image process", ex);
}
} finally {
}
reverted = true;
}
}
}

View File

@ -18,7 +18,9 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.Color;
import java.awt.EventQueue;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@ -27,6 +29,7 @@ import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
/**
* The final panel of the add image wizard. It displays a progress bar and
@ -50,6 +53,49 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa
private AddImageWizardAddingProgressVisual component;
private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl();
public DSPProgressMonitorImpl getDSPProgressMonitorImpl() {
return dspProgressMonitorImpl;
}
private class DSPProgressMonitorImpl implements DSPProgressMonitor {
@Override
public void setIndeterminate(final boolean indeterminate) {
// update the progress bar asynchronously
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
getComponent().getProgressBar().setIndeterminate(indeterminate);
}
});
}
@Override
public void setProgress(final int progress) {
// update the progress bar asynchronously
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
getComponent().getProgressBar().setValue(progress);
}
});
}
@Override
public void setProgressText(final String text) {
// update the progress UI asynchronously
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
getComponent().setProgressMsgText(text);
}
});
}
}
/**
* 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

View File

@ -142,7 +142,7 @@
<Component id="subTitle2Label" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="progressLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="subTitle1Label" alignment="0" max="32767" attributes="1"/>
<Component id="TextArea_CurrentDirectory" alignment="0" max="32767" attributes="0"/>
<Component id="progressTextArea" alignment="0" max="32767" attributes="0"/>
<Component id="progressBar" alignment="0" max="32767" attributes="1"/>
</Group>
<EmptySpace min="0" pref="8" max="32767" attributes="0"/>
@ -158,7 +158,7 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="progressBar" min="-2" pref="23" max="-2" attributes="1"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="TextArea_CurrentDirectory" min="-2" pref="91" max="-2" attributes="0"/>
<Component id="progressTextArea" min="-2" pref="91" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="progressLabel" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -185,7 +185,7 @@
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextArea" name="TextArea_CurrentDirectory">
<Component class="javax.swing.JTextArea" name="progressTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
@ -196,11 +196,11 @@
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Currently Adding:">
<TitledBorder title="Status">
<Border PropertyName="innerBorder" info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.progressTextArea.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>

View File

@ -71,7 +71,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
donePanel.setVisible(false);
viewLogButton.setVisible(false);
//match visual background of panel
this.TextArea_CurrentDirectory.setBackground(this.getBackground());
this.progressTextArea.setBackground(this.getBackground());
}
@ -95,10 +95,10 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
/**
* Updates the currently processing directory
*
* @param dir the text to update with
* @param msg the text to update with
*/
public void setCurrentDirText(String dir) {
this.TextArea_CurrentDirectory.setText(dir);
public void setProgressMsgText(String msg) {
this.progressTextArea.setText(msg);
}
/**
@ -140,7 +140,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
inProgressPanel = new javax.swing.JPanel();
progressBar = new javax.swing.JProgressBar();
progressLabel = new javax.swing.JLabel();
TextArea_CurrentDirectory = new javax.swing.JTextArea();
progressTextArea = new javax.swing.JTextArea();
subTitle2Label = new javax.swing.JLabel();
subTitle1Label = new javax.swing.JLabel();
@ -193,14 +193,14 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressLabel.text")); // NOI18N
progressLabel.setPreferredSize(null);
TextArea_CurrentDirectory.setEditable(false);
TextArea_CurrentDirectory.setBackground(new java.awt.Color(240, 240, 240));
TextArea_CurrentDirectory.setLineWrap(true);
TextArea_CurrentDirectory.setRows(5);
TextArea_CurrentDirectory.setWrapStyleWord(true);
TextArea_CurrentDirectory.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title"))); // NOI18N
TextArea_CurrentDirectory.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
TextArea_CurrentDirectory.setFocusable(false);
progressTextArea.setEditable(false);
progressTextArea.setBackground(new java.awt.Color(240, 240, 240));
progressTextArea.setLineWrap(true);
progressTextArea.setRows(5);
progressTextArea.setWrapStyleWord(true);
progressTextArea.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressTextArea.border.title"))); // NOI18N
progressTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
progressTextArea.setFocusable(false);
org.openide.awt.Mnemonics.setLocalizedText(subTitle2Label, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.subTitle2Label.text")); // NOI18N
@ -216,7 +216,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
.addComponent(subTitle2Label)
.addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(subTitle1Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(TextArea_CurrentDirectory)
.addComponent(progressTextArea)
.addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(0, 8, Short.MAX_VALUE))
);
@ -229,7 +229,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(TextArea_CurrentDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(progressTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
@ -268,12 +268,12 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
dialog.setVisible(true);
}//GEN-LAST:event_viewLogButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
protected javax.swing.JTextArea TextArea_CurrentDirectory;
protected javax.swing.JPanel donePanel;
protected javax.swing.JPanel inProgressPanel;
private javax.swing.JPanel loadingPanel;
private javax.swing.JProgressBar progressBar;
protected javax.swing.JLabel progressLabel;
protected javax.swing.JTextArea progressTextArea;
protected javax.swing.JLabel statusLabel;
protected javax.swing.JLabel subTitle1Label;
protected javax.swing.JLabel subTitle2Label;

View File

@ -43,6 +43,7 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
*/
private AddImageWizardAddingProgressPanel progressPanel;
private AddImageWizardChooseDataSourceVisual component;
private boolean isNextEnable = false;
private static final String PROP_LASTDATASOURCE_PATH = "LBL_LastDataSource_PATH";
@ -50,6 +51,12 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
// paths to any set hash lookup databases (can be null)
private String NSRLPath, knownBadPath;
AddImageWizardChooseDataSourcePanel(AddImageWizardAddingProgressPanel proPanel) {
this.progressPanel = proPanel;
}
/**
* 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
@ -173,13 +180,6 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
// Prepopulate the image directory from the properties file
try {
String lastDataSourceDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_PATH);
String lastDataSourceType = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_TYPE);
//set the last path for the content panel for which it was saved
if (component.getContentType().toString().equals(lastDataSourceType)) {
component.setContentPath(lastDataSourceDirectory);
}
// Load hash database settings, enable or disable the checkbox
this.NSRLPath = null;
@ -216,19 +216,8 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
*/
@Override
public void storeSettings(WizardDescriptor settings) {
settings.putProperty(AddImageAction.DATASOURCEPATH_PROP, getComponent().getContentPaths());
settings.putProperty(AddImageAction.DATASOURCETYPE_PROP, getComponent().getContentType());
settings.putProperty(AddImageAction.TIMEZONE_PROP, getComponent().getSelectedTimezone()); // store the timezone
settings.putProperty(AddImageAction.NOFATORPHANS_PROP, Boolean.valueOf(getComponent().getNoFatOrphans()));
//settings.putProperty(AddImageAction.LOOKUPFILES_PROP, getComponent().getLookupFilesCheckboxChecked());
//settings.putProperty(AddImageAction.SOLR_PROP, getComponent().getIndexImageCheckboxChecked());
// Store the path to the first image selected into the properties file
String firstImage = getComponent().getContentPaths();
String firstImagePath = firstImage.substring(0, firstImage.lastIndexOf(File.separator) + 1);
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_PATH, firstImagePath);
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_TYPE, getComponent().getContentType().toString());
return;
}
/**

View File

@ -39,16 +39,6 @@
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="nextLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="252" max="-2" attributes="0"/>
</Group>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="imgInfoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="54" max="32767" attributes="0"/>
@ -65,16 +55,7 @@
<Component id="imgInfoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="inputPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="64" max="32767" attributes="0"/>
<EmptySpace pref="45" max="32767" attributes="0"/>
<Component id="nextLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
@ -89,41 +70,6 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="inputPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
@ -160,7 +106,7 @@
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="typePanel" pref="77" max="32767" attributes="0"/>
<Component id="typePanel" pref="173" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -192,7 +138,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="77" max="32767" attributes="0"/>
<EmptySpace min="0" pref="173" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -204,7 +150,7 @@
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ContentTypePanel&gt;"/>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>

View File

@ -18,49 +18,44 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import javax.swing.ComboBoxModel;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.JPanel;
import javax.swing.JList;
import javax.swing.JSeparator;
import javax.swing.event.DocumentEvent;
import javax.swing.event.ListDataListener;
import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
import javax.swing.ListCellRenderer;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* visual component for the first panel of add image wizard. Allows user to pick
* data source and timezone.
* visual component for the first panel of add image wizard.
* Allows the user to choose the data source type and then select the data source
*
*/
final class AddImageWizardChooseDataSourceVisual extends JPanel {
enum EVENT {
UPDATE_UI, FOCUS_NEXT
};
static final List<String> rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"});
static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)";
static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc);
static final List<String> encaseExt = Arrays.asList(new String[]{".e01"});
static final String encaseDesc = "Encase Images (*.e01)";
static GeneralFilter encaseFilter = new GeneralFilter(encaseExt, encaseDesc);
static final List<String> allExt = new ArrayList<String>();
static {
allExt.addAll(rawExt);
allExt.addAll(encaseExt);
}
static final String allDesc = "All Supported Types";
static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
static final Logger logger = Logger.getLogger(AddImageWizardChooseDataSourceVisual.class.getName());
private AddImageWizardChooseDataSourcePanel wizPanel;
private ContentTypeModel model;
private ContentTypePanel currentPanel;
private JPanel currentPanel;
private Map<String, DataSourceProcessor> datasourceProcessorsMap = new HashMap<String, DataSourceProcessor>();
List<String> coreDSPTypes = new ArrayList<String>();
/**
* Creates new form AddImageVisualPanel1
@ -70,24 +65,83 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
AddImageWizardChooseDataSourceVisual(AddImageWizardChooseDataSourcePanel wizPanel) {
initComponents();
this.wizPanel = wizPanel;
createTimeZoneList();
customInit();
}
private void customInit() {
model = new ContentTypeModel();
typeComboBox.setModel(model);
typeComboBox.setSelectedIndex(0);
typePanel.setLayout(new BorderLayout());
updateCurrentPanel(ImageFilePanel.getDefault());
discoverDataSourceProcessors();
// set up the DSP type combobox
typeComboBox.removeAllItems();
Set<String> dspTypes = datasourceProcessorsMap.keySet();
// make a list of core DSPs
// ensure that the core DSPs are at the top and in a fixed order
coreDSPTypes.add(ImageDSProcessor.dsType);
coreDSPTypes.add(LocalDiskDSProcessor.dsType);
coreDSPTypes.add(LocalFilesDSProcessor.dsType);
for(String dspType:coreDSPTypes){
typeComboBox.addItem(dspType);
}
// now add any addtional DSPs that haven't already been added
for(String dspType:dspTypes){
if (!coreDSPTypes.contains(dspType)) {
typeComboBox.addItem(dspType);
}
}
// set a custom renderer that draws a separator at the end of the core DSPs in the combobox
typeComboBox.setRenderer(new ComboboxSeparatorRenderer(typeComboBox.getRenderer()){
@Override
protected boolean addSeparatorAfter(JList list, Object value, int index){
return (index == coreDSPTypes.size() - 1);
}
});
//add actionlistner to listen for change
ActionListener cbActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dspSelectionChanged();
}
};
typeComboBox.addActionListener(cbActionListener);
typeComboBox.setSelectedIndex(0);
}
private void discoverDataSourceProcessors() {
for (DataSourceProcessor dsProcessor: Lookup.getDefault().lookupAll(DataSourceProcessor.class)) {
if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) {
dsProcessor.reset();
datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor);
}
else {
logger.log(Level.SEVERE, "discoverDataSourceProcessors(): A DataSourceProcessor already exists for type = " + dsProcessor.getType() );
}
}
}
private void dspSelectionChanged() {
// update the current panel to selection
currentPanel = getCurrentDSProcessor().getPanel();
updateCurrentPanel(currentPanel);
}
/**
* Changes the current panel to the given panel.
*
* @param panel instance of ImageTypePanel to change to
*/
private void updateCurrentPanel(ContentTypePanel panel) {
private void updateCurrentPanel(JPanel panel) {
currentPanel = panel;
typePanel.removeAll();
typePanel.add((JPanel) currentPanel, BorderLayout.CENTER);
@ -96,28 +150,32 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
currentPanel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) {
if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString())) {
updateUI(null);
}
if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) {
if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString())) {
wizPanel.moveFocusToNext();
}
}
});
currentPanel.select();
if (currentPanel.getContentType().equals(ContentType.LOCAL)) {
//disable image specific options
noFatOrphansCheckbox.setEnabled(false);
descLabel.setEnabled(false);
timeZoneComboBox.setEnabled(false);
} else {
noFatOrphansCheckbox.setEnabled(true);
descLabel.setEnabled(true);
timeZoneComboBox.setEnabled(true);
}
updateUI(null);
}
/**
* Returns the currently selected DS Processor
* @return DataSourceProcessor the DataSourceProcessor corresponding to the data source type selected in the combobox
*/
public DataSourceProcessor getCurrentDSProcessor() {
// get the type of the currently selected panel and then look up
// the correspodning DS Handler in the map
String dsType = (String) typeComboBox.getSelectedItem();
DataSourceProcessor dsProcessor = datasourceProcessorsMap.get(dsType);
return dsProcessor;
}
/**
* Returns the name of the this panel. This name will be shown on the left
* panel of the "Add Image" wizard panel.
@ -129,94 +187,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
return "Enter Data Source Information";
}
/**
* Gets the data sources path from the Image Path Text Field.
*
* @return data source path, can be comma separated for multiples
*/
public String getContentPaths() {
return currentPanel.getContentPaths();
}
/**
* Gets the data sources type selected
*
* @return data source selected
*/
public ContentType getContentType() {
return currentPanel.getContentType();
}
/**
* Reset the data sources panel selected
*/
public void reset() {
currentPanel.reset();
}
/**
* Sets the image path of the current panel.
*
* @param s the image path to set
*/
public void setContentPath(String s) {
currentPanel.setContentPath(s);
}
/**
*
* @return true if no fat orphans processing is selected
*/
boolean getNoFatOrphans() {
return noFatOrphansCheckbox.isSelected();
}
/**
* Gets the time zone that selected on the drop down list.
*
* @return timeZone the time zone that selected
*/
public String getSelectedTimezone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
// add the timeZone list to the timeZoneComboBox
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zones to be selected.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
}
/**
* This method is called from within the constructor to initialize the form.
@ -229,14 +199,10 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
buttonGroup1 = new javax.swing.ButtonGroup();
jLabel2 = new javax.swing.JLabel();
nextLabel = new javax.swing.JLabel();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
inputPanel = new javax.swing.JPanel();
typeTabel = new javax.swing.JLabel();
typePanel = new javax.swing.JPanel();
typeComboBox = new javax.swing.JComboBox<ContentTypePanel>();
typeComboBox = new javax.swing.JComboBox<String>();
imgInfoLabel = new javax.swing.JLabel();
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.jLabel2.text")); // NOI18N
@ -245,15 +211,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
org.openide.awt.Mnemonics.setLocalizedText(nextLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.nextLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text")); // NOI18N
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.descLabel.text")); // NOI18N
inputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.typeTabel.text")); // NOI18N
@ -269,7 +226,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
);
typePanelLayout.setVerticalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 77, Short.MAX_VALUE)
.addGap(0, 173, Short.MAX_VALUE)
);
javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel);
@ -295,7 +252,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
.addComponent(typeTabel)
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 77, Short.MAX_VALUE)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
.addContainerGap())
);
@ -313,14 +270,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel)
.addGap(18, 18, 18)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 252, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel))
.addComponent(imgInfoLabel))
.addGap(0, 54, Short.MAX_VALUE)))
.addContainerGap())
@ -332,30 +281,18 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
.addComponent(imgInfoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.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))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(descLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 64, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 45, Short.MAX_VALUE)
.addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JLabel descLabel;
private javax.swing.JLabel imgInfoLabel;
private javax.swing.JPanel inputPanel;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel nextLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JComboBox<String> timeZoneComboBox;
private javax.swing.JLabel timeZoneLabel;
private javax.swing.JComboBox<ContentTypePanel> typeComboBox;
private javax.swing.JComboBox<String> typeComboBox;
private javax.swing.JPanel typePanel;
private javax.swing.JLabel typeTabel;
// End of variables declaration//GEN-END:variables
@ -369,44 +306,31 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
* @param e the document event
*/
public void updateUI(DocumentEvent e) {
this.wizPanel.enableNextButton(currentPanel.enableNext());
// Enable the Next button if the current DSP panel is valid
this.wizPanel.enableNextButton(getCurrentDSProcessor().validatePanel());
}
/**
* ComboBoxModel to control typeComboBox and supply ImageTypePanels.
*/
private class ContentTypeModel implements ComboBoxModel<ContentTypePanel> {
public abstract class ComboboxSeparatorRenderer implements ListCellRenderer{
private ListCellRenderer delegate;
private JPanel separatorPanel = new JPanel(new BorderLayout());
private JSeparator separator = new JSeparator();
private ContentTypePanel selected;
private ContentTypePanel[] types = ContentTypePanel.getPanels();
@Override
public void setSelectedItem(Object anItem) {
selected = (ContentTypePanel) anItem;
updateCurrentPanel(selected);
public ComboboxSeparatorRenderer(ListCellRenderer delegate){
this.delegate = delegate;
}
@Override
public Object getSelectedItem() {
return selected;
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
Component comp = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if(index!=-1 && addSeparatorAfter(list, value, index)){
separatorPanel.removeAll();
separatorPanel.add(comp, BorderLayout.CENTER);
separatorPanel.add(separator, BorderLayout.SOUTH);
return separatorPanel;
}else
return comp;
}
@Override
public int getSize() {
return types.length;
}
@Override
public ContentTypePanel getElementAt(int index) {
return types[index];
}
@Override
public void addListDataListener(ListDataListener l) {
}
@Override
public void removeListDataListener(ListDataListener l) {
}
protected abstract boolean addSeparatorAfter(JList list, Object value, int index);
}
}

View File

@ -18,41 +18,25 @@
*/
package org.sleuthkit.autopsy.casemodule;
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Window;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* second panel of add image wizard, allows user to configure ingest modules.
*
@ -68,28 +52,27 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
* component from this class, just use getComponent().
*/
private Component component = null;
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
private boolean ingested = false;
private boolean readyToIngest = false;
// the paths of the image files to be added
private String dataSourcePath;
private ContentType dataSourceType;
// the time zone where the image is added
private String timeZone;
//whether to not process FAT filesystem orphans
private boolean noFatOrphans;
// task that will clean up the created database file if the wizard is cancelled before it finishes
private AddImageAction.CleanupTask cleanupImage; // initialized to null in readSettings()
private CurrentDirectoryFetcher fetcher;
private AddImageProcess process;
private AddImageAction action;
private AddImageTask addImageTask;
private AddLocalFilesTask addLocalFilesTask;
private AddImageAction.CleanupTask cleanupTask;
private AddImageAction addImageAction;
private AddImageWizardAddingProgressPanel progressPanel;
private AddImageWizardChooseDataSourcePanel dataSourcePanel;
private DataSourceProcessor dsProcessor;
AddImageWizardIngestConfigPanel(AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
this.action = action;
AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
this.addImageAction = action;
this.progressPanel = proPanel;
this.dataSourcePanel = dsPanel;
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
List<String> messages = ingestConfig.setContext(AddImageWizardIngestConfigPanel.class.getCanonicalName());
if (messages.isEmpty() == false) {
@ -183,24 +166,14 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
JButton cancel = new JButton("Cancel");
cancel.setEnabled(false);
settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, cancel});
cleanupImage = null;
cleanupTask = null;
readyToIngest = false;
newContents.clear();
dataSourcePath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP);
dataSourceType = (ContentType) settings.getProperty(AddImageAction.DATASOURCETYPE_PROP);
timeZone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString();
noFatOrphans = ((Boolean) settings.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue();
//start the process of adding the content
if (dataSourceType.equals(ContentType.LOCAL)) {
addLocalFilesTask = new AddLocalFilesTask(settings);
addLocalFilesTask.execute();
} else {
//disk or image
addImageTask = new AddImageTask(settings);
addImageTask.execute();
}
// 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(settings);
}
/**
@ -234,470 +207,98 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
}
}
/**
* Class for getting the currently processing directory.
*
/**
* Starts the Data source processing by kicking off the selected DataSourceProcessor
*/
private static class CurrentDirectoryFetcher extends SwingWorker<Integer, Integer> {
AddImageTask task;
JProgressBar prog;
AddImageWizardAddingProgressVisual wiz;
AddImageProcess proc;
CurrentDirectoryFetcher(JProgressBar prog, AddImageWizardAddingProgressVisual wiz, AddImageProcess proc) {
this.wiz = wiz;
this.proc = proc;
this.prog = prog;
}
/**
* @return the currently processing directory
*/
@Override
protected Integer doInBackground() {
try {
while (prog.getValue() < 100 || prog.isIndeterminate()) { //TODO Rely on state variable in AddImgTask class
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
wiz.setCurrentDirText(proc.currentDirectory());
}
});
Thread.sleep(2 * 1000);
}
return 1;
} catch (InterruptedException ie) {
return -1;
}
}
}
/**
* Thread that will add logical files to database, and then kick-off ingest
* modules. Note: the add logical files task cannot currently be reverted as
* the add image task can. This is a separate task from AddImgTask because
* it is much simpler and does not require locks, since the underlying file
* manager methods acquire the locks for each transaction when adding
* logical files.
*/
private class AddLocalFilesTask extends SwingWorker<Integer, Integer> {
private JProgressBar progressBar;
private Case currentCase;
// true if the process was requested to stop
private boolean interrupted = false;
private boolean hasCritError = false;
private String errorString = null;
private WizardDescriptor settings;
private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName());
protected AddLocalFilesTask(WizardDescriptor settings) {
this.progressBar = progressPanel.getComponent().getProgressBar();
currentCase = Case.getCurrentCase();
this.settings = settings;
}
/**
* Starts the addImage process, but does not commit the results.
*
* @return
*
* @throws Exception
*/
@Override
protected Integer doInBackground() {
this.setProgress(0);
// Add a cleanup task to interupt the backgroud process if the
// wizard exits while the background process is running.
AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() {
@Override
void cleanup() throws Exception {
logger.log(Level.INFO, "Add logical files process interrupted.");
//nothing to be cleanedup
}
};
cancelledWhileRunning.enable();
final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(this.progressBar, progressPanel.getComponent());
try {
final FileManager fileManager = currentCase.getServices().getFileManager();
progressPanel.setStateStarted();
String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP);
List<String> absLocalPaths = new ArrayList<String>();
for (String path : paths) {
absLocalPaths.add(path);
}
newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex);
hasCritError = true;
errorString = ex.getMessage();
} finally {
// process is over, doesn't need to be dealt with if cancel happens
cancelledWhileRunning.disable();
//enqueue what would be in done() to EDT thread
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
postProcess();
}
});
}
return 0;
}
/**
*
* (called by EventDispatch Thread after doInBackground finishes)
*/
protected void postProcess() {
progressBar.setIndeterminate(false);
setProgress(100);
//clear updates
// progressPanel.getComponent().setProcessInvis();
if (interrupted || hasCritError) {
logger.log(Level.INFO, "Handling errors or interruption that occured in logical files process");
if (hasCritError) {
//core error
progressPanel.getComponent().showErrors(errorString, true);
}
return;
} else {
if (errorString != null) {
//data error (non-critical)
logger.log(Level.INFO, "Handling non-critical errors that occured in logical files process");
progressPanel.getComponent().showErrors(errorString, false);
}
}
try {
// When everything happens without an error:
if (errorString == null) { // complete progress bar
progressPanel.getComponent().setProgressBarTextAndColor("*Logical Files added.", 100, Color.black);
}
// Get attention for the process finish
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
if (panel != null) {
Window w = SwingUtilities.getWindowAncestor(panel);
if (w != null) {
w.toFront();
}
}
progressPanel.setStateFinished();
//notify the case
if (!newContents.isEmpty()) {
Case.getCurrentCase().addLocalDataSource(newContents.get(0));
}
// Start ingest if we can
startIngest();
} catch (Exception ex) {
//handle unchecked exceptions
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
logger.log(Level.SEVERE, "Error adding image to case", ex);
}
}
/**
* Updates the wizard status with logical file/folder
*/
private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater {
private int count = 0;
private JProgressBar prog;
private AddImageWizardAddingProgressVisual wiz;
LocalFilesAddProgressUpdater(JProgressBar prog, AddImageWizardAddingProgressVisual wiz) {
this.wiz = wiz;
this.prog = prog;
}
private void startDataSourceProcessing(WizardDescriptor settings) {
// Add a cleanup task to interrupt the background process if the
// wizard exits while the background process is running.
cleanupTask = addImageAction.new CleanupTask() {
@Override
public void fileAdded(final AbstractFile newFile) {
if (count++ % 10 == 0 && (prog.getValue() < 100 || prog.isIndeterminate())) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
wiz.setCurrentDirText(newFile.getParentPath() + "/" + newFile.getName());
}
});
}
void cleanup() throws Exception {
cancelDataSourceProcessing();
}
}
};
cleanupTask.enable();
// get the selected DSProcessor
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
DSPCallback cbObj = new DSPCallback () {
@Override
public void doneEDT(DSPCallback.DSP_Result result, List<String> errList, List<Content> contents) {
dataSourceProcessorDone(result, errList, contents );
}
};
progressPanel.setStateStarted();
// Kick off the DSProcessor
dsProcessor.run(progressPanel.getDSPProgressMonitorImpl(), cbObj);
}
/**
* Thread that will make the JNI call to add image to database, and then
* kick-off ingest modules.
/*
* Cancels the data source processing - in case the users presses 'Cancel'
*/
private class AddImageTask extends SwingWorker<Integer, Integer> {
private JProgressBar progressBar;
private Case currentCase;
// true if the process was requested to stop
private boolean interrupted = false;
private boolean hasCritError = false;
private String errorString = null;
private WizardDescriptor wizDescriptor;
private Logger logger = Logger.getLogger(AddImageTask.class.getName());
protected AddImageTask(WizardDescriptor settings) {
this.progressBar = progressPanel.getComponent().getProgressBar();
currentCase = Case.getCurrentCase();
this.wizDescriptor = settings;
}
/**
* Starts the addImage process, but does not commit the results.
*
* @return
*
* @throws Exception
*/
@Override
protected Integer doInBackground() {
this.setProgress(0);
// Add a cleanup task to interupt the backgroud process if the
// wizard exits while the background process is running.
AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() {
@Override
void cleanup() throws Exception {
logger.log(Level.INFO, "Add image process interrupted.");
addImageTask.interrupt(); //it might take time to truly interrupt
}
};
try {
//lock DB for writes in EWT thread
//wait until lock acquired in EWT
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
SleuthkitCase.dbWriteLock();
}
});
} catch (InterruptedException ex) {
logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex);
return 0;
} catch (InvocationTargetException ex) {
logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex);
return 0;
}
process = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
fetcher = new CurrentDirectoryFetcher(this.progressBar, progressPanel.getComponent(), process);
cancelledWhileRunning.enable();
try {
progressPanel.setStateStarted();
fetcher.execute();
process.run(new String[]{dataSourcePath});
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex);
//critical core/system error and process needs to be interrupted
hasCritError = true;
errorString = ex.getMessage();
} catch (TskDataException ex) {
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex);
errorString = ex.getMessage();
} finally {
// process is over, doesn't need to be dealt with if cancel happens
cancelledWhileRunning.disable();
}
return 0;
}
/**
* Commit the finished AddImageProcess, and cancel the CleanupTask that
* would have reverted it.
*
* @param settings property set to get AddImageProcess and CleanupTask
* from
*
* @throws Exception if commit or adding the image to the case failed
*/
private void commitImage(WizardDescriptor settings) throws Exception {
String contentPath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP);
String timezone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString();
settings.putProperty(AddImageAction.IMAGEID_PROP, "");
long imageId = 0;
try {
imageId = process.commit();
} catch (TskException e) {
logger.log(Level.WARNING, "Errors occured while committing the image", e);
} finally {
//commit done, unlock db write in EWT thread
//before doing anything else
SleuthkitCase.dbWriteUnlock();
if (imageId != 0) {
Image newImage = Case.getCurrentCase().addImage(contentPath, imageId, timezone);
//while we have the image, verify the size of its contents
String verificationErrors = newImage.verifyImageSize();
if (verificationErrors.equals("") == false) {
//data error (non-critical)
progressPanel.addErrors(verificationErrors, false);
}
newContents.add(newImage);
settings.putProperty(AddImageAction.IMAGEID_PROP, imageId);
}
// Can't bail and revert image add after commit, so disable image cleanup
// task
cleanupImage.disable();
settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null);
logger.log(Level.INFO, "Image committed, imageId: " + imageId);
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
private void cancelDataSourceProcessing() {
dsProcessor.cancel();
}
/*
* Callback for the data source processor.
* Invoked by the DSP on the EDT thread, when it finishes processing the data source.
*/
private void dataSourceProcessorDone(DSPCallback.DSP_Result result, List<String> errList, List<Content> contents) {
// disable the cleanup task
cleanupTask.disable();
// Get attention for the process finish
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
if (panel != null) {
Window w = SwingUtilities.getWindowAncestor(panel);
if (w != null) {
w.toFront();
}
}
/**
*
* (called by EventDispatch Thread after doInBackground finishes)
*/
@Override
protected void done() {
//these are required to stop the CurrentDirectoryFetcher
progressBar.setIndeterminate(false);
setProgress(100);
// attempt actions that might fail and force the process to stop
if (interrupted || hasCritError) {
logger.log(Level.INFO, "Handling errors or interruption that occured in add image process");
revert();
if (hasCritError) {
//core error
progressPanel.addErrors(errorString, true);
}
return;
}
if (errorString != null) {
//data error (non-critical)
logger.log(Level.INFO, "Handling non-critical errors that occured in add image process");
progressPanel.addErrors(errorString, false);
}
try {
// When everything happens without an error:
// the add-image process needs to be reverted if the wizard doesn't finish
cleanupImage = action.new CleanupTask() {
//note, CleanupTask runs inside EWT thread
@Override
void cleanup() throws Exception {
logger.log(Level.INFO, "Running cleanup task after add image process");
revert();
}
};
cleanupImage.enable();
if (errorString == null) { // complete progress bar
progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black);
}
// Get attention for the process finish
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
if (panel != null) {
Window w = SwingUtilities.getWindowAncestor(panel);
if (w != null) {
w.toFront();
}
}
// Tell the panel we're done
progressPanel.setStateFinished();
// Commit the image
if (!newContents.isEmpty()) //already commited
{
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
return;
}
if (process != null) { // and if we're done configuring ingest
// commit anything
try {
commitImage(wizDescriptor);
} catch (Exception ex) {
// Log error/display warning
logger.log(Level.SEVERE, "Error adding image to case.", ex);
}
} else {
logger.log(Level.SEVERE, "Missing image process object");
}
// Start ingest if we can
startIngest();
} catch (Exception ex) {
//handle unchecked exceptions post image add
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
// Log error/display warning
logger.log(Level.SEVERE, "Error adding image to case", ex);
} finally {
}
// Tell the panel we're done
progressPanel.setStateFinished();
//check the result and display to user
if (result == DSPCallback.DSP_Result.NO_ERRORS)
progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black);
else
progressPanel.getComponent().setProgressBarTextAndColor("*Errors encountered in adding Data Source.", 100, Color.red);
//if errors, display them on the progress panel
for ( String err: errList ) {
// TBD: there probably should be an error level for each error
progressPanel.addErrors(err, false);
}
newContents.clear();
newContents.addAll(contents);
//notify the UI of the new content added to the case
if (!newContents.isEmpty()) {
Case.getCurrentCase().notifyNewDataSource(newContents.get(0));
}
void interrupt() throws Exception {
interrupted = true;
try {
logger.log(Level.INFO, "interrupt() add image process");
process.stop(); //it might take time to truly stop processing and writing to db
} catch (TskException ex) {
throw new Exception("Error stopping add-image process.", ex);
}
}
//runs in EWT
void revert() {
try {
logger.log(Level.INFO, "Revert after add image process");
try {
process.revert();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error reverting add image process", ex);
}
} finally {
//unlock db write within EWT thread
SleuthkitCase.dbWriteUnlock();
}
}
// Start ingest if we can
progressPanel.setStateStarted();
startIngest();
}
}

View File

@ -47,11 +47,16 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDescript
*/
private List<WizardDescriptor.Panel<WizardDescriptor>> getPanels() {
if (panels == null) {
AddImageWizardAddingProgressPanel wizPanel = new AddImageWizardAddingProgressPanel();
panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>();
panels.add(new AddImageWizardChooseDataSourcePanel());
panels.add(new AddImageWizardIngestConfigPanel(action, wizPanel));
panels.add(wizPanel);
AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel();
AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel);
AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel);
panels.add(dsPanel);
panels.add(ingestConfigPanel);
panels.add(progressPanel);
String[] steps = new String[panels.size()];
for (int i = 0; i < panels.size(); i++) {

View File

@ -0,0 +1,185 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Thread that will add logical files to database, and then kick-off ingest
* modules. Note: the add logical files task cannot currently be reverted as
* the add image task can. This is a separate task from AddImgTask because
* it is much simpler and does not require locks, since the underlying file
* manager methods acquire the locks for each transaction when adding
* logical files.
*/
public class AddLocalFilesTask implements Runnable {
private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName());
private String dataSourcePath;
private DSPProgressMonitor progressMonitor;
private DSPCallback callbackObj;
private Case currentCase;
// true if the process was requested to stop
private volatile boolean cancelled = false;
private boolean hasCritError = false;
private List<String> errorList = new ArrayList<String>();
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
protected AddLocalFilesTask(String dataSourcePath, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj) {
currentCase = Case.getCurrentCase();
this.dataSourcePath = dataSourcePath;
this.callbackObj = cbObj;
this.progressMonitor = aProgressMonitor;
}
/**
* Starts the addImage process, but does not commit the results.
*
* @return
*
* @throws Exception
*/
@Override
public void run() {
errorList.clear();
final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(progressMonitor);
try {
progressMonitor.setIndeterminate(true);
progressMonitor.setProgress(0);
final FileManager fileManager = currentCase.getServices().getFileManager();
String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP);
List<String> absLocalPaths = new ArrayList<String>();
for (String path : paths) {
absLocalPaths.add(path);
}
newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex);
hasCritError = true;
errorList.add(ex.getMessage());
} finally {
}
// handle done
postProcess();
return;
}
/**
*
* (called by EventDispatch Thread after doInBackground finishes)
*/
protected void postProcess() {
if (cancelled || hasCritError) {
logger.log(Level.WARNING, "Handling errors or interruption that occured in logical files process");
}
if (!errorList.isEmpty()) {
//data error (non-critical)
logger.log(Level.WARNING, "Handling non-critical errors that occured in logical files process");
}
if (!(cancelled || hasCritError)) {
progressMonitor.setProgress(100);
progressMonitor.setIndeterminate(false);
}
// invoke the callBack, unless the caller cancelled
if (!cancelled) {
doCallBack();
}
}
/*
* Call the callback with results, new content, and errors, if any
*/
private void doCallBack()
{
DSPCallback.DSP_Result result;
if (hasCritError) {
result = DSPCallback.DSP_Result.CRITICAL_ERRORS;
}
else if (!errorList.isEmpty()) {
result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS;
}
else {
result = DSPCallback.DSP_Result.NO_ERRORS;
}
// invoke the callback, passing it the result, list of new contents, and list of errors
callbackObj.done(result, errorList, newContents);
}
/*
* cancel the files addition, if possible
*/
public void cancelTask() {
cancelled = true;
}
/**
* Updates the wizard status with logical file/folder
*/
private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater {
private int count = 0;
private DSPProgressMonitor progressMonitor;
LocalFilesAddProgressUpdater(DSPProgressMonitor progressMonitor) {
this.progressMonitor = progressMonitor;
}
@Override
public void fileAdded(final AbstractFile newFile) {
if (count++ % 10 == 0) {
progressMonitor.setProgressText("Adding: " + newFile.getParentPath() + "/" + newFile.getName());
}
}
}
}

View File

@ -115,7 +115,6 @@ ImageFilePanel.browseButton.text=Browse
ImageFilePanel.pathTextField.text=
LocalDiskPanel.diskLabel.text=Select a local disk:
MissingImageDialog.selectButton.text=Select Image
MissingImageDialog.typeTabel.text=Select input type to add:
MissingImageDialog.titleLabel.text=Search for missing image
MissingImageDialog.cancelButton.text=Cancel
LocalDiskPanel.errorLabel.text=Error Label
@ -134,17 +133,23 @@ LocalFilesPanel.selectButton.actionCommand=Add
AddImageWizardIngestConfigVisual.subtitleLabel.text=Configure the ingest modules you would like to run on this data source.
AddImageWizardIngestConfigVisual.titleLabel.text=Configure Ingest Modules
AddImageWizardAddingProgressVisual.statusLabel.text=File system has been added to the local database. Files are being analyzed.
AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText=
AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
AddImageWizardChooseDataSourceVisual.descLabel.text=(faster results, although some data will not be searched)
AddImageWizardChooseDataSourceVisual.typeTabel.text=Select source type to add:
AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2
AddImageWizardChooseDataSourceVisual.timeZoneLabel.text=Please select the input timezone:
AddImageWizardChooseDataSourceVisual.nextLabel.text=<html> Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database.</html>
AddImageWizardChooseDataSourceVisual.imgInfoLabel.text=Enter Data Source Information:
AddImageWizardAddingProgressVisual.progressLabel.text=<progress>
AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title=Currently Adding:
AddImageWizardAddingProgressVisual.viewLogButton.text=View Log
AddImageWizardAddingProgressVisual.titleLabel.text=Adding Data Source
AddImageWizardAddingProgressVisual.subTitle1Label.text=File system information is being added to a local database. File analysis will start when this finishes.
AddImageWizardAddingProgressVisual.subTitle2Label.text=Processing Data Source and Adding to Database
ImageFilePanel.timeZoneLabel.text=Please select the input timezone:
ImageFilePanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
ImageFilePanel.noFatOrphansCheckbox.toolTipText=
ImageFilePanel.descLabel.text=(faster results, although some data will not be searched)
LocalDiskPanel.timeZoneLabel.text=Please select the input timezone:
LocalDiskPanel.noFatOrphansCheckbox.toolTipText=
LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched)
MissingImageDialog.browseButton.text=Browse
MissingImageDialog.pathNameTextField.text=
AddImageWizardAddingProgressVisual.progressTextArea.border.title=Status

View File

@ -384,7 +384,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
+ "\nPlease note that you will still be able to browse directories and generate reports\n"
+ "if you choose No, but you will not be able to view file content or run the ingest process.", "Missing Image", JOptionPane.YES_NO_OPTION);
if (ret == JOptionPane.YES_OPTION) {
MissingImageDialog.makeDialog(obj_id, db);
} else {
logger.log(Level.WARNING, "Selected image files don't match old files!");
}
@ -401,6 +403,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
* @param imgId the ID of the image that being added
* @param timeZone the timeZone of the image where it's added
*/
@Deprecated
public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException {
logger.log(Level.INFO, "Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}", new Object[]{imgPath, imgId, timeZone});
@ -420,11 +423,23 @@ public class Case implements SleuthkitCase.ErrorObserver {
*
* @param newDataSource new data source added
*/
@Deprecated
void addLocalDataSource(Content newDataSource) {
pcs.firePropertyChange(CASE_ADD_DATA_SOURCE, null, newDataSource);
CoreComponentControl.openCoreWindows();
}
/**
* Notifies the UI that a new data source has been added.
*
*
* @param newDataSource new data source added
*/
void notifyNewDataSource(Content newDataSource) {
pcs.firePropertyChange(CASE_ADD_DATA_SOURCE, null, newDataSource);
CoreComponentControl.openCoreWindows();
}
/**
* @return The Services object for this case.
*/

View File

@ -1,72 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
import java.beans.PropertyChangeListener;
import javax.swing.JPanel;
abstract class ContentTypePanel extends JPanel {
public enum ContentType{IMAGE, DISK, LOCAL};
/**
* Returns a list off all the panels extending ImageTypePanel.
* @return list of all ImageTypePanels
*/
public static ContentTypePanel[] getPanels() {
return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() };
}
/**
* Return the path of the selected content in this panel.
* @return paths to selected content (one or more if multiselect supported)
*/
abstract public String getContentPaths();
/**
* Set the selected content in this panel to the provided path.
* This function is optional.
* @param s path to selected content
*/
abstract public void setContentPath(String s);
/**
* Get content type (image, disk, local file) of the source this wizard panel is for
* @return ContentType of the source panel
*/
abstract public ContentType getContentType();
/**
* Returns if the next button should be enabled in the current wizard.
* @return true if the next button should be enabled, false otherwise
*/
abstract public boolean enableNext();
/**
* Tells this panel to reset itself
*/
abstract public void reset();
/**
* Tells this panel it has been selected.
*/
abstract public void select();
}

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.util.List;
import java.util.Arrays;
import javax.swing.filechooser.FileFilter;
/**
@ -28,6 +29,16 @@ import javax.swing.filechooser.FileFilter;
*/
public class GeneralFilter extends FileFilter{
// Extensions & Descriptions for commonly used filters
public static final List<String> RAW_IMAGE_EXTS = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw", ".bin"});
public static final String RAW_IMAGE_DESC = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)";
public static final List<String> ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"});
public static final String ENCASE_IMAGE_DESC = "Encase Images (*.e01)";
private List<String> extensions;
private String desc;

View File

@ -0,0 +1,218 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
import java.util.logging.Level;
import javax.swing.JPanel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.filechooser.FileFilter;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* Image data source processor.
* Handles the addition of "disk images" to Autopsy.
*
* An instance of this class is created via the Netbeans Lookup() method.
*
*/
@ServiceProvider(service = DataSourceProcessor.class)
public class ImageDSProcessor implements DataSourceProcessor {
static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName());
// Data source type handled by this processor
protected final static String dsType = "Image File";
// The Config UI panel that plugins into the Choose Data Source Wizard
private ImageFilePanel imageFilePanel;
// The Background task that does the actual work of adding the image
private AddImageTask addImageTask;
// true of cancelled by the caller
private boolean cancelled = false;
DSPCallback callbackObj = null;
// set to TRUE if the image options have been set via API and config Jpanel should be ignored
private boolean imageOptionsSet = false;
// image options
private String imagePath;
private String timeZone;
private boolean noFatOrphans;
static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC);
static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC);
static final List<String> allExt = new ArrayList<String>();
static {
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
}
static final String allDesc = "All Supported Types";
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
static final List<FileFilter> filtersList = new ArrayList<FileFilter>();
static {
filtersList.add(allFilter);
filtersList.add(rawFilter);
filtersList.add(encaseFilter);
}
/*
* A no argument constructor is required for the NM lookup() method to create an object
*/
public ImageDSProcessor() {
// Create the config panel
imageFilePanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList);
}
/**
* Returns the Data source type (string) handled by this DSP
*
* @return String the data source type
**/
@Override
public String getType() {
return dsType;
}
/**
* Returns the JPanel for collecting the Data source information
*
* @return JPanel the config panel
**/
@Override
public JPanel getPanel() {
imageFilePanel.readSettings();
imageFilePanel.select();
return imageFilePanel;
}
/**
* Validates the data collected by the JPanel
*
* @return String returns NULL if success, error string if there is any errors
**/
@Override
public boolean validatePanel() {
return imageFilePanel.validatePanel();
}
/**
* Runs the data source processor.
* This must kick off processing the data source in background
*
* @param progressMonitor Progress monitor to report progress during processing
* @param cbObj callback to call when processing is done.
**/
@Override
public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) {
callbackObj = cbObj;
cancelled = false;
if (!imageOptionsSet)
{
//tell the panel to save the current settings
imageFilePanel.storeSettings();
// get the image options from the panel
imagePath = imageFilePanel.getContentPaths();
timeZone = imageFilePanel.getTimeZone();
noFatOrphans = imageFilePanel.getNoFatOrphans();
}
addImageTask = new AddImageTask(imagePath, timeZone, noFatOrphans, progressMonitor, cbObj);
new Thread(addImageTask).start();
return;
}
/**
* Cancel the data source processing
**/
@Override
public void cancel() {
cancelled = true;
addImageTask.cancelTask();
return;
}
/**
* Reset the data source processor
**/
@Override
public void reset() {
// reset the config panel
imageFilePanel.reset();
// reset state
imageOptionsSet = false;
imagePath = null;
timeZone = null;
noFatOrphans = false;
return;
}
/**
* Sets the data source options externally.
* To be used by a client that does not have a UI and does not use the JPanel to
* collect this information from a user.
*
* @param imgPath path to thew image or first image
* @param String timeZone
* @param noFat whether to parse FAT orphans
**/
public void setDataSourceOptions(String imgPath, String tz, boolean noFat) {
this.imagePath = imgPath;
this.timeZone = tz;
this.noFatOrphans = noFat;
imageOptionsSet = true;
}
}

View File

@ -31,8 +31,20 @@
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="284" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="20" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -45,6 +57,16 @@
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -74,5 +96,40 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -22,41 +22,71 @@ import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import javax.swing.JFileChooser;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
/**
* ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc.
*/
public class ImageFilePanel extends ContentTypePanel implements DocumentListener {
private static ImageFilePanel instance = null;
public class ImageFilePanel extends JPanel implements DocumentListener {
private final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH";
private PropertyChangeSupport pcs = null;
private JFileChooser fc = new JFileChooser();
// Externally supplied name is used to store settings
private String contextName;
/**
* Creates new form ImageFilePanel
* @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
*/
public ImageFilePanel() {
private ImageFilePanel(String context, List<FileFilter> fileChooserFilters) {
initComponents();
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.rawFilter);
fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.encaseFilter);
fc.setFileFilter(AddImageWizardChooseDataSourceVisual.allFilter);
boolean firstFilter = true;
for (FileFilter filter: fileChooserFilters ) {
if (firstFilter) { // set the first on the list as the default selection
fc.setFileFilter(filter);
firstFilter = false;
}
else {
fc.addChoosableFileFilter(filter);
}
}
this.contextName = context;
pcs = new PropertyChangeSupport(this);
createTimeZoneList();
}
/**
* Returns the default instance of a ImageFilePanel.
* Creates and returns an instance of a ImageFilePanel.
*/
public static synchronized ImageFilePanel getDefault() {
if (instance == null) {
instance = new ImageFilePanel();
instance.postInit();
}
return instance;
public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters );
instance.postInit();
return instance;
}
//post-constructor initialization to properly initialize listener support
@ -79,6 +109,10 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
pathLabel = new javax.swing.JLabel();
browseButton = new javax.swing.JButton();
pathTextField = new javax.swing.JTextField();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(403, 65));
@ -94,6 +128,15 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
pathTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.text")); // NOI18N
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.descLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -104,8 +147,17 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
.addComponent(browseButton)
.addGap(2, 2, 2))
.addGroup(layout.createSequentialGroup()
.addComponent(pathLabel)
.addGap(0, 284, Short.MAX_VALUE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(pathLabel)
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel)))
.addGap(0, 20, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -114,7 +166,16 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
.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)))
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.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))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(descLabel)
.addContainerGap(33, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@ -131,20 +192,23 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
String path = fc.getSelectedFile().getPath();
pathTextField.setText(path);
}
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true);
}//GEN-LAST:event_browseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JLabel descLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JLabel pathLabel;
private javax.swing.JTextField pathTextField;
private javax.swing.JComboBox<String> timeZoneComboBox;
private javax.swing.JLabel timeZoneLabel;
// End of variables declaration//GEN-END:variables
/**
* Get the path of the user selected image.
* @return the image path
*/
@Override
public String getContentPaths() {
return pathTextField.getText();
}
@ -152,33 +216,37 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
/**
* Set the path of the image file.
*/
@Override
public void setContentPath(String s) {
pathTextField.setText(s);
}
@Override
public ContentType getContentType() {
return ContentType.IMAGE;
public String getTimeZone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
public boolean getNoFatOrphans() {
return noFatOrphansCheckbox.isSelected();
}
@Override
public void reset() {
//nothing to reset
//reset the UI elements to default
pathTextField.setText(null);
}
/**
* Should we enable the next button of the wizard?
* @return true if a proper image has been selected, false otherwise
*/
@Override
public boolean enableNext() {
public boolean validatePanel() {
String path = getContentPaths();
if (path == null || path.isEmpty()) {
return false;
}
boolean isExist = Case.pathExists(path);
boolean isPhysicalDrive = Case.isPhysicalDrive(path);
boolean isPartition = Case.isPartition(path);
@ -186,6 +254,57 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
return (isExist || isPhysicalDrive || isPartition);
}
public void storeSettings() {
String imagePathName = getContentPaths();
if (null != imagePathName ) {
String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1);
ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, imagePath);
}
}
public void readSettings() {
String lastImagePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH);
if (null != lastImagePath) {
if (!lastImagePath.isEmpty())
pathTextField.setText(lastImagePath);
}
}
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zone to be selected.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
}
/**
* Update functions are called by the pathTextField which has this set
* as it's DocumentEventListener. Each update function fires a property change
@ -194,34 +313,26 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
*/
@Override
public void insertUpdate(DocumentEvent e) {
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
@Override
public void removeUpdate(DocumentEvent e) {
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
@Override
public void changedUpdate(DocumentEvent e) {
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
/**
* Set the focus to the pathTextField.
*/
@Override
public void select() {
pathTextField.requestFocusInWindow();
}
/**
* @return the string form of this panel
*/
@Override
public String toString() {
return "Image File";
}
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) {

View File

@ -0,0 +1,184 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
import javax.swing.JPanel;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
@ServiceProvider(service = DataSourceProcessor.class)
public class LocalDiskDSProcessor implements DataSourceProcessor {
static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName());
// Data source type handled by this processor
static protected final String dsType = "Local Disk";
// The Config UI panel that plugins into the Choose Data Source Wizard
private LocalDiskPanel localDiskPanel;
// The Background task that does the actual work of adding the local Disk
// Adding a local disk is exactly same as adding an Image.
private AddImageTask addDiskTask;
// true if cancelled by the caller
private boolean cancelled = false;
DSPCallback callbackObj = null;
// set to TRUE if the image options have been set via API and config Jpanel should be ignored
private boolean localDiskOptionsSet = false;
// data source options
private String localDiskPath;
private String timeZone;
private boolean noFatOrphans;
/*
* A no argument constructor is required for the NM lookup() method to create an object
*/
public LocalDiskDSProcessor() {
// Create the config panel
localDiskPanel = LocalDiskPanel.getDefault();
}
/**
* Returns the Data source type (string) handled by this DSP
*
* @return String the data source type
**/
@Override
public String getType() {
return dsType;
}
/**
* Returns the JPanel for collecting the Data source information
*
* @return JPanel the config panel
**/
@Override
public JPanel getPanel() {
localDiskPanel.select();
return localDiskPanel;
}
/**
* Validates the data collected by the JPanel
*
* @return String returns NULL if success, error string if there is any errors
**/
@Override
public boolean validatePanel() {
return localDiskPanel.validatePanel();
}
/**
* Runs the data source processor.
* This must kick off processing the data source in background
*
* @param progressMonitor Progress monitor to report progress during processing
* @param cbObj callback to call when processing is done.
**/
@Override
public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) {
callbackObj = cbObj;
cancelled = false;
if (!localDiskOptionsSet) {
// get the image options from the panel
localDiskPath = localDiskPanel.getContentPaths();
timeZone = localDiskPanel.getTimeZone();
noFatOrphans = localDiskPanel.getNoFatOrphans();
}
addDiskTask = new AddImageTask(localDiskPath, timeZone, noFatOrphans, progressMonitor, cbObj);
new Thread(addDiskTask).start();
return;
}
/**
* Cancel the data source processing
**/
@Override
public void cancel() {
cancelled = true;
addDiskTask.cancelTask();
return;
}
/**
* Reset the data source processor
**/
@Override
public void reset() {
// reset the config panel
localDiskPanel.reset();
// reset state
localDiskOptionsSet = false;
localDiskPath = null;
timeZone = null;
noFatOrphans = false;
return;
}
/**
* Sets the data source options externally.
* To be used by a client that does not have a UI and does not use the JPanel to
* collect this information from a user.
*
* @param diskPath path to the local disk
* @param String timeZone
* @param noFat whether to parse FAT orphans
**/
public void setDataSourceOptions(String diskPath, String tz, boolean noFat) {
this.localDiskPath = diskPath;
this.timeZone = tz;
this.noFatOrphans = noFat;
localDiskOptionsSet = true;
}
}

View File

@ -29,8 +29,18 @@
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
<Component id="diskComboBox" min="-2" pref="345" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="140" max="32767" attributes="0"/>
<EmptySpace min="0" pref="102" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -40,8 +50,18 @@
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="diskComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -71,5 +91,40 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -25,7 +25,10 @@ import java.awt.Font;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import javax.swing.ComboBoxModel;
@ -37,13 +40,16 @@ import javax.swing.ListCellRenderer;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListDataListener;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or C:.
*/
public class LocalDiskPanel extends ContentTypePanel {
public class LocalDiskPanel extends JPanel {
private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());
private static LocalDiskPanel instance;
private PropertyChangeSupport pcs = null;
private List<LocalDisk> disks = new ArrayList<LocalDisk>();
@ -56,6 +62,9 @@ public class LocalDiskPanel extends ContentTypePanel {
public LocalDiskPanel() {
initComponents();
customInit();
createTimeZoneList();
}
/**
@ -73,8 +82,10 @@ public class LocalDiskPanel extends ContentTypePanel {
model = new LocalDiskModel();
diskComboBox.setModel(model);
diskComboBox.setRenderer(model);
errorLabel.setText("");
diskComboBox.setEnabled(false);
}
/**
@ -89,6 +100,10 @@ public class LocalDiskPanel extends ContentTypePanel {
diskLabel = new javax.swing.JLabel();
diskComboBox = new javax.swing.JComboBox();
errorLabel = new javax.swing.JLabel();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(485, 65));
@ -98,6 +113,15 @@ public class LocalDiskPanel extends ContentTypePanel {
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.errorLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.text")); // NOI18N
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.descLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -106,8 +130,16 @@ public class LocalDiskPanel extends ContentTypePanel {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(diskLabel)
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(errorLabel))
.addGap(0, 140, Short.MAX_VALUE))
.addComponent(errorLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel)))
.addGap(0, 102, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -115,21 +147,34 @@ public class LocalDiskPanel extends ContentTypePanel {
.addComponent(diskLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(13, 13, 13)
.addComponent(errorLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.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))
.addGap(18, 18, 18)
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(errorLabel))
.addComponent(descLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel descLabel;
private javax.swing.JComboBox diskComboBox;
private javax.swing.JLabel diskLabel;
private javax.swing.JLabel errorLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JComboBox<String> timeZoneComboBox;
private javax.swing.JLabel timeZoneLabel;
// End of variables declaration//GEN-END:variables
/**
* Return the currently selected disk path.
* @return String selected disk path
*/
@Override
//@Override
public String getContentPaths() {
if(disks.size() > 0) {
LocalDisk selected = (LocalDisk) diskComboBox.getSelectedItem();
@ -143,7 +188,7 @@ public class LocalDiskPanel extends ContentTypePanel {
/**
* Set the selected disk.
*/
@Override
// @Override
public void setContentPath(String s) {
for(int i=0; i<disks.size(); i++) {
if(disks.get(i).getPath().equals(s)) {
@ -152,9 +197,14 @@ public class LocalDiskPanel extends ContentTypePanel {
}
}
@Override
public ContentType getContentType() {
return ContentType.DISK;
public String getTimeZone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
boolean getNoFatOrphans() {
return noFatOrphansCheckbox.isSelected();
}
/**
@ -162,31 +212,27 @@ public class LocalDiskPanel extends ContentTypePanel {
* Always return true because we control the possible selections.
* @return true
*/
@Override
public boolean enableNext() {
//@Override
public boolean validatePanel() {
return enableNext;
}
@Override
//@Override
public void reset() {
//nothing to reset
}
/**
* @return the representation of this panel as a String.
*/
@Override
public String toString() {
return "Local Disk";
}
/**
* Set the focus to the diskComboBox and refreshes the list of disks.
*/
@Override
// @Override
public void select() {
diskComboBox.requestFocusInWindow();
model.loadDisks();
model.loadDisks();
}
@Override
@ -207,16 +253,61 @@ public class LocalDiskPanel extends ContentTypePanel {
pcs.removePropertyChangeListener(pcl);
}
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zone to be selected.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
}
private class LocalDiskModel implements ComboBoxModel, ListCellRenderer {
private Object selected;
private boolean ready = false;
private volatile boolean loadingDisks = false;
List<LocalDisk> physical = new ArrayList<LocalDisk>();
List<LocalDisk> partitions = new ArrayList<LocalDisk>();
//private String SELECT = "Select a local disk:";
private String LOADING = "Loading local disks...";
LocalDiskThread worker = null;
private void loadDisks() {
// if there is a worker already building the lists, then cancel it first.
if (loadingDisks && worker != null) {
worker.cancel(false);
}
// Clear the lists
errorLabel.setText("");
disks = new ArrayList<LocalDisk>();
@ -224,9 +315,13 @@ public class LocalDiskPanel extends ContentTypePanel {
partitions = new ArrayList<LocalDisk>();
diskComboBox.setEnabled(false);
ready = false;
LocalDiskThread worker = new LocalDiskThread();
enableNext = false;
loadingDisks = true;
worker = new LocalDiskThread();
worker.execute();
}
@Override
@ -234,7 +329,7 @@ public class LocalDiskPanel extends ContentTypePanel {
if(ready) {
selected = anItem;
enableNext = true;
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
}
@ -260,7 +355,7 @@ public class LocalDiskPanel extends ContentTypePanel {
@Override
public void removeListDataListener(ListDataListener l) {
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JPanel panel = new JPanel(new BorderLayout());
@ -300,8 +395,6 @@ public class LocalDiskPanel extends ContentTypePanel {
// Populate the lists
physical = PlatformUtil.getPhysicalDrives();
partitions = PlatformUtil.getPartitions();
disks.addAll(physical);
disks.addAll(partitions);
return null;
}
@ -337,6 +430,11 @@ public class LocalDiskPanel extends ContentTypePanel {
enableNext = false;
displayErrors();
ready = true;
worker = null;
loadingDisks = false;
disks.addAll(physical);
disks.addAll(partitions);
if(disks.size() > 0) {
diskComboBox.setEnabled(true);

View File

@ -0,0 +1,167 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
import javax.swing.JPanel;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
@ServiceProvider(service = DataSourceProcessor.class)
public class LocalFilesDSProcessor implements DataSourceProcessor {
static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName());
// Data source type handled by this processor
protected static final String dsType = "Logical Files";
// The Config UI panel that plugins into the Choose Data Source Wizard
private LocalFilesPanel localFilesPanel;
// The Background task that does the actual work of adding the files
private AddLocalFilesTask addFilesTask;
// true if cancelled by the caller
private boolean cancelled = false;
DSPCallback callbackObj = null;
// set to TRUE if the image options have been set via API and config Jpanel should be ignored
private boolean localFilesOptionsSet = false;
// data source options
private String localFilesPath;
/*
* A no argument constructor is required for the NM lookup() method to create an object
*/
public LocalFilesDSProcessor() {
// Create the config panel
localFilesPanel = LocalFilesPanel.getDefault();
}
/**
* Returns the Data source type (string) handled by this DSP
*
* @return String the data source type
**/
@Override
public String getType() {
return dsType;
}
/**
* Returns the JPanel for collecting the Data source information
*
* @return JPanel the config panel
**/
@Override
public JPanel getPanel() {
localFilesPanel.select();
return localFilesPanel;
}
/**
* Validates the data collected by the JPanel
*
* @return String returns NULL if success, error string if there is any errors
**/
@Override
public boolean validatePanel() {
return localFilesPanel.validatePanel();
}
/**
* Runs the data source processor.
* This must kick off processing the data source in background
*
* @param progressMonitor Progress monitor to report progress during processing
* @param cbObj callback to call when processing is done.
**/
@Override
public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) {
callbackObj = cbObj;
cancelled = false;
if (!localFilesOptionsSet) {
// get the selected file paths from the panel
localFilesPath = localFilesPanel.getContentPaths();
}
addFilesTask = new AddLocalFilesTask(localFilesPath, progressMonitor, cbObj);
new Thread(addFilesTask).start();
return;
}
/**
* Cancel the data source processing
**/
@Override
public void cancel() {
cancelled = true;
addFilesTask.cancelTask();
return;
}
/**
* Reset the data source processor
**/
@Override
public void reset() {
// reset the config panel
localFilesPanel.reset();
// reset state
localFilesOptionsSet = false;
localFilesPath = null;
return;
}
/**
* Sets the data source options externally.
* To be used by a client that does not have a UI and does not use the JPanel to
* collect this information from a user.
*
* @param filesPath PATH_SEP list of paths to local files
*
**/
public void setDataSourceOptions(String filesPath) {
this.localFilesPath = filesPath;
localFilesOptionsSet = true;
}
}

View File

@ -24,11 +24,13 @@ import java.io.File;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* Add input wizard subpanel for adding local files / dirs to the case
*/
public class LocalFilesPanel extends ContentTypePanel {
public class LocalFilesPanel extends JPanel {
private PropertyChangeSupport pcs = null;
private Set<File> currentFiles = new TreeSet<File>(); //keep currents in a set to disallow duplicates per add
@ -57,7 +59,7 @@ public class LocalFilesPanel extends ContentTypePanel {
}
@Override
//@Override
public String getContentPaths() {
//TODO consider interface change to return list of paths instead
@ -72,36 +74,37 @@ public class LocalFilesPanel extends ContentTypePanel {
return b.toString();
}
@Override
//@Override
public void setContentPath(String s) {
//for the local file panel we don't need to restore the last paths used
//when the wizard restarts
}
@Override
public ContentType getContentType() {
return ContentType.LOCAL;
//@Override
public String getContentType() {
return "LOCAL";
}
@Override
public boolean enableNext() {
//@Override
public boolean validatePanel() {
return enableNext;
}
@Override
//@Override
public void select() {
reset();
}
@Override
//@Override
public void reset() {
currentFiles.clear();
selectedPaths.setText("");
enableNext = false;
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
//pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
}
@Override
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) {
super.addPropertyChangeListener(pcl);
@ -231,7 +234,7 @@ public class LocalFilesPanel extends ContentTypePanel {
else {
enableNext = false;
}
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}//GEN-LAST:event_selectButtonActionPerformed
private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed

View File

@ -110,65 +110,49 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="typePanel" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="typeTabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="typeComboBox" pref="298" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="pathNameTextField" min="-2" pref="285" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="83" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="typeTabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="typePanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace pref="62" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="typeComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="typeTabel">
<Component class="javax.swing.JTextField" name="pathNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.typeTabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.pathNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pathNameTextFieldActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="typePanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="57" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="titleLabel">

View File

@ -18,49 +18,71 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Level;
import javax.swing.ComboBoxModel;
import javax.swing.JDialog;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.ListDataListener;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
public class MissingImageDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName());
long obj_id;
SleuthkitCase db;
ContentTypePanel currentPanel;
ImageTypeModel model;
static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC);
static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC);
static final List<String> allExt = new ArrayList<String>();
static {
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
}
static final String allDesc = "All Supported Types";
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
private JFileChooser fc = new JFileChooser();
private MissingImageDialog(long obj_id, SleuthkitCase db) {
super(new JFrame(), true);
this.obj_id = obj_id;
this.db = db;
initComponents();
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.addChoosableFileFilter(rawFilter);
fc.addChoosableFileFilter(encaseFilter);
fc.setFileFilter(allFilter);
customInit();
}
/**
* Client call to create a MissingImageDialog.
*
* @param obj_id obj_id of the missing image
* @param db the current SleuthkitCase connected to a db
*/
//
// * Client call to create a MissingImageDialog.
// *
// * @param obj_id obj_id of the missing image
// * @param db the current SleuthkitCase connected to a db
//
static void makeDialog(long obj_id, SleuthkitCase db) {
final MissingImageDialog dialog = new MissingImageDialog(obj_id, db);
dialog.addWindowListener(new WindowAdapter() {
@ -73,11 +95,8 @@ public class MissingImageDialog extends javax.swing.JDialog {
}
private void customInit() {
model = new ImageTypeModel();
typeComboBox.setModel(model);
typeComboBox.setSelectedIndex(0);
typePanel.setLayout(new BorderLayout());
updateCurrentPanel(ImageFilePanel.getDefault());
selectButton.setEnabled(false);
}
private void display() {
@ -92,54 +111,31 @@ public class MissingImageDialog extends javax.swing.JDialog {
this.setVisible(true);
}
/**
* Refresh this panel.
* @param panel current typepanel
*/
private void updateCurrentPanel(ContentTypePanel panel) {
currentPanel = panel;
typePanel.removeAll();
typePanel.add((JPanel) currentPanel, BorderLayout.CENTER);
typePanel.validate();
typePanel.repaint();
this.validate();
this.repaint();
currentPanel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) {
updateSelectButton();
}
if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) {
moveFocusToSelect();
}
}
});
currentPanel.select();
updateSelectButton();
}
/**
* Focuses the select button for easy enter-pressing access.
*/
//
// * Focuses the select button for easy enter-pressing access.
//
private void moveFocusToSelect() {
this.selectButton.requestFocusInWindow();
}
/**
* Enables/disables the select button based off the current panel.
*/
//
// * Enables/disables the select button based off the current panel.
//
private void updateSelectButton() {
this.selectButton.setEnabled(currentPanel.enableNext());
// Enable this based on whether there is a valid path
if (!pathNameTextField.getText().isEmpty()) {
String filePath = pathNameTextField.getText();
boolean isExist = Case.pathExists(filePath) || Case.driveExists(filePath);
selectButton.setEnabled(isExist);
}
}
/**
* 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.
*/
//
// * 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
@ -148,9 +144,8 @@ public class MissingImageDialog extends javax.swing.JDialog {
selectButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
containerPanel = new javax.swing.JPanel();
typeComboBox = new javax.swing.JComboBox();
typeTabel = new javax.swing.JLabel();
typePanel = new javax.swing.JPanel();
pathNameTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
titleLabel = new javax.swing.JLabel();
titleSeparator = new javax.swing.JSeparator();
@ -191,43 +186,39 @@ public class MissingImageDialog extends javax.swing.JDialog {
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.typeTabel.text")); // NOI18N
pathNameTextField.setText(org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.pathNameTextField.text")); // NOI18N
pathNameTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pathNameTextFieldActionPerformed(evt);
}
});
javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel);
typePanel.setLayout(typePanelLayout);
typePanelLayout.setHorizontalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
typePanelLayout.setVerticalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 57, Short.MAX_VALUE)
);
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel);
containerPanel.setLayout(containerPanelLayout);
containerPanelLayout.setHorizontalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(containerPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(containerPanelLayout.createSequentialGroup()
.addComponent(typeTabel)
.addGap(18, 18, 18)
.addComponent(typeComboBox, 0, 298, Short.MAX_VALUE)))
.addContainerGap())
.addContainerGap()
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 285, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(browseButton)
.addContainerGap(83, Short.MAX_VALUE))
);
containerPanelLayout.setVerticalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(containerPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addGap(18, 18, 18)
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(typeTabel)
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addContainerGap(62, Short.MAX_VALUE))
);
titleLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
@ -268,7 +259,7 @@ public class MissingImageDialog extends javax.swing.JDialog {
private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectButtonActionPerformed
try {
String newPath = currentPanel.getContentPaths();
String newPath = pathNameTextField.getText();
//TODO handle local files
db.setImagePaths(obj_id, Arrays.asList(new String[]{newPath}));
} catch (TskCoreException ex) {
@ -281,21 +272,48 @@ public class MissingImageDialog extends javax.swing.JDialog {
cancel();
}//GEN-LAST:event_cancelButtonActionPerformed
private void pathNameTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pathNameTextFieldActionPerformed
// TODO add your handling code here:
updateSelectButton();
}//GEN-LAST:event_pathNameTextFieldActionPerformed
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
String oldText = pathNameTextField.getText();
// set the current directory of the FileChooser if the ImagePath Field is valid
File currentDir = new File(oldText);
if (currentDir.exists()) {
fc.setCurrentDirectory(currentDir);
}
int retval = fc.showOpenDialog(this);
if (retval == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
pathNameTextField.setText(path);
}
//pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true);
updateSelectButton();
}//GEN-LAST:event_browseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JPanel buttonPanel;
private javax.swing.JButton cancelButton;
private javax.swing.JPanel containerPanel;
private javax.swing.JTextField pathNameTextField;
private javax.swing.JButton selectButton;
private javax.swing.JLabel titleLabel;
private javax.swing.JSeparator titleSeparator;
private javax.swing.JComboBox typeComboBox;
private javax.swing.JPanel typePanel;
private javax.swing.JLabel typeTabel;
// End of variables declaration//GEN-END:variables
/**
* Verify the user wants to cancel searching for the image.
*/
//
// * Verify the user wants to cancel searching for the image.
//
void cancel() {
int ret = JOptionPane.showConfirmDialog(null,
"No image file has been selected, are you sure you\n" +
@ -306,40 +324,5 @@ public class MissingImageDialog extends javax.swing.JDialog {
}
}
/**
* ComboBoxModel to control typeComboBox and supply ImageTypePanels.
*/
private class ImageTypeModel implements ComboBoxModel {
ContentTypePanel selected;
ContentTypePanel[] types = ContentTypePanel.getPanels();
@Override
public void setSelectedItem(Object anItem) {
selected = (ContentTypePanel) anItem;
updateCurrentPanel(selected);
}
@Override
public Object getSelectedItem() {
return selected;
}
@Override
public int getSize() {
return types.length;
}
@Override
public Object getElementAt(int index) {
return types[index];
}
@Override
public void addListDataListener(ListDataListener l) {
}
@Override
public void removeListDataListener(ListDataListener l) {
}
}
}
}

View File

@ -0,0 +1,66 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.corecomponentinterfaces;
import java.awt.EventQueue;
import java.util.List;
import org.sleuthkit.datamodel.Content;
/**
* Abstract class for a callback for a DataSourceProcessor.
*
* Ensures that DSP invokes the caller overridden method, doneEDT(),
* in the EDT thread.
*
*/
public abstract class DSPCallback {
public enum DSP_Result
{
NO_ERRORS,
CRITICAL_ERRORS,
NONCRITICAL_ERRORS,
};
/*
* Invoke the caller supplied callback function on the EDT thread
*/
public void done(DSP_Result result, List<String> errList, List<Content> newContents)
{
final DSP_Result resultf = result;
final List<String> errListf = errList;
final List<Content> newContentsf = newContents;
// Invoke doneEDT() that runs on the EDT .
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
doneEDT(resultf, errListf, newContentsf );
}
});
}
/*
* calling code overrides to provide its own calllback
*/
public abstract void doneEDT(DSP_Result result, List<String> errList, List<Content> newContents);
};

View File

@ -0,0 +1,33 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.corecomponentinterfaces;
/*
* An GUI agnostic DSPProgressMonitor interface for DataSourceProcesssors to
* indicate progress.
* It models after a JProgressbar though it could use any underlying implementation
*/
public interface DSPProgressMonitor {
void setIndeterminate(boolean indeterminate);
void setProgress(int progress);
void setProgressText(String text);
}

View File

@ -0,0 +1,92 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.corecomponentinterfaces;
import javax.swing.JPanel;
/*
* Defines an interface used by the Add DataSource wizard to discover different
* Data SourceProcessors.
*
* Each data source may have its unique attributes and may need to be processed
* differently.
*
* The DataSourceProcessor interface defines a uniform mechanism for the Autopsy UI
* to:
* - collect details for the data source to be processed.
* - Process the data source in the background
* - Be notified when the processing is complete
*/
public interface DataSourceProcessor {
/*
* The DSP Panel may fire Property change events
* The caller must enure to add itself as a listener and
* then react appropriately to the events
*/
enum DSP_PANEL_EVENT {
UPDATE_UI, // the content of JPanel has changed that MAY warrant updates to the caller UI
FOCUS_NEXT // the caller UI may move focus the the next UI element, floowing the panel.
};
/**
* Returns the type of Data Source it handles.
* This name gets displayed in the drop-down listbox
**/
String getType();
/**
* Returns the picker panel to be displayed along with any other
* runtime options supported by the data source handler.
**/
JPanel getPanel();
/**
* Called to validate the input data in the panel.
* Returns true if no errors, or
* Returns false if there is an error.
**/
boolean validatePanel();
/**
* Called to invoke the handling of Data source in the background.
* Returns after starting the background thread
* @param settings wizard settings to read/store properties
* @param progressPanel progress panel to be updated while processing
*
**/
void run(DSPProgressMonitor progressPanel, DSPCallback dspCallback);
/**
* Called to cancel the background processing.
**/
void cancel();
/**
* Called to reset/reinitialize the DSP.
*
**/
void reset();
}