Accurate user-friendly case create/open error dialogs

This commit is contained in:
Richard Cordovano 2016-01-30 15:00:03 -05:00
parent 518eccb7e9
commit 1a908d109f
7 changed files with 281 additions and 227 deletions

View File

@ -108,11 +108,11 @@ AddImageWizardIterator.stepXofN=Step {0} of {1}
AddLocalFilesTask.localFileAdd.progress.text=Adding\: {0}/{1}
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\!
Case.create.exception.msg=Error creating a case\: {0} in dir {1}
Case.databaseConnectionInfo.error.msg=Error accessing case database connection info
Case.databaseConnectionInfo.error.msg=Error accessing database server connection info. See Tools, Options, Multi-user.
Case.open.exception.blankCase.msg=Case name is blank.
Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made\:\n {0}
Case.open.msgDlg.updated.title=Case Database Schema Update
Case.open.exception.checkFile.msg=Check that you selected the correct case file (usually with {0} extension)
Case.open.exception.checkFile.msg=Case file must have {0} extension.
Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-user.
Case.checkImgExist.confDlg.doesntExist.msg={0} has detected that one of the images associated with \n\
this case are missing. Would you like to search for them now?\n\
@ -139,6 +139,9 @@ Case.createCaseDir.exception.gen=Could not create case directory\: {0}
Case.CollaborationSetup.FailNotify.ErrMsg=Failed to connect to any other nodes that may be collaborating on this case.
Case.CollaborationSetup.FailNotify.Title=Connection Failure
Case.GetCaseTypeGivenPath.Failure=Unable to get case type
Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted.
Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk.
Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1}
CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\
Case Name\: {0}\n\
Case Directory\: {1}
@ -208,14 +211,11 @@ NewCaseWizardPanel1.validate.errMsg.cantCreateDir=Error\: Could not create direc
NewCaseWizardPanel1.validate.errMsg.invalidBaseDir.msg=ERROR\: The Base Directory that you entered is not valid.\nPlease enter a valid Base Directory.
NewCaseWizardPanel1.createDir.errMsg.cantCreateDir.msg=ERROR\: Could not create the case directory. \nPlease enter a valid Case Name and Directory.
NewCaseWizardPanel2.validate.errCreateCase.msg=Error creating case
OpenRecentCasePanel.openCase.msgDlg.caseDoesntExist.msg=Error\: Case {0} does not exist.
OpenRecentCasePanel.openCase.msgDlg.err=Error
OpenRecentCasePanel.colName.caseName=Case Name
OpenRecentCasePanel.colName.path=Path
RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range.
RecentCases.getName.text=Clear Recent Cases
RecentItems.openRecentCase.msgDlg.text=Error\: Case {0} does not exist.
RecentItems.openRecentCase.msgDlg.err=Error
RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists.
StartupWindow.title.text=Welcome
UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases
UpdateRecentCases.menuItem.empty=-Empty-
@ -240,13 +240,10 @@ NewCaseVisualPanel1.caseParentDirWarningLabel.text=
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user
NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user
NewCaseVisualPanel1.caseTypeLabel.text=Case Type:
Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk.
Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1}
CasePropertiesForm.lbDbType.text=Case Type:
CasePropertiesForm.tbDbType.text=
CasePropertiesForm.lbDbName.text=Database Name:
CasePropertiesForm.tbDbName.text=
CaseExceptionWarning.CheckMultiUserOptions=Check Multi-user options.
SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist!
SingleUserCaseConverter.AlreadyMultiUser=Case is already multi-user!
SingleUserCaseConverter.NonUniqueDatabaseName=Database name not unique.

View File

@ -192,14 +192,11 @@ NewCaseWizardPanel1.validate.errMsg.cantCreateDir=\u30a8\u30e9\u30fc\uff1a\u30c7
NewCaseWizardPanel1.validate.errMsg.invalidBaseDir.msg=\u30a8\u30e9\u30fc\uff1a\u5165\u529b\u3057\u305f\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306f\u6709\u52b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\n\u6709\u52b9\u306a\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002
NewCaseWizardPanel1.createDir.errMsg.cantCreateDir.msg=\u30a8\u30e9\u30fc\uff1a\u30b1\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n\u6709\u52b9\u306a\u30b1\u30fc\u30b9\u540d\u304a\u3088\u3073\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002
NewCaseWizardPanel2.validate.errCreateCase.msg=\u30b1\u30fc\u30b9\u4f5c\u6210\u30a8\u30e9\u30fc
OpenRecentCasePanel.openCase.msgDlg.caseDoesntExist.msg=\u30a8\u30e9\u30fc\uff1a\u30b1\u30fc\u30b9{0}\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
OpenRecentCasePanel.openCase.msgDlg.err=\u30a8\u30e9\u30fc
OpenRecentCasePanel.colName.caseName=\u30b1\u30fc\u30b9\u540d
OpenRecentCasePanel.colName.path=\u30d1\u30b9
RecentCases.exception.caseIdxOutOfRange.msg=\u6700\u8fd1\u306e\u30b1\u30fc\u30b9\u30a4\u30f3\u30c7\u30c3\u30af\u30b9{0}\u306f\u7bc4\u56f2\u5916\u3067\u3059\u3002
RecentCases.getName.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u30af\u30ea\u30a2
RecentItems.openRecentCase.msgDlg.text=\u30a8\u30e9\u30fc\uff1a\u30b1\u30fc\u30b9{0}\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
RecentItems.openRecentCase.msgDlg.err=\u30a8\u30e9\u30fc
StartupWindow.title.text=\u3088\u3046\u3053\u305d
UpdateRecentCases.menuItem.clearRecentCases.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u30af\u30ea\u30a2
UpdateRecentCases.menuItem.empty=-\u7a7a\u767d-

View File

@ -384,7 +384,8 @@ public class Case implements SleuthkitCase.ErrorObserver {
@Override
public void receiveError(String context, String errorMessage) {
/* NOTE: We are accessing tskErrorReporter from two different threads.
/*
* NOTE: We are accessing tskErrorReporter from two different threads.
* This is ok as long as we only read the value of tskErrorReporter
* because tskErrorReporter is declared as volatile.
*/
@ -398,63 +399,87 @@ public class Case implements SleuthkitCase.ErrorObserver {
}
/**
* Creates a new case (create the XML config file and database). Overload
* for API consistency, defaults to a single-user case.
* Creates a single-user new case.
*
* @param caseDir The directory to store case data in. Will be created if
* it doesn't already exist. If it exists, it should have
* all of the needed sub dirs that createCaseDirectory()
* will create.
* @param caseName the name of case
* @param caseNumber the case number
* @param examiner the examiner for this case
* @param caseDir The full path of the case directory. It will be created
* if it doesn't already exist; if it exists, it should
* have been created using Case.createCaseDirectory() to
* ensure that the required sub-directories aere created.
* @param caseName The name of case.
* @param caseNumber The case number, can be the empty string.
* @param examiner The examiner to associate with the case, can be the
* empty string.
*
* @throws org.sleuthkit.autopsy.casemodule.CaseActionException
* @throws CaseActionException if there is a problem creating the case. The
* exception will have a user-friendly message
* and may be a wrapper for a lower-level
* exception. If so,
* CaseActionException.getCause will return a
* Throwable (null otherwise).
*/
public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException {
create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE);
}
/**
* Creates a new case (create the XML config file and database)
* Creates a new case.
*
* @param caseDir The directory to store case data in. Will be created if
* it doesn't already exist. If it exists, it should have
* all of the needed sub dirs that createCaseDirectory()
* will create.
* @param caseName the name of case
* @param caseNumber the case number
* @param examiner the examiner for this case
* @param caseType the type of case, single-user or multi-user
* @param caseDir The full path of the case directory. It will be created
* if it doesn't already exist; if it exists, it should
* have been created using Case.createCaseDirectory() to
* ensure that the required sub-directories aere created.
* @param caseName The name of case.
* @param caseNumber The case number, can be the empty string.
* @param examiner The examiner to associate with the case, can be the
* empty string.
* @param caseType The type of case (single-user or multi-user). The
* exception will have a user-friendly message and may be
* a wrapper for a lower-level exception. If so,
* CaseActionException.getCause will return a Throwable
* (null otherwise).
*
* @throws CaseActionException if there is a problem creating the case.
*/
public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException {
logger.log(Level.INFO, "Creating new case.\ncaseDir: {0}\ncaseName: {1}", new Object[]{caseDir, caseName}); //NON-NLS
logger.log(Level.INFO, "Creating case with case directory {0}, caseName {1}", new Object[]{caseDir, caseName}); //NON-NLS
// create case directory if it doesn't already exist.
/*
* Create case directory if it doesn't already exist.
*/
if (new File(caseDir).exists() == false) {
Case.createCaseDirectory(caseDir, caseType);
}
String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION;
XMLCaseManagement xmlcm = new XMLCaseManagement();
/*
* Sanitize the case name, create a unique keyword search index name,
* and create a standard (single-user) or unique (multi-user) case
* database name.
*/
String santizedCaseName = sanitizeCaseName(caseName);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
Date date = new Date();
String santizedCaseName = sanitizeCaseName(caseName);
String indexName = santizedCaseName + "_" + dateFormat.format(date);
String dbName = null;
// figure out the database name and index name for text extraction
if (caseType == CaseType.SINGLE_USER_CASE) {
dbName = caseDir + File.separator + "autopsy.db"; //NON-NLS
} else if (caseType == CaseType.MULTI_USER_CASE) {
dbName = indexName;
}
xmlcm.create(caseDir, caseName, examiner, caseNumber, caseType, dbName, indexName); // create a new XML config file
/*
* Create the case metadata (.aut) file.
*
* TODO (AUT-1885): Replace use of obsolete and unsafe XMLCaseManagement
* class with use of CaseMetadata class.
*/
String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION;
XMLCaseManagement xmlcm = new XMLCaseManagement();
xmlcm.create(caseDir, caseName, examiner, caseNumber, caseType, dbName, indexName);
xmlcm.writeFile();
/*
* Create the case database.
*/
SleuthkitCase db = null;
try {
if (caseType == CaseType.SINGLE_USER_CASE) {
@ -463,24 +488,23 @@ public class Case implements SleuthkitCase.ErrorObserver {
db = SleuthkitCase.newCase(dbName, UserPreferences.getDatabaseConnectionInfo(), caseDir);
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error creating a case: " + caseName + " in dir " + caseDir + " " + ex.getMessage(), ex); //NON-NLS
logger.log(Level.SEVERE, String.format("Error creating a case %s in %s ", caseName, caseDir), ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
/*
* SleuthkitCase.newCase throws TskCoreExceptions with user-friendly
* messages, so propagate the exception message.
*/
throw new CaseActionException(ex.getMessage(), ex); //NON-NLS
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
throw new CaseActionException(
NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
}
/**
* Two-stage initialization to avoid leaking reference to "this" in
* constructor.
*/
Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType);
changeCase(newCase);
}
@ -549,20 +573,28 @@ public class Case implements SleuthkitCase.ErrorObserver {
/**
* Opens an existing case.
*
* @param caseMetadataFilePath The path of the case metadata file for the
* case to be opened.
* @param caseMetadataFilePath The path of the case metadata file.
*
* @throws CaseActionException
* @throws CaseActionException if there is a problem opening the case. The
* exception will have a user-friendly message
* and may be a wrapper for a lower-level
* exception. If so,
* CaseActionException.getCause will return a
* Throwable (null otherwise).
*/
public static void open(String caseMetadataFilePath) throws CaseActionException {
logger.log(Level.INFO, "Opening case with metadata file path {0}", caseMetadataFilePath); //NON-NLS
/*
* Verify the extension of the case metadata file.
*/
if (!caseMetadataFilePath.endsWith(CASE_DOT_EXTENSION)) {
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.checkFile.msg", CASE_DOT_EXTENSION));
}
logger.log(Level.INFO, "Opening case, case metadata file path: {0}", caseMetadataFilePath); //NON-NLS
try {
/**
* Get the case metadata from the file.
/*
* Get the case metadata required to open the case database.
*/
CaseMetadata metadata = new CaseMetadata(Paths.get(caseMetadataFilePath));
String caseName = metadata.getCaseName();
@ -571,7 +603,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
CaseType caseType = metadata.getCaseType();
String caseDir = metadata.getCaseDirectory();
/**
/*
* Open the case database.
*/
SleuthkitCase db;
@ -585,40 +617,57 @@ public class Case implements SleuthkitCase.ErrorObserver {
try {
db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir);
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
}
}
/**
* Do things that require a UI.
/*
* Check for the presence of the UI and do things that can only be
* done with user interaction.
*/
if (RuntimeProperties.coreComponentsAreActive()) {
/**
/*
* If the case database was upgraded for a new schema, notify
* the user.
*/
if (null != db.getBackupDatabasePath()) {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg",
db.getBackupDatabasePath()),
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg", db.getBackupDatabasePath()),
NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"),
JOptionPane.INFORMATION_MESSAGE);
});
}
/**
* TODO: This currently has no value if it there is no user to
* interact with a fid missing images dialog.
/*
* Look for the files for the data sources listed in the case
* database and give the user the opportunity to locate any that
* are missing.
*/
checkImagesExist(db);
Map<Long, String> imgPaths = getImagePaths(db);
for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
long obj_id = entry.getKey();
String path = entry.getValue();
boolean fileExists = (pathExists(path) || driveExists(path));
if (!fileExists) {
int ret = JOptionPane.showConfirmDialog(
WindowManager.getDefault().getMainWindow(),
NbBundle.getMessage(Case.class, "Case.checkImgExist.confDlg.doesntExist.msg", getAppName(), path),
NbBundle.getMessage(Case.class, "Case.checkImgExist.confDlg.doesntExist.title"),
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!"); //NON-NLS
}
}
}
}
/**
* Two-stage initialization to avoid leaking reference to "this" in
* constructor. TODO: Remove use of obsolete XMLCaseManagement
* class.
/*
* TODO (AUT-1885): Replace use of obsolete and unsafe
* XMLCaseManagement class with use of CaseMetadata class.
*/
XMLCaseManagement xmlcm = new XMLCaseManagement();
xmlcm.open(caseMetadataFilePath);
@ -626,28 +675,16 @@ public class Case implements SleuthkitCase.ErrorObserver {
changeCase(openedCase);
} catch (CaseMetadataException ex) {
/**
* Attempt clean up.
*/
try {
Case badCase = Case.getCurrentCase();
badCase.closeCase();
} catch (IllegalStateException ignored) {
}
throw new CaseActionException(ex.getMessage(), ex); //NON-NLS
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.metaDataFileCorrupt.exception.msg"), ex); //NON-NLS
} catch (TskCoreException ex) {
/**
* Attempt clean up.
*/
try {
Case badCase = Case.getCurrentCase();
badCase.closeCase();
} catch (IllegalStateException ignored) {
}
SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
throw new CaseActionException(ex.getMessage(), ex); //NON-NLS
/*
* SleuthkitCase.openCase throws TskCoreExceptions with
* user-friendly messages, so propagate the exception message.
*/
throw new CaseActionException(ex.getMessage(), ex);
}
}
@ -666,35 +703,6 @@ public class Case implements SleuthkitCase.ErrorObserver {
return imgPaths;
}
/**
* Ensure that all image paths point to valid image files
*/
private static void checkImagesExist(SleuthkitCase db) {
Map<Long, String> imgPaths = getImagePaths(db);
for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
long obj_id = entry.getKey();
String path = entry.getValue();
boolean fileExists = (pathExists(path) || driveExists(path));
if (!fileExists) {
int ret = JOptionPane.showConfirmDialog(null,
NbBundle.getMessage(Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg",
getAppName(), path),
NbBundle.getMessage(Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
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!"); //NON-NLS
}
}
}
}
/**
* Adds the image to the current case after it has been added to the DB.
* Sends out event and reopens windows if needed.

View File

@ -65,7 +65,7 @@ public final class CaseOpenAction implements ActionListener {
}
/**
* Pops up a file chooser to allow the user to select a case meta data file
* Pops up a file chooser to allow the user to select a case metadata file
* (.aut file) and attempts to open the case described by the file.
*
* @param e The action event.
@ -73,21 +73,28 @@ public final class CaseOpenAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
/*
* If ingest is running, do a dialog to warn the user and confirm
* abandoning the ingest.
* If ingest is running, do a dialog to warn the user and confirm the
* intent to close the current case and leave the ingest process
* incomplete.
*/
if (IngestManager.getInstance().isIngestRunning()) {
String closeCurrentCase = NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning");
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(closeCurrentCase,
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(
NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning"),
NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning.title"),
NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE);
descriptor.setValue(NotifyDescriptor.NO_OPTION);
Object res = DialogDisplayer.getDefault().notify(descriptor);
if (res != null && res == DialogDescriptor.YES_OPTION) {
Case currentCase = null;
try {
Case.getCurrentCase().closeCase();
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error closing case", ex); //NON-NLS
currentCase = Case.getCurrentCase();
currentCase.closeCase();
} catch (IllegalStateException ignored) {
/*
* No current case.
*/
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, String.format("Error closing case at %s while ingest was running", (null != currentCase ? currentCase.getCaseDirectory() : "?")), ex); //NON-NLS
}
} else {
return;
@ -100,17 +107,13 @@ public final class CaseOpenAction implements ActionListener {
*/
int retval = fileChooser.showOpenDialog(WindowManager.getDefault().getMainWindow());
if (retval == JFileChooser.APPROVE_OPTION) {
/**
* This is a bit of a hack, but close the startup window, if it was
* the source of the action invocation.
/*
* Close the startup window, if it is open.
*/
try {
StartupWindowProvider.getInstance().close();
} catch (Exception unused) {
}
/**
* Try to open the case associated with the case meta data file the
/*
* Try to open the case associated with the case metadata file the
* user selected.
*/
final String path = fileChooser.getSelectedFile().getPath();
@ -121,12 +124,14 @@ public final class CaseOpenAction implements ActionListener {
try {
Case.open(path);
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, String.format("Could not open case at %s", path), ex);
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", path), ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getMessage(),
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), JOptionPane.ERROR_MESSAGE); //NON-NLS
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getMessage(), // Should be user-friendly
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}

View File

@ -39,10 +39,11 @@ import javax.swing.JOptionPane;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.openide.windows.WindowManager;
import java.awt.Cursor;
import java.util.concurrent.ExecutionException;
import org.sleuthkit.autopsy.ingest.IngestManager;
/**
* An action that runs the new case wizard.
* An action that creates and runs the new case wizard.
*/
final class NewCaseWizardAction extends CallableSystemAction {
@ -53,32 +54,39 @@ final class NewCaseWizardAction extends CallableSystemAction {
@Override
public void performAction() {
/*
* If ingest is running, do a dialog to warn the user and confirm
* abandoning the ingest.
* If ingest is running, do a dialog to warn the user and confirm the
* intent to close the current case and leave the ingest process
* incomplete.
*/
if (IngestManager.getInstance().isIngestRunning()) {
String closeCurrentCase = NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning");
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(closeCurrentCase,
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(
NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning"),
NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning.title"),
NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE);
descriptor.setValue(NotifyDescriptor.NO_OPTION);
Object res = DialogDisplayer.getDefault().notify(descriptor);
if (res != null && res == DialogDescriptor.YES_OPTION) {
Case currentCase = null;
try {
Case.getCurrentCase().closeCase();
} catch (Exception ex) {
Logger.getLogger(NewCaseWizardAction.class.getName()).log(Level.WARNING, "Error closing case", ex); //NON-NLS
currentCase = Case.getCurrentCase();
currentCase.closeCase();
} catch (IllegalStateException ignored) {
/*
* No current case.
*/
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, String.format("Error closing case at %s while ingest was running", (null != currentCase ? currentCase.getCaseDirectory() : "?")), ex); //NON-NLS
}
} else {
return;
}
}
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
newCaseAction();
runNewCaseWizard();
}
private void newCaseAction() {
final WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
private void runNewCaseWizard() {
final WizardDescriptor wizardDescriptor = new WizardDescriptor(getNewCaseWizardPanels());
wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.newCase.windowTitle.text"));
Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
@ -104,21 +112,14 @@ final class NewCaseWizardAction extends CallableSystemAction {
AddImageAction addImageAction = SystemAction.get(AddImageAction.class);
addImageAction.actionPerformed(null);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error creating case", ex); //NON-NLS
logger.log(Level.SEVERE, String.format("Error creating case %s", wizardDescriptor.getProperty("caseName")), ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), ex.getCause().getMessage() + " "
+ NbBundle.getMessage(this.getClass(), "CaseExceptionWarning.CheckMultiUserOptions"),
NbBundle.getMessage(this.getClass(), "CaseCreateAction.msgDlg.cantCreateCase.msg"),
JOptionPane.ERROR_MESSAGE); //NON-NLS
/**
* This is a bit of a hack, but close the startup
* window, if it was the source of the action
* invocation.
*/
try {
StartupWindowProvider.getInstance().close();
} catch (Exception unused) {
}
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
(ex instanceof ExecutionException ? ex.getCause().getMessage() : ex.getMessage()),
NbBundle.getMessage(this.getClass(), "CaseCreateAction.msgDlg.cantCreateCase.msg"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
StartupWindowProvider.getInstance().close(); // RC: Why close and open?
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}
@ -137,7 +138,6 @@ final class NewCaseWizardAction extends CallableSystemAction {
private void doFailedCaseCleanup(WizardDescriptor wizardDescriptor) {
String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
if (createdDirectory != null) {
logger.log(Level.INFO, "Deleting a created case directory due to an error, dir: {0}", createdDirectory); //NON-NLS
Case.deleteCaseDirectory(new File(createdDirectory));
}
SwingUtilities.invokeLater(() -> {
@ -146,10 +146,10 @@ final class NewCaseWizardAction extends CallableSystemAction {
}
/**
* Initializes the new case wizard panels.
* Creates the new case wizard panels.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private WizardDescriptor.Panel<WizardDescriptor>[] getPanels() {
private WizardDescriptor.Panel<WizardDescriptor>[] getNewCaseWizardPanels() {
if (panels == null) {
panels = new WizardDescriptor.Panel[]{
new NewCaseWizardPanel1(),
@ -180,21 +180,33 @@ final class NewCaseWizardAction extends CallableSystemAction {
return panels;
}
/**
* @inheritDoc
*/
@Override
public String getName() {
return NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.getName.text");
}
/**
* @inheritDoc
*/
@Override
public String iconResource() {
return null;
}
/**
* @inheritDoc
*/
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
/**
* @inheritDoc
*/
@Override
protected boolean asynchronous() {
return false;

View File

@ -43,31 +43,39 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
private static String[] casePaths;
private RecentCasesTableModel model;
/**
* Constructs a panel used by the the open recent case option of the start
* window.
*/
private OpenRecentCasePanel() {
initComponents();
}
/*
* Gets the singleton instance of the panel used by the the open recent case
* option of the start window.
*/
static OpenRecentCasePanel getInstance() {
if (instance == null) {
instance = new OpenRecentCasePanel();
}
instance.generateRecentCases(); // refresh the case list
instance.refreshRecentCasesTable();
return instance;
}
/**
* Sets the Close button action listener.
* Adds an action listener to the cancel button.
*
* @param e the action listener
* @param listener An action listener.
*/
public void setCloseButtonActionListener(ActionListener e) {
this.cancelButton.addActionListener(e);
void setCloseButtonActionListener(ActionListener listener) {
this.cancelButton.addActionListener(listener);
}
/**
* Retrieves all the recent cases and adds them to the table.
*/
private void generateRecentCases() {
private void refreshRecentCasesTable() {
caseNames = RecentCases.getInstance().getRecentCaseNames();
casePaths = RecentCases.getInstance().getRecentCasePaths();
model = new RecentCasesTableModel();
@ -86,7 +94,9 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
}
}
// Open the selected case
/*
* Opens the selected case.
*/
private void openCase() {
if (casePaths.length < 1) {
return;
@ -102,7 +112,7 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
}
/*
* Verify the case name and metadata file path.
* Open the case.
*/
if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) {
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
@ -110,14 +120,9 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"),
JOptionPane.ERROR_MESSAGE);
RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore
/*
* If a case was not already open, pop up the start window.
*/
if (Case.isCaseOpen() == false) {
StartupWindowProvider.getInstance().open();
}
} else {
SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
@ -131,12 +136,9 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getMessage(),
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), JOptionPane.ERROR_MESSAGE); //NON-NLS
/*
* If a case was not already open, pop up the start
* window.
*/
ex.getMessage(), // Should be user-friendly
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}
@ -154,6 +156,9 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
/**
* @inheritDoc
*/
@Override
public int getRowCount() {
int count = 0;
@ -165,11 +170,17 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
return count;
}
/**
* @inheritDoc
*/
@Override
public int getColumnCount() {
return 2;
}
/**
* @inheritDoc
*/
@Override
public String getColumnName(int column) {
String colName = null;
@ -186,6 +197,9 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
return colName;
}
/**
* @inheritDoc
*/
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object ret = null;
@ -203,15 +217,28 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
return ret;
}
/**
* @inheritDoc
*/
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
/**
* @inheritDoc
*/
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
/**
* Shortens a path to fit the display.
*
* @param path The path to shorten.
*
* @return The shortened path.
*/
private String shortenPath(String path) {
String shortenedPath = path;
if (shortenedPath.length() > 50) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,7 +23,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
@ -36,21 +35,23 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
/**
* This class is used to add the action to the recent case menu item. When the
* the recent case menu is pressed, it should open that selected case.
* An action listener that opens a recent case.
*/
class RecentItems implements ActionListener {
final String caseName;
final String casePath;
private JPanel caller; // for error handling
private static final Logger logger = Logger.getLogger(RecentItems.class.getName());
private final String caseName;
private final String caseMetaDataFilePath;
/**
* the constructor
* Constructs an action listener that opens a recent case.
*
* @param caseName The name of the case.
* @param caseMetaDataFilePath The path to the case metadata file.
*/
public RecentItems(String caseName, String casePath) {
public RecentItems(String caseName, String caseMetaDataFilePath) {
this.caseName = caseName;
this.casePath = casePath;
this.caseMetaDataFilePath = caseMetaDataFilePath;
}
/**
@ -60,58 +61,65 @@ class RecentItems implements ActionListener {
*/
@Override
public void actionPerformed(ActionEvent e) {
// if ingest is ongoing, warn and get confirmaion before opening a different case
/*
* If ingest is running, do a dialog to warn the user and confirm the
* intent to close the current case and leave the ingest process
* incomplete.
*/
if (IngestManager.getInstance().isIngestRunning()) {
// show the confirmation first to close the current case and open the "New Case" wizard panel
String closeCurrentCase = NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning");
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(closeCurrentCase,
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(
NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning"),
NbBundle.getMessage(this.getClass(), "CloseCaseWhileIngesting.Warning.title"),
NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE);
descriptor.setValue(NotifyDescriptor.NO_OPTION);
Object res = DialogDisplayer.getDefault().notify(descriptor);
if (res != null && res == DialogDescriptor.YES_OPTION) {
Case currentCase = null;
try {
Case.getCurrentCase().closeCase(); // close the current case
} catch (Exception ex) {
Logger.getLogger(NewCaseWizardAction.class.getName()).log(Level.WARNING, "Error closing case.", ex); //NON-NLS
currentCase = Case.getCurrentCase();
currentCase.closeCase();
} catch (IllegalStateException ignored) {
/*
* No current case.
*/
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, String.format("Error closing case at %s while ingest was running", (null!= currentCase ? currentCase.getCaseDirectory() : "?")),ex); //NON-NLS
}
} else {
return;
}
}
// check if the file exists
if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) {
// throw an error here
JOptionPane.showMessageDialog(caller,
NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.text",
caseName),
NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.err"),
/*
* Open the case.
*/
if (caseName.equals("") || caseMetaDataFilePath.equals("") || (!new File(caseMetaDataFilePath).exists())) {
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
NbBundle.getMessage(this.getClass(), "RecentItems.openRecentCase.msgDlg.text", caseName),
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"),
JOptionPane.ERROR_MESSAGE);
RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore
//if case is not opened, open the start window
RecentCases.getInstance().removeRecentCase(caseName, caseMetaDataFilePath);
if (Case.isCaseOpen() == false) {
EventQueue.invokeLater(() -> {
StartupWindowProvider.getInstance().open();
});
}
} else {
SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
});
new Thread(() -> {
// Create case.
try {
Case.open(casePath);
Case.open(caseMetaDataFilePath);
} catch (CaseActionException ex) {
SwingUtilities.invokeLater(() -> {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetaDataFilePath), ex); //NON-NLS
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), ex.getMessage(),
NbBundle.getMessage(RecentItems.this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), JOptionPane.ERROR_MESSAGE); //NON-NLS
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getMessage(), // Should be user-friendly
NbBundle.getMessage(RecentItems.this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}