mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
Revert "Fix thread safety, clean up add data source wizard classes"
This reverts commit b93d45fbf12824d7172ac6297ce4e6c24fbe1ed4.
This commit is contained in:
parent
fc6f972e54
commit
eda180e34f
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,11 +21,13 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import org.openide.DialogDisplayer;
|
||||
@ -35,91 +37,139 @@ import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
|
||||
/**
|
||||
* An action that adds a data source to the current case.
|
||||
* The action to add an image to the current Case. This action should be
|
||||
* disabled on creation and it will be enabled on new case creation or case
|
||||
* opened.
|
||||
*
|
||||
* RC: This action needs to be enabled and disabled as cases are opened and
|
||||
* closed. Currently this is done using
|
||||
* CallableSystemAction.get(AddImageAction.class).setEnabled().
|
||||
* @author jantonius
|
||||
*/
|
||||
// TODO: need annotation because there's a "Lookup.getDefault().lookup(AddImageAction.class)"
|
||||
// used in AddImageWizardPanel1 (among other places). It really shouldn't be done like that.
|
||||
@ServiceProvider(service = AddImageAction.class)
|
||||
public final class AddImageAction extends CallableSystemAction implements Presenter.Toolbar {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(AddImageAction.class.getName());
|
||||
private final ChangeSupport cleanupSupport;
|
||||
private final JButton toolbarButton;
|
||||
// Keys into the WizardDescriptor properties that pass information between stages of the wizard
|
||||
// <TYPE>: <DESCRIPTION>
|
||||
// String: time zone that the image is from
|
||||
static final String TIMEZONE_PROP = "timeZone"; //NON-NLS
|
||||
// String[]: array of paths to each data source selected
|
||||
static final String DATASOURCEPATH_PROP = "dataSrcPath"; //NON-NLS
|
||||
// String data source type selected
|
||||
static final String DATASOURCETYPE_PROP = "dataSrcType"; //NON-NLS
|
||||
// CleanupTask: task to clean up the database file if wizard errors/is cancelled after it is created
|
||||
static final String IMAGECLEANUPTASK_PROP = "finalFileCleanup"; //NON-NLS
|
||||
// int: the next availble id for a new image
|
||||
static final String IMAGEID_PROP = "imageId"; //NON-NLS
|
||||
// AddImageProcess: the next availble id for a new image
|
||||
static final String PROCESS_PROP = "process"; //NON-NLS
|
||||
// boolean: whether or not to lookup files in the hashDB
|
||||
static final String LOOKUPFILES_PROP = "lookupFiles"; //NON-NLS
|
||||
// boolean: whether or not to skip processing orphan files on FAT filesystems
|
||||
static final String NOFATORPHANS_PROP = "nofatorphans"; //NON-NLS
|
||||
|
||||
static final Logger logger = Logger.getLogger(AddImageAction.class.getName());
|
||||
|
||||
private WizardDescriptor wizardDescriptor;
|
||||
private WizardDescriptor.Iterator<WizardDescriptor> iterator;
|
||||
private Dialog dialog;
|
||||
private JButton toolbarButton = new JButton();
|
||||
|
||||
/**
|
||||
* Constructs an action that adds a data source to the current case.
|
||||
* The constructor for AddImageAction class
|
||||
*/
|
||||
public AddImageAction() {
|
||||
cleanupSupport = new ChangeSupport(this);
|
||||
putValue(Action.NAME, NbBundle.getMessage(AddImageAction.class, "CTL_AddImage"));
|
||||
toolbarButton = new JButton();
|
||||
toolbarButton.addActionListener(AddImageAction.this::actionPerformed);
|
||||
setEnabled(false);
|
||||
putValue(Action.NAME, NbBundle.getMessage(AddImageAction.class, "CTL_AddImage")); // set the action Name
|
||||
|
||||
// set the action for the toolbar button
|
||||
toolbarButton.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
AddImageAction.this.actionPerformed(e);
|
||||
}
|
||||
});
|
||||
|
||||
this.setEnabled(false); // disable this action class
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the first panel of the add data source wizard.
|
||||
* Pop-up the "Add Image" wizard panel.
|
||||
*
|
||||
* @param notUsed An action event, may be null.
|
||||
* @param e
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent notUsed) {
|
||||
/*
|
||||
* If ingest is running, confirm that the user wants to add another data
|
||||
* source at this time, instead of waiting for the current ingest job to
|
||||
* complete.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (IngestManager.getInstance().isIngestRunning()) {
|
||||
if (JOptionPane.showConfirmDialog(null,
|
||||
NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg"),
|
||||
NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.title"),
|
||||
final String msg = NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg");
|
||||
if (JOptionPane.showConfirmDialog(null, msg,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"AddImageAction.ingestConfig.ongoingIngest.title"),
|
||||
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct and display the wizard.
|
||||
*/
|
||||
iterator = new AddImageWizardIterator();
|
||||
iterator = new AddImageWizardIterator(this);
|
||||
wizardDescriptor = new WizardDescriptor(iterator);
|
||||
wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "AddImageAction.wizard.title"));
|
||||
Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
|
||||
wizardDescriptor.putProperty(NAME, e);
|
||||
|
||||
if (dialog != null) {
|
||||
dialog.setVisible(false); // hide the old one
|
||||
}
|
||||
dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
|
||||
dialog.setVisible(true);
|
||||
dialog.toFront();
|
||||
|
||||
/*
|
||||
* Run any registered cleanup tasks by firing a change event. This will
|
||||
* cause the stateChanged method of any implementations of the inner,
|
||||
* abstract CleanupTask class to call their cleanup methods (assuming
|
||||
* they have not done an override of stateChanged), after which the
|
||||
* CleanupTasks are unregistered.
|
||||
*
|
||||
* RC: This is a convoluted and error-prone way to implement clean up.
|
||||
* Fortunately, it is confined to this package.
|
||||
*/
|
||||
cleanupSupport.fireChange();
|
||||
// Do any cleanup that needs to happen (potentially: stopping the
|
||||
//add-image process, reverting an image)
|
||||
runCleanupTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Closes the current dialog and wizard, and opens a new one. Used in the
|
||||
* "Add another image" action on the last panel
|
||||
*/
|
||||
void restart() {
|
||||
// Simulate clicking finish for the current dialog
|
||||
wizardDescriptor.setValue(WizardDescriptor.FINISH_OPTION);
|
||||
dialog.setVisible(false);
|
||||
|
||||
// let the previous call to AddImageAction.actionPerformed() finish up
|
||||
// after the wizard, this will run when its it's done
|
||||
final Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
actionPerformed(null);
|
||||
}
|
||||
};
|
||||
|
||||
SwingUtilities.invokeLater(r);
|
||||
}
|
||||
|
||||
public interface IndexImageTask {
|
||||
|
||||
void runTask(Image newImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does nothing. Use the "actionPerformed(ActionEvent e)"
|
||||
* instead of this method.
|
||||
*/
|
||||
@Override
|
||||
public void performAction() {
|
||||
actionPerformed(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Gets the name of this action. This may be presented as an item in a menu.
|
||||
*
|
||||
* @return actionName
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
@ -127,7 +177,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Gets the HelpCtx associated with implementing object
|
||||
*
|
||||
* @return HelpCtx or HelpCtx.DEFAULT_HELP
|
||||
*/
|
||||
@Override
|
||||
public HelpCtx getHelpCtx() {
|
||||
@ -135,7 +187,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Returns the toolbar component of this action
|
||||
*
|
||||
* @return component the toolbar button
|
||||
*/
|
||||
@Override
|
||||
public Component getToolbarPresenter() {
|
||||
@ -146,7 +200,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Set this action to be enabled/disabled
|
||||
*
|
||||
* @param value whether to enable this action or not
|
||||
*/
|
||||
@Override
|
||||
public void setEnabled(boolean value) {
|
||||
@ -155,80 +211,68 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing, do not use.
|
||||
* Set the focus to the button of the given name on this wizard dialog.
|
||||
*
|
||||
* @deprecated Classes in this package may call requestFocusForWizardButton
|
||||
* instead.
|
||||
* Note: the name of the buttons that available are "Next >", "< Back",
|
||||
* "Cancel", and "Finish". If you change the name of any of those buttons,
|
||||
* use the latest name instead.
|
||||
*
|
||||
* @param buttonText the text of the button
|
||||
*/
|
||||
@Deprecated
|
||||
public void requestFocusButton(String buttonText) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests focus for an add data source wizard button.
|
||||
*
|
||||
* @param buttonText The text of the button.
|
||||
*/
|
||||
void requestFocusForWizardButton(String buttonText) {
|
||||
for (Object wizardButton : wizardDescriptor.getOptions()) {
|
||||
JButton button = (JButton) wizardButton;
|
||||
if (button.getText().equals(buttonText)) {
|
||||
button.setDefaultCapable(true);
|
||||
button.requestFocus();
|
||||
// get all buttons on this wizard panel
|
||||
Object[] wizardButtons = wizardDescriptor.getOptions();
|
||||
for (int i = 0; i < wizardButtons.length; i++) {
|
||||
JButton tempButton = (JButton) wizardButtons[i];
|
||||
if (tempButton.getText().equals(buttonText)) {
|
||||
tempButton.setDefaultCapable(true);
|
||||
tempButton.requestFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabled instances of this class are called to do clean up after the add
|
||||
* data source wizard is closed. The instances are disabled after the
|
||||
* cleanUp method is called. Implementations should not override
|
||||
* stateChanged, and should not re-enable themselves after cleanUp is
|
||||
* called. To stop cleanUp being called, call disable before the wizard is
|
||||
* dismissed.
|
||||
* Run and clear any cleanup tasks for wizard closing that might be
|
||||
* registered. This should be run even when the wizard exits cleanly, so
|
||||
* that no cleanup actions remain the next time the wizard is run.
|
||||
*/
|
||||
private void runCleanupTasks() {
|
||||
cleanupSupport.fireChange();
|
||||
}
|
||||
|
||||
ChangeSupport cleanupSupport = new ChangeSupport(this);
|
||||
|
||||
/**
|
||||
* Instances of this class implement the cleanup() method to run cleanup
|
||||
* code when the wizard exits.
|
||||
*
|
||||
* Instances must be constructed using a reference to an AddImageAction
|
||||
* object because this is a non-static inner class.
|
||||
* After enable() has been called on an instance it will run once after the
|
||||
* wizard closes (on both a cancel and a normal finish).
|
||||
*
|
||||
* RC: This is a convoluted and error-prone way to implement clean up.
|
||||
* Fortunately, it is confined to this package.
|
||||
* If disable() is called before the wizard exits, the task will not run.
|
||||
*/
|
||||
abstract class CleanupTask implements ChangeListener {
|
||||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
/*
|
||||
* actionPerformed fires this event after the add data source wizard
|
||||
* is closed.
|
||||
*/
|
||||
// fired by AddImageAction.runCleanupTasks() after the wizard closes
|
||||
try {
|
||||
cleanup();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error cleaning in add data source wizard clean up task", ex); //NON-NLS
|
||||
Logger logger = Logger.getLogger(this.getClass().getName());
|
||||
logger.log(Level.WARNING, "Error cleaning up from wizard.", ex); //NON-NLS
|
||||
} finally {
|
||||
/*
|
||||
* Clean up tasks should only be done exactly once.
|
||||
*/
|
||||
disable();
|
||||
disable(); // cleanup tasks should only run once.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this task to the list of tasks to be done when the wizard
|
||||
* closes.
|
||||
* Add task to the enabled list to run when the wizard closes.
|
||||
*/
|
||||
void enable() {
|
||||
public void enable() {
|
||||
cleanupSupport.addChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this task from the list of tasks to be done when the wizard
|
||||
* closes.
|
||||
*/
|
||||
void disable() {
|
||||
cleanupSupport.removeChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs cleanup action when called
|
||||
*
|
||||
@ -236,12 +280,11 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
*/
|
||||
abstract void cleanup() throws Exception;
|
||||
|
||||
/**
|
||||
* Remove task from the enabled list.
|
||||
*/
|
||||
public void disable() {
|
||||
cleanupSupport.removeChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public interface IndexImageTask {
|
||||
|
||||
void runTask(Image newImage);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,97 +20,105 @@ 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;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import org.openide.WizardDescriptor;
|
||||
import org.openide.util.ChangeSupport;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
|
||||
/**
|
||||
* The third and final panel of the add data source wizard. The visual component
|
||||
* of this panel displays a progress bar that is managed by the previous panel
|
||||
* and the data source processor.
|
||||
* The final panel of the add image wizard. It displays a progress bar and
|
||||
* status updates.
|
||||
*
|
||||
* All the real work is kicked off in the previous panel:
|
||||
* {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m
|
||||
* -jm)
|
||||
*/
|
||||
// All the real work is kicked off in the previous panel:
|
||||
// {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m
|
||||
// -jm)
|
||||
final class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePanel<WizardDescriptor> {
|
||||
class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePanel<WizardDescriptor> {
|
||||
|
||||
private final ChangeSupport changeSupport;
|
||||
private final DSPProgressMonitorImpl dspProgressMonitor = new DSPProgressMonitorImpl();
|
||||
/**
|
||||
* flag to indicate that the image adding process is finished and this panel
|
||||
* is completed(valid)
|
||||
*/
|
||||
private boolean imgAdded = false;
|
||||
/**
|
||||
* The visual component that displays this panel. If you need to access the
|
||||
* component from this class, just use getComponent().
|
||||
*/
|
||||
private AddImageWizardAddingProgressVisual component;
|
||||
private boolean dataSourceAdded = false;
|
||||
private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
|
||||
|
||||
/**
|
||||
* Constructs an instance of the third and final panel of the add data
|
||||
* source wizard.
|
||||
*/
|
||||
AddImageWizardAddingProgressPanel() {
|
||||
changeSupport = new ChangeSupport(this);
|
||||
private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl();
|
||||
|
||||
public DSPProgressMonitorImpl getDSPProgressMonitorImpl() {
|
||||
return dspProgressMonitorImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data source progress monitor. Allows the previous panel to hand
|
||||
* off the progress monitor to the data source processor.
|
||||
*/
|
||||
DSPProgressMonitorImpl getDSPProgressMonitor() {
|
||||
return dspProgressMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* A data source processor progress monitor that acts as a bridge between
|
||||
* the data source processor started by the previous panel and the progress
|
||||
* bar displayed by the visual component of this panel.
|
||||
*/
|
||||
private class DSPProgressMonitorImpl implements DataSourceProcessorProgressMonitor {
|
||||
|
||||
@Override
|
||||
public void setIndeterminate(final boolean indeterminate) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
getComponent().getProgressBar().setIndeterminate(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(() -> {
|
||||
getComponent().getProgressBar().setValue(progress);
|
||||
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(() -> {
|
||||
getComponent().setProgressMsgText(text);
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getComponent().setProgressMsgText(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the visual component for the panel. In this template, the component
|
||||
* Get the visual component for the panel. In this template, the component
|
||||
* is kept separate. This can be more efficient: if the wizard is created
|
||||
* but never displayed, or not all panels are displayed, it is better to
|
||||
* create only those which really need to be visible.
|
||||
*
|
||||
* @return The UI component of this wizard panel.
|
||||
* It also separates the view from the control - jm
|
||||
*
|
||||
* @return component the UI component of this wizard panel
|
||||
*/
|
||||
@Override
|
||||
public AddImageWizardAddingProgressVisual getComponent() {
|
||||
if (null == component) {
|
||||
if (component == null) {
|
||||
component = new AddImageWizardAddingProgressVisual();
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help for this panel. When the panel is active, this is used as
|
||||
* the help for the wizard dialog.
|
||||
* Help for this panel. When the panel is active, this is used as the help
|
||||
* for the wizard dialog.
|
||||
*
|
||||
* @return The help for this panel
|
||||
* @return HelpCtx.DEFAULT_HELP the help for this panel
|
||||
*/
|
||||
@Override
|
||||
public HelpCtx getHelp() {
|
||||
@ -126,12 +134,17 @@ final class AddImageWizardAddingProgressPanel implements WizardDescriptor.Finish
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return dataSourceAdded;
|
||||
// set the focus to the next button of the wizard dialog if it's enabled
|
||||
if (imgAdded) {
|
||||
Lookup.getDefault().lookup(AddImageAction.class).requestFocusButton(
|
||||
NbBundle.getMessage(this.getClass(), "AddImageWizardAddingProgressPanel.isValid.focusNext"));
|
||||
}
|
||||
|
||||
return imgAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the progress bar of the visual component of this panel indicate
|
||||
* that the data source processor is running.
|
||||
* Updates the UI to display the add image process has begun.
|
||||
*/
|
||||
void setStateStarted() {
|
||||
component.getProgressBar().setIndeterminate(true);
|
||||
@ -140,85 +153,94 @@ final class AddImageWizardAddingProgressPanel implements WizardDescriptor.Finish
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the progress bar of the visual component of this panel indicate
|
||||
* that the data source processor is not running.
|
||||
* Updates the UI to display the add image process is over.
|
||||
*/
|
||||
void setStateFinished() {
|
||||
dataSourceAdded = true;
|
||||
imgAdded = true;
|
||||
getComponent().setStateFinished();
|
||||
fireChangeEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc5
|
||||
* Adds a listener to changes of the panel's validity.
|
||||
*
|
||||
* @param l the change listener to add
|
||||
*/
|
||||
@Override
|
||||
public final void addChangeListener(ChangeListener listener) {
|
||||
changeSupport.addChangeListener(listener);
|
||||
public final void addChangeListener(ChangeListener l) {
|
||||
synchronized (listeners) {
|
||||
listeners.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Removes a listener to changes of the panel's validity.
|
||||
*
|
||||
* @param l the change listener to move
|
||||
*/
|
||||
@Override
|
||||
public final void removeChangeListener(ChangeListener listener) {
|
||||
changeSupport.removeChangeListener(listener);
|
||||
public final void removeChangeListener(ChangeListener l) {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* This method is auto-generated. It seems that this method is used to
|
||||
* listen to any change in this wizard panel.
|
||||
*/
|
||||
protected final void fireChangeEvent() {
|
||||
changeSupport.fireChange();
|
||||
Iterator<ChangeListener> it;
|
||||
synchronized (listeners) {
|
||||
it = new HashSet<ChangeListener>(listeners).iterator();
|
||||
}
|
||||
ChangeEvent ev = new ChangeEvent(this);
|
||||
while (it.hasNext()) {
|
||||
it.next().stateChanged(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the wizard panel with the current data--either the default data
|
||||
* or already-modified settings, if the user used the previous and/or next
|
||||
* buttons. This method can be called multiple times on one instance of
|
||||
* WizardDescriptor.Panel.
|
||||
* Load the image locations from the WizardDescriptor settings object, and
|
||||
* the
|
||||
*
|
||||
* @param settings The settings.
|
||||
* @param settings the setting to be read from
|
||||
*/
|
||||
@Override
|
||||
public void readSettings(WizardDescriptor settings) {
|
||||
settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, WizardDescriptor.CANCEL_OPTION});
|
||||
if (dataSourceAdded) {
|
||||
if (imgAdded) {
|
||||
getComponent().setStateFinished();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the wizard panel with the opportunity to update the settings
|
||||
* with its current customized state. Rather than updating its settings with
|
||||
* every change in the GUI, it should collect them, and then only save them
|
||||
* when requested to by this method. This method can be called multiple
|
||||
* times on one instance of WizardDescriptor.Panel.
|
||||
* this doesn't appear to store anything? plus, there are no settings in
|
||||
* this panel -jm
|
||||
*
|
||||
* @param settings the setting to be stored to
|
||||
*/
|
||||
@Override
|
||||
public void storeSettings(WizardDescriptor settings) {
|
||||
//why did we do this? -jm
|
||||
// getComponent().resetInfoPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an error message from the data source processor for the data
|
||||
* source being added.
|
||||
* forward errors to visual component
|
||||
*
|
||||
* @param errorString The error message to be displayed
|
||||
* @param critical True if this is a critical error
|
||||
* should this be modified to handle a list of errors? -jm
|
||||
*
|
||||
*
|
||||
* @param errorString the error string to be displayed
|
||||
* @param critical true if this is a critical error
|
||||
*/
|
||||
// Should this be modified to handle a list of errors? -jm
|
||||
void displayDataSourceProcessorError(String errorString, boolean critical) {
|
||||
void addErrors(String errorString, boolean critical) {
|
||||
getComponent().showErrors(errorString, critical);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isFinishPanel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,43 +20,55 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import org.openide.WizardDescriptor;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.windows.WindowManager;
|
||||
import java.awt.Cursor;
|
||||
import org.openide.util.ChangeSupport;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
|
||||
/**
|
||||
* The first panel of the add data source wizard. The visual component of this
|
||||
* panel allows a user to select data sources to add to the current case.
|
||||
* The "Add Image" wizard panel1 handling the logic of selecting image file(s)
|
||||
* to add to Case, and pick the time zone.
|
||||
*/
|
||||
final class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<WizardDescriptor>, PropertyChangeListener {
|
||||
|
||||
private AddImageWizardChooseDataSourceVisual component;
|
||||
private final ChangeSupport changeSupport;
|
||||
private boolean nextButtonIsEnabled = false;
|
||||
class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<WizardDescriptor>, PropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Constructs an instance of the first panel of the add data source wizard.
|
||||
* The visual component that displays this panel. If you need to access the
|
||||
* component from this class, just use getComponent().
|
||||
*/
|
||||
AddImageWizardChooseDataSourcePanel() {
|
||||
changeSupport = new ChangeSupport(this);
|
||||
private AddImageWizardAddingProgressPanel progressPanel;
|
||||
private AddImageWizardChooseDataSourceVisual component;
|
||||
private boolean isNextEnable = false;
|
||||
private static final String PROP_LASTDATASOURCE_PATH = "LBL_LastDataSource_PATH"; //NON-NLS
|
||||
private static final String PROP_LASTDATASOURCE_TYPE = "LBL_LastDataSource_TYPE"; //NON-NLS
|
||||
// paths to any set hash lookup databases (can be null)
|
||||
private String NSRLPath, knownBadPath;
|
||||
|
||||
AddImageWizardChooseDataSourcePanel(AddImageWizardAddingProgressPanel proPanel) {
|
||||
|
||||
this.progressPanel = proPanel;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the visual component for the panel. The component is kept separate.
|
||||
* This can be more efficient: if the wizard is created but never displayed,
|
||||
* or not all panels are displayed, it is better to create only those which
|
||||
* really need to be visible.
|
||||
* Get the visual component for the panel. In this template, the component
|
||||
* is kept separate. This can be more efficient: if the wizard is created
|
||||
* but never displayed, or not all panels are displayed, it is better to
|
||||
* create only those which really need to be visible.
|
||||
*
|
||||
* @return The UI component of this wizard panel.
|
||||
* @return component the UI component of this wizard panel
|
||||
*/
|
||||
@Override
|
||||
public AddImageWizardChooseDataSourceVisual getComponent() {
|
||||
if (null == component) {
|
||||
if (component == null) {
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
component = new AddImageWizardChooseDataSourceVisual(this);
|
||||
}
|
||||
@ -65,103 +77,156 @@ final class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Pane
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help for this panel. When the panel is active, this is used as
|
||||
* the help for the wizard dialog.
|
||||
* Help for this panel. When the panel is active, this is used as the help
|
||||
* for the wizard dialog.
|
||||
*
|
||||
* @return The help for this panel
|
||||
* @return HelpCtx.DEFAULT_HELP the help for this panel
|
||||
*/
|
||||
@Override
|
||||
public HelpCtx getHelp() {
|
||||
// Show no Help button for this panel:
|
||||
return HelpCtx.DEFAULT_HELP;
|
||||
// If you have context help:
|
||||
// return new HelpCtx(SampleWizardPanel1.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the panel is finished and it is safe to proceed to the next
|
||||
* one. If the panel is valid, the "Next" button will be enabled.
|
||||
*
|
||||
* Tests whether or not the panel is finished. If the panel is valid, the
|
||||
* "Finish" button will be enabled.
|
||||
*
|
||||
* @return True or false.
|
||||
* @return boolean true if all the fields are correctly filled, false
|
||||
* otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
// If it is always OK to press Next or Finish, then:
|
||||
// return true;
|
||||
// If it depends on some condition (form filled out...), then:
|
||||
// return someCondition();
|
||||
// and when this condition changes (last form field filled in...) then:
|
||||
// fireChangeEvent();
|
||||
/*
|
||||
* When it is valid, the visual component calls enableNextButton to set
|
||||
* this flag.
|
||||
*/
|
||||
return nextButtonIsEnabled;
|
||||
return isNextEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the keyboard focus to the next button of the wizard.
|
||||
* Move the keyboard focus to the next button
|
||||
*/
|
||||
void moveFocusToNext() {
|
||||
if (nextButtonIsEnabled) {
|
||||
CallableSystemAction.get(AddImageAction.class).requestFocusForWizardButton(
|
||||
// set the focus to the next button of the wizard dialog if it's enabled
|
||||
if (isNextEnable) {
|
||||
Lookup.getDefault().lookup(AddImageAction.class).requestFocusButton(
|
||||
NbBundle.getMessage(this.getClass(), "AddImageWizardChooseDataSourcePanel.moveFocusNext"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the "Next" button and fires a change event to update the UI.
|
||||
* Enable the "Next" button and fireChangeEvent to update the GUI
|
||||
*
|
||||
* @param isEnabled True if next button should be enabled, false otherwise.
|
||||
* @param isEnabled true if next button can be enabled, false otherwise
|
||||
*/
|
||||
void enableNextButton(boolean isEnabled) {
|
||||
nextButtonIsEnabled = isEnabled;
|
||||
public void enableNextButton(boolean isEnabled) {
|
||||
isNextEnable = isEnabled;
|
||||
fireChangeEvent();
|
||||
}
|
||||
private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(1); // or can use ChangeSupport in NB 6.0
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Adds a listener to changes of the panel's validity.
|
||||
*
|
||||
* @param l the change listener to add
|
||||
*/
|
||||
@Override
|
||||
public final void addChangeListener(ChangeListener listener) {
|
||||
changeSupport.addChangeListener(listener);
|
||||
public final void addChangeListener(ChangeListener l) {
|
||||
synchronized (listeners) {
|
||||
listeners.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Removes a listener to changes of the panel's validity.
|
||||
*
|
||||
* @param l the change listener to move
|
||||
*/
|
||||
@Override
|
||||
public final void removeChangeListener(ChangeListener listener) {
|
||||
changeSupport.removeChangeListener(listener);
|
||||
public final void removeChangeListener(ChangeListener l) {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* This method is auto-generated. It seems that this method is used to
|
||||
* listen to any change in this wizard panel.
|
||||
*/
|
||||
protected final void fireChangeEvent() {
|
||||
changeSupport.fireChange();
|
||||
Iterator<ChangeListener> it;
|
||||
synchronized (listeners) {
|
||||
it = new HashSet<ChangeListener>(listeners).iterator();
|
||||
}
|
||||
ChangeEvent ev = new ChangeEvent(this);
|
||||
while (it.hasNext()) {
|
||||
it.next().stateChanged(ev);
|
||||
}
|
||||
}
|
||||
|
||||
// You can use a settings object to keep track of state. Normally the
|
||||
// settings object will be the WizardDescriptor, so you can use
|
||||
// WizardDescriptor.getProperty & putProperty to store information entered
|
||||
// by the user.
|
||||
/**
|
||||
* Provides the wizard panel with the current data--either the default data
|
||||
* or already-modified settings, if the user used the previous and/or next
|
||||
* buttons. This method can be called multiple times on one instance of
|
||||
* WizardDescriptor.Panel.
|
||||
* WizardDescriptor.Panel. s
|
||||
*
|
||||
* @param settings The settings.
|
||||
* @param settings the setting to be read from
|
||||
*/
|
||||
@Override
|
||||
public void readSettings(WizardDescriptor settings) {
|
||||
|
||||
//reset settings if supports it
|
||||
//getComponent().reset();
|
||||
// Prepopulate the image directory from the properties file
|
||||
try {
|
||||
|
||||
// Load hash database settings, enable or disable the checkbox
|
||||
this.NSRLPath = null;
|
||||
this.knownBadPath = null;
|
||||
//JCheckBox lookupFilesCheckbox = component.getLookupFilesCheckbox();
|
||||
//lookupFilesCheckbox.setSelected(false);
|
||||
//lookupFilesCheckbox.setEnabled(this.NSRLPath != null || this.knownBadPath != null);
|
||||
|
||||
// If there is a process object in the settings, revert it and remove it from the settings
|
||||
AddImageAction.CleanupTask cleanupTask = (AddImageAction.CleanupTask) settings.getProperty(AddImageAction.IMAGECLEANUPTASK_PROP);
|
||||
if (cleanupTask != null) {
|
||||
try {
|
||||
cleanupTask.cleanup();
|
||||
} catch (Exception ex) {
|
||||
Logger logger = Logger.getLogger(AddImageWizardChooseDataSourcePanel.class.getName());
|
||||
logger.log(Level.WARNING, "Error cleaning up image task", ex); //NON-NLS
|
||||
} finally {
|
||||
cleanupTask.disable();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Provides the wizard panel with the opportunity to update the settings
|
||||
* with its current customized state. Rather than updating its settings with
|
||||
* every change in the GUI, it should collect them, and then only save them
|
||||
* when requested to by this method. This method can be called multiple
|
||||
* times on one instance of WizardDescriptor.Panel.
|
||||
*
|
||||
* @param settings the setting to be stored to
|
||||
*/
|
||||
@Override
|
||||
public void storeSettings(WizardDescriptor settings) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* The "listener" for any property change in this panel. Any property
|
||||
* changes will invoke the "fireChangeEvent()" method.
|
||||
*
|
||||
* @param evt the property change event
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -31,9 +31,7 @@ import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import org.openide.WizardDescriptor;
|
||||
import org.openide.util.ChangeSupport;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
@ -42,108 +40,80 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
|
||||
/**
|
||||
* The second panel of the add data source wizard. The visual component of this
|
||||
* panel allows a user to configure the ingest modules for the ingest job for
|
||||
* the data source, and this panel both runs the data source processor and
|
||||
* starts the ingest job.
|
||||
* second panel of add image wizard, allows user to configure ingest modules.
|
||||
*
|
||||
* TODO: review this for dead code. think about moving logic of adding image to
|
||||
* 3rd panel( {@link AddImageWizardAddingProgressPanel}) separate class -jm
|
||||
*/
|
||||
// JM: Think about moving the logic of adding image to the 3rd panel
|
||||
// ( {@link AddImageWizardAddingProgressPanel})
|
||||
final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDescriptor> {
|
||||
class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDescriptor> {
|
||||
|
||||
private final AddImageWizardChooseDataSourcePanel selectDataSourcePanel;
|
||||
private final AddImageWizardAddingProgressPanel progressPanel;
|
||||
private final ChangeSupport changeSupport;
|
||||
private final List<Content> newContents;
|
||||
private final IngestJobSettingsPanel ingestJobSettingsPanel;
|
||||
private Component component;
|
||||
private volatile boolean ingestModulesConfigured;
|
||||
private volatile boolean ingestJobStarted;
|
||||
private AddImageAction.CleanupTask cleanupTask;
|
||||
private DataSourceProcessor dsProcessor;
|
||||
|
||||
/**
|
||||
* Constructs an instance of The second panel of the add data source wizard.
|
||||
* The visual component of this panel allows a user to configure the ingest
|
||||
* modules for the ingest job for the data source.
|
||||
*
|
||||
* @param selectDataSourcePanel The second panel of the add data source
|
||||
* wizard.
|
||||
* @param progressPanel The third panel of the data source wizard.
|
||||
* The visual component that displays this panel. If you need to access the
|
||||
* component from this class, just use getComponent().
|
||||
*/
|
||||
AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel selectDataSourcePanel, AddImageWizardAddingProgressPanel progressPanel) {
|
||||
this.selectDataSourcePanel = selectDataSourcePanel;
|
||||
this.progressPanel = progressPanel;
|
||||
changeSupport = new ChangeSupport(this);
|
||||
private Component component = null;
|
||||
|
||||
/*
|
||||
* Create a collection to receive the Content objects returned by the
|
||||
* data source processor.
|
||||
*/
|
||||
newContents = Collections.synchronizedList(new ArrayList<Content>());
|
||||
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
|
||||
private boolean ingested = false;
|
||||
private boolean readyToIngest = false;
|
||||
|
||||
// task that will clean up the created database file if the wizard is cancelled before it finishes
|
||||
private AddImageAction.CleanupTask cleanupTask;
|
||||
|
||||
private final AddImageAction addImageAction;
|
||||
|
||||
private final AddImageWizardAddingProgressPanel progressPanel;
|
||||
private final AddImageWizardChooseDataSourcePanel dataSourcePanel;
|
||||
|
||||
private DataSourceProcessor dsProcessor;
|
||||
|
||||
AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
|
||||
this.addImageAction = action;
|
||||
this.progressPanel = proPanel;
|
||||
this.dataSourcePanel = dsPanel;
|
||||
|
||||
/*
|
||||
* Get the ingest job settings for the add data source wizard context
|
||||
* and use them to create an ingest module configuration panel.
|
||||
*/
|
||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(AddImageWizardIngestConfigPanel.class.getCanonicalName());
|
||||
showIngestModuleConfigurationWarnings(ingestJobSettings);
|
||||
ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings);
|
||||
|
||||
/*
|
||||
* This flag is used to stop the data source processing thread from
|
||||
* starting the ingest job before the user has finished configuring the
|
||||
* ingest modules. It is only set in the EDT.
|
||||
*/
|
||||
ingestModulesConfigured = false;
|
||||
|
||||
/*
|
||||
* This flag is required because because the storeSettings method is
|
||||
* currently called twice during the course of executing the add data
|
||||
* source wizard, whether invoked from the new case wizard or
|
||||
* independently. This means that the tryStartDataSourceIngestJob method
|
||||
* gets called three times: once when the data source processor
|
||||
* completes, and twice when the two storeSettings calls are made.
|
||||
*
|
||||
* TODO (AUT-1864): Figure out whether storeSettings is always called
|
||||
* twice by NetBeans, or the extra call is due to an Autopsy bug.
|
||||
*/
|
||||
ingestJobStarted = false;
|
||||
showWarnings(ingestJobSettings);
|
||||
this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the visual component for the panel. In this template, the component
|
||||
* Get the visual component for the panel. In this template, the component
|
||||
* is kept separate. This can be more efficient: if the wizard is created
|
||||
* but never displayed, or not all panels are displayed, it is better to
|
||||
* create only those which really need to be visible.
|
||||
*
|
||||
* @return The UI component of this wizard panel.
|
||||
* @return component the UI component of this wizard panel
|
||||
*/
|
||||
@Override
|
||||
public Component getComponent() {
|
||||
if (null == component) {
|
||||
if (component == null) {
|
||||
component = new AddImageWizardIngestConfigVisual(this.ingestJobSettingsPanel);
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help for this panel. When the panel is active, this is used as
|
||||
* the help for the wizard dialog.
|
||||
* Help for this panel. When the panel is active, this is used as the help
|
||||
* for the wizard dialog.
|
||||
*
|
||||
* @return The help for this panel
|
||||
* @return HelpCtx.DEFAULT_HELP the help for this panel
|
||||
*/
|
||||
@Override
|
||||
public HelpCtx getHelp() {
|
||||
// Show no Help button for this panel:
|
||||
return HelpCtx.DEFAULT_HELP;
|
||||
// If you have context help:
|
||||
// return new HelpCtx(SampleWizardPanel1.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not the panel is finished. If the panel is valid, the
|
||||
* "Finish" button will be enabled.
|
||||
* Tests whether the panel is finished. If the panel is valid, the "Finish"
|
||||
* button will be enabled.
|
||||
*
|
||||
* @return True or false.
|
||||
* @return true the finish button should be always enabled at this point
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
@ -153,53 +123,52 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<Wi
|
||||
// return someCondition();
|
||||
// and when this condition changes (last form field filled in...) then:
|
||||
// fireChangeEvent();
|
||||
// and uncomment the complicated stuff below.
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Adds a listener to changes of the panel's validity.
|
||||
*
|
||||
* @param l the change listener to add
|
||||
*/
|
||||
@Override
|
||||
public final void addChangeListener(ChangeListener listener) {
|
||||
changeSupport.addChangeListener(listener);
|
||||
public final void addChangeListener(ChangeListener l) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Removes a listener to changes of the panel's validity.
|
||||
*
|
||||
* @param l the change listener to move
|
||||
*/
|
||||
@Override
|
||||
public final void removeChangeListener(ChangeListener listener) {
|
||||
changeSupport.removeChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected final void fireChangeEvent() {
|
||||
changeSupport.fireChange();
|
||||
public final void removeChangeListener(ChangeListener l) {
|
||||
}
|
||||
|
||||
// You can use a settings object to keep track of state. Normally the
|
||||
// settings object will be the WizardDescriptor, so you can use
|
||||
// WizardDescriptor.getProperty & putProperty to store information entered
|
||||
// by the user.
|
||||
/**
|
||||
* Provides the wizard panel with the current data--either the default data
|
||||
* or already-modified settings, if the user used the previous and/or next
|
||||
* buttons. This method can be called multiple times on one instance of
|
||||
* WizardDescriptor.Panel.
|
||||
*
|
||||
* @param settings The settings.
|
||||
* @param settings the setting to be read from
|
||||
*/
|
||||
@Override
|
||||
public void readSettings(WizardDescriptor settings) {
|
||||
/*
|
||||
* The user has pushed the next button on the previous panel of the add
|
||||
* data source wizard. Start the data source processor so it can run
|
||||
* while the user is doing the ingest module configuration. It is ok to
|
||||
* do this now because the back button is disabled for this wizard - the
|
||||
* user cannot go back to choose a different data source.
|
||||
*
|
||||
* RC: Not sure why the cancel button is disabled.
|
||||
*/
|
||||
JButton cancel = new JButton(NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text"));
|
||||
JButton cancel = new JButton(
|
||||
NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text"));
|
||||
cancel.setEnabled(false);
|
||||
settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, cancel});
|
||||
cleanupTask = null;
|
||||
readyToIngest = false;
|
||||
|
||||
newContents.clear();
|
||||
|
||||
// Start processing the data source by handing it off to the selected DSP,
|
||||
// so it gets going in the background while the user is still picking the Ingest modules
|
||||
startDataSourceProcessing(settings);
|
||||
}
|
||||
|
||||
@ -214,29 +183,16 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<Wi
|
||||
*/
|
||||
@Override
|
||||
public void storeSettings(WizardDescriptor settings) {
|
||||
/*
|
||||
* The user has pushed the next button on this panel. Save the ingest
|
||||
* job settings for the add data source wizard context and try to start
|
||||
* the ingest job. It is ok to do this now because the back button is
|
||||
* disabled for this wizard - the user cannot go back to choose a
|
||||
* different data source. However, the job will not be started if either
|
||||
* the data source processor has not finished yet, or it finished but
|
||||
* did not produce any Content objects for the data source.
|
||||
*/
|
||||
IngestJobSettings ingestJobSettings = this.ingestJobSettingsPanel.getSettings();
|
||||
ingestJobSettings.save();
|
||||
showIngestModuleConfigurationWarnings(ingestJobSettings);
|
||||
ingestModulesConfigured = true;
|
||||
tryStartIngestJob();
|
||||
showWarnings(ingestJobSettings);
|
||||
|
||||
// Start ingest if it hasn't already been started
|
||||
readyToIngest = true;
|
||||
startIngest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays any warnings returned form operations on the ingest job settings
|
||||
* for the add data source wizard context.
|
||||
*
|
||||
* @param ingestJobSettings The ingest job settings.
|
||||
*/
|
||||
private static void showIngestModuleConfigurationWarnings(IngestJobSettings ingestJobSettings) {
|
||||
private static void showWarnings(IngestJobSettings ingestJobSettings) {
|
||||
List<String> warnings = ingestJobSettings.getWarnings();
|
||||
if (warnings.isEmpty() == false) {
|
||||
StringBuilder warningMessage = new StringBuilder();
|
||||
@ -248,78 +204,76 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<Wi
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the data source processor selected by the user when the previous
|
||||
* panel was displayed.
|
||||
* Start ingest after verifying we have a new image, we are ready to ingest,
|
||||
* and we haven't already ingested.
|
||||
*/
|
||||
private void startIngest() {
|
||||
if (!newContents.isEmpty() && readyToIngest && !ingested) {
|
||||
ingested = true;
|
||||
IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettingsPanel.getSettings());
|
||||
progressPanel.setStateFinished();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Data source processing by kicking off the selected
|
||||
* DataSourceProcessor
|
||||
*/
|
||||
private void startDataSourceProcessing(WizardDescriptor settings) {
|
||||
/*
|
||||
* Create a unique id to use to synch up the data source events that are
|
||||
* published for the data source being added.
|
||||
*/
|
||||
final UUID addDataSourceEventId = UUID.randomUUID();
|
||||
final UUID dataSourceId = UUID.randomUUID();
|
||||
|
||||
/*
|
||||
* Register a clean up task with the action that invokes the add data
|
||||
* source wizard. This action takes responsibility for doing cleanup
|
||||
* after the wizard is closed (see the definition of the AddImageAction
|
||||
* class).
|
||||
*/
|
||||
cleanupTask = CallableSystemAction.get(AddImageAction.class).new CleanupTask() {
|
||||
// Add a cleanup task to interrupt the background process if the
|
||||
// wizard exits while the background process is running.
|
||||
cleanupTask = addImageAction.new CleanupTask() {
|
||||
@Override
|
||||
void cleanup() throws Exception {
|
||||
new Thread(() -> {
|
||||
/*
|
||||
* Publish a failed adding data source event, using the
|
||||
* event id associated with the adding data source event.
|
||||
*/
|
||||
Case.getCurrentCase().notifyFailedAddingDataSource(addDataSourceEventId);
|
||||
}).start();
|
||||
dsProcessor.cancel();
|
||||
cancelDataSourceProcessing(dataSourceId);
|
||||
}
|
||||
};
|
||||
|
||||
cleanupTask.enable();
|
||||
|
||||
/*
|
||||
* Publish an adding data source event.
|
||||
*/
|
||||
// get the selected DSProcessor
|
||||
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
|
||||
|
||||
new Thread(() -> {
|
||||
Case.getCurrentCase().notifyAddingDataSource(addDataSourceEventId);
|
||||
Case.getCurrentCase().notifyAddingDataSource(dataSourceId);
|
||||
}).start();
|
||||
|
||||
/*
|
||||
* Notify the progress panel for this wizard that data source processing
|
||||
* is starting.
|
||||
*/
|
||||
progressPanel.setStateStarted();
|
||||
|
||||
/*
|
||||
* Get the data source processor the user selected and start it.
|
||||
*/
|
||||
dsProcessor = selectDataSourcePanel.getComponent().getCurrentDSProcessor();
|
||||
DataSourceProcessorCallback callback = new DataSourceProcessorCallback() {
|
||||
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
|
||||
@Override
|
||||
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
|
||||
dataSourceProcessorDone(addDataSourceEventId, result, errList, contents);
|
||||
dataSourceProcessorDone(dataSourceId, result, errList, contents);
|
||||
}
|
||||
|
||||
};
|
||||
dsProcessor.run(progressPanel.getDSPProgressMonitor(), callback);
|
||||
|
||||
progressPanel.setStateStarted();
|
||||
|
||||
// Kick off the DSProcessor
|
||||
dsProcessor.run(progressPanel.getDSPProgressMonitorImpl(), cbObj);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The callback for the data source processor to invoke when it finishes.
|
||||
* Cancels the data source processing - in case the users presses 'Cancel'
|
||||
*/
|
||||
private void dataSourceProcessorDone(UUID addDataSourceEventId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
|
||||
/*
|
||||
* Disable the clean up task.
|
||||
*/
|
||||
private void cancelDataSourceProcessing(UUID dataSourceId) {
|
||||
new Thread(() -> {
|
||||
Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId);
|
||||
}).start();
|
||||
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(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
|
||||
// disable the cleanup task
|
||||
cleanupTask.disable();
|
||||
|
||||
/*
|
||||
* Get the user's attention.
|
||||
*
|
||||
* RC: Is this really necessary?
|
||||
*/
|
||||
java.awt.Toolkit.getDefaultToolkit().beep();
|
||||
// Get attention for the process finish
|
||||
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
|
||||
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
|
||||
if (panel != null) {
|
||||
Window w = SwingUtilities.getWindowAncestor(panel);
|
||||
@ -327,12 +281,10 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<Wi
|
||||
w.toFront();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify the progress panel that the data source processor has finished
|
||||
* its work and display the processing results on the progress panel.
|
||||
*/
|
||||
// Tell the panel we're done
|
||||
progressPanel.setStateFinished();
|
||||
|
||||
//check the result and display to user
|
||||
if (result == DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS) {
|
||||
progressPanel.getComponent().setProgressBarTextAndColor(
|
||||
NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text"), 100, Color.black);
|
||||
@ -340,45 +292,32 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<Wi
|
||||
progressPanel.getComponent().setProgressBarTextAndColor(
|
||||
NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.errs.text"), 100, Color.red);
|
||||
}
|
||||
|
||||
//if errors, display them on the progress panel
|
||||
boolean critErr = false;
|
||||
if (result == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
|
||||
critErr = true;
|
||||
}
|
||||
for (String err : errList) {
|
||||
progressPanel.displayDataSourceProcessorError(err, critErr);
|
||||
// TBD: there probably should be an error level for each error
|
||||
progressPanel.addErrors(err, critErr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the Content objects returned by the data source processor.
|
||||
*/
|
||||
newContents.clear();
|
||||
newContents.addAll(contents);
|
||||
|
||||
//notify the UI of the new content added to the case
|
||||
new Thread(() -> {
|
||||
if (!newContents.isEmpty()) {
|
||||
Case.getCurrentCase().notifyDataSourceAdded(newContents.get(0), addDataSourceEventId);
|
||||
Case.getCurrentCase().notifyDataSourceAdded(newContents.get(0), dataSourceId);
|
||||
} else {
|
||||
Case.getCurrentCase().notifyFailedAddingDataSource(addDataSourceEventId);
|
||||
Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId);
|
||||
}
|
||||
}).start();
|
||||
|
||||
/*
|
||||
* Try starting the ingest job for this data source. If the data source
|
||||
* processor finished before the user finished configuring the ingest
|
||||
* modules, the job will not be started yet.
|
||||
*/
|
||||
tryStartIngestJob();
|
||||
}
|
||||
// Start ingest if we can
|
||||
progressPanel.setStateStarted();
|
||||
startIngest();
|
||||
|
||||
/**
|
||||
* Starts an ingest job for the data source, but only if the data source
|
||||
* processor has been run and has produced content, and the ingest modules
|
||||
* are configured.
|
||||
*/
|
||||
synchronized private void tryStartIngestJob() {
|
||||
if (!newContents.isEmpty() && ingestModulesConfigured && !ingestJobStarted) {
|
||||
ingestJobStarted = true; // See contructor for comment on this flag.
|
||||
IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettingsPanel.getSettings());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -28,52 +28,52 @@ import org.openide.WizardDescriptor;
|
||||
import org.openide.util.NbBundle;
|
||||
|
||||
/**
|
||||
* The iterator for the add data source wizard panels.
|
||||
* The iterator class for the "Add Image" wizard panel. This class is used to
|
||||
* iterate on the sequence of panels of the "Add Image" wizard panel.
|
||||
*/
|
||||
final class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDescriptor> {
|
||||
class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDescriptor> {
|
||||
|
||||
private int index = 0;
|
||||
private List<WizardDescriptor.Panel<WizardDescriptor>> panels;
|
||||
private AddImageAction action;
|
||||
|
||||
AddImageWizardIterator(AddImageAction action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily create the panels for the add data source wizard.
|
||||
* Initialize panels representing individual wizard's steps and sets various
|
||||
* properties for them influencing wizard appearance.
|
||||
*/
|
||||
private List<WizardDescriptor.Panel<WizardDescriptor>> getPanels() {
|
||||
if (null == panels) {
|
||||
panels = new ArrayList<>();
|
||||
if (panels == null) {
|
||||
panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>();
|
||||
|
||||
/*
|
||||
* Create the wizard panels. The first panel is used to select a
|
||||
* data source. The second panel is used to configure the ingest
|
||||
* modules. The third panel has a progress bar that tracks progress
|
||||
* as the Sleuthkit layer adds the data source to the case database.
|
||||
*/
|
||||
AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel();
|
||||
AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel();
|
||||
AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, progressPanel);
|
||||
|
||||
AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel);
|
||||
AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel);
|
||||
|
||||
panels.add(dsPanel);
|
||||
panels.add(ingestConfigPanel);
|
||||
panels.add(progressPanel);
|
||||
|
||||
/*
|
||||
* Set the appearance of the visual components of the panels.
|
||||
*/
|
||||
String[] steps = new String[panels.size()];
|
||||
for (int i = 0; i < panels.size(); i++) {
|
||||
Component visualComponent = panels.get(i).getComponent();
|
||||
// Default step name to component name.
|
||||
steps[i] = visualComponent.getName();
|
||||
if (visualComponent instanceof JComponent) {
|
||||
JComponent jc = (JComponent) visualComponent;
|
||||
// Set step number.
|
||||
jc.putClientProperty("WizardPanel_contentSelectedIndex", i);
|
||||
// Sets step name.
|
||||
Component c = panels.get(i).getComponent();
|
||||
// Default step name to component name of panel.
|
||||
steps[i] = c.getName();
|
||||
if (c instanceof JComponent) { // assume Swing components
|
||||
JComponent jc = (JComponent) c;
|
||||
// Sets step number of a component
|
||||
jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
|
||||
// Sets steps names for a panel
|
||||
jc.putClientProperty("WizardPanel_contentData", steps);
|
||||
// Turn on subtitle creation.
|
||||
// Turn on subtitle creation on each step
|
||||
jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
|
||||
// Show steps on the left side, with image in the background.
|
||||
// Show steps on the left side with the image on the background
|
||||
jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
|
||||
// Turn on step numbering.
|
||||
// Turn on numbering of all steps
|
||||
jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@ -81,10 +81,20 @@ final class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDe
|
||||
return panels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the current panel. Note: 0 = panel 1, 1 = panel 2,
|
||||
* etc
|
||||
*
|
||||
* @return index the current panel index
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current panel.
|
||||
*
|
||||
* @return The current panel.
|
||||
* @return panel the current panel
|
||||
*/
|
||||
@Override
|
||||
public WizardDescriptor.Panel<WizardDescriptor> current() {
|
||||
@ -98,17 +108,18 @@ final class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDe
|
||||
/**
|
||||
* Gets the name of the current panel.
|
||||
*
|
||||
* @return The name of the current panel.
|
||||
* @return name the name of the current panel
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return NbBundle.getMessage(this.getClass(), "AddImageWizardIterator.stepXofN", Integer.toString(index + 1), getPanels().size());
|
||||
return NbBundle.getMessage(this.getClass(), "AddImageWizardIterator.stepXofN", Integer.toString(index + 1),
|
||||
getPanels().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether there is a next panel.
|
||||
*
|
||||
* @return True or false.
|
||||
* @return boolean true if it has next panel, false if not
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
@ -118,18 +129,17 @@ final class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDe
|
||||
/**
|
||||
* Tests whether there is a previous panel.
|
||||
*
|
||||
* @return True or false.
|
||||
* @return boolean true if it has previous panel, false if not
|
||||
*/
|
||||
@Override
|
||||
// disable the previous button on all panels
|
||||
public boolean hasPrevious() {
|
||||
/*
|
||||
* Disable the back buttons for the add data source wizard.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the next panel.
|
||||
* Moves to the next panel. I.e. increment its index, need not actually
|
||||
* change any GUI itself.
|
||||
*/
|
||||
@Override
|
||||
public void nextPanel() {
|
||||
@ -140,7 +150,8 @@ final class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDe
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the previous panel.
|
||||
* Moves to the previous panel. I.e. decrement its index, need not actually
|
||||
* change any GUI itself.
|
||||
*/
|
||||
@Override
|
||||
public void previousPanel() {
|
||||
@ -153,18 +164,12 @@ final class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDe
|
||||
index--;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// If nothing unusual changes in the middle of the wizard, simply:
|
||||
@Override
|
||||
public void addChangeListener(ChangeListener l) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void removeChangeListener(ChangeListener l) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ AddImageAction.ingestConfig.ongoingIngest.msg=<html>Ingest is ongoing on another
|
||||
AddImageAction.ingestConfig.ongoingIngest.title=Ingest in progress
|
||||
AddImageTask.run.progress.adding=Adding\: {0}
|
||||
AddImageTask.interrupt.exception.msg=Error stopping add-image process.
|
||||
AddImageWizardAddingProgressPanel.isValid.focusNext=Next >
|
||||
AddImageWizardAddingProgressPanel.stateStarted.progressBarText=*This process may take some time for large data sources.
|
||||
AddImageWizardAddingProgressVisual.addingDsComplete.text=Adding Data Source - Complete
|
||||
AddImageWizardAddingProgressVisual.getName.text=Add Data Source
|
||||
|
@ -88,6 +88,7 @@ AddImageAction.ingestConfig.ongoingIngest.msg=<html>\u4ed6\u306e\u30c7\u30fc\u30
|
||||
AddImageAction.ingestConfig.ongoingIngest.title=\u51e6\u7406\u4e2d
|
||||
AddImageTask.run.progress.adding=\u8ffd\u52a0\u4e2d\uff1a{0}
|
||||
AddImageTask.interrupt.exception.msg=\u30a4\u30e1\u30fc\u30b8\u8ffd\u52a0\u30d7\u30ed\u30bb\u30b9\u306e\u505c\u6b62\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
|
||||
AddImageWizardAddingProgressPanel.isValid.focusNext=\u6b21 >
|
||||
AddImageWizardAddingProgressPanel.stateStarted.progressBarText=*\u5927\u304d\u3044\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306e\u5834\u5408\u3001\u3053\u306e\u30d7\u30ed\u30bb\u30b9\u306f\u6642\u9593\u304c\u304b\u304b\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002
|
||||
AddImageWizardAddingProgressVisual.addingDsComplete.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0 - \u5b8c\u4e86
|
||||
AddImageWizardAddingProgressVisual.getName.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0
|
||||
|
Loading…
x
Reference in New Issue
Block a user