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} AddLocalFilesTask.localFileAdd.progress.text=Adding\: {0}/{1}
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\! 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.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.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.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.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.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\ 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\ 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.ErrMsg=Failed to connect to any other nodes that may be collaborating on this case.
Case.CollaborationSetup.FailNotify.Title=Connection Failure Case.CollaborationSetup.FailNotify.Title=Connection Failure
Case.GetCaseTypeGivenPath.Failure=Unable to get case type 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\ CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\
Case Name\: {0}\n\ Case Name\: {0}\n\
Case Directory\: {1} 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.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. 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 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.caseName=Case Name
OpenRecentCasePanel.colName.path=Path OpenRecentCasePanel.colName.path=Path
RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range. RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range.
RecentCases.getName.text=Clear Recent Cases RecentCases.getName.text=Clear Recent Cases
RecentItems.openRecentCase.msgDlg.text=Error\: Case {0} does not exist. RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists.
RecentItems.openRecentCase.msgDlg.err=Error
StartupWindow.title.text=Welcome StartupWindow.title.text=Welcome
UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases
UpdateRecentCases.menuItem.empty=-Empty- UpdateRecentCases.menuItem.empty=-Empty-
@ -240,17 +240,14 @@ NewCaseVisualPanel1.caseParentDirWarningLabel.text=
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user
NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user
NewCaseVisualPanel1.caseTypeLabel.text=Case Type: 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.lbDbType.text=Case Type:
CasePropertiesForm.tbDbType.text= CasePropertiesForm.tbDbType.text=
CasePropertiesForm.lbDbName.text=Database Name: CasePropertiesForm.lbDbName.text=Database Name:
CasePropertiesForm.tbDbName.text= CasePropertiesForm.tbDbName.text=
CaseExceptionWarning.CheckMultiUserOptions=Check Multi-user options.
SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist! SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist!
SingleUserCaseConverter.AlreadyMultiUser=Case is already multi-user! SingleUserCaseConverter.AlreadyMultiUser=Case is already multi-user!
SingleUserCaseConverter.NonUniqueDatabaseName=Database name not unique. SingleUserCaseConverter.NonUniqueDatabaseName=Database name not unique.
SingleUserCaseConverter.UnableToCopySourceImages=Unable to copy source images SingleUserCaseConverter.UnableToCopySourceImages=Unable to copy source images
SingleUserCaseConverter.CanNotOpenDatabase=Unable to open database SingleUserCaseConverter.CanNotOpenDatabase=Unable to open database
CloseCaseWhileIngesting.Warning=Ingest is running. Are you sure you want to close the case? CloseCaseWhileIngesting.Warning=Ingest is running. Are you sure you want to close the case?
CloseCaseWhileIngesting.Warning.title=Warning\: This will close the current case CloseCaseWhileIngesting.Warning.title=Warning\: This will close the current case

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.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 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 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.caseName=\u30b1\u30fc\u30b9\u540d
OpenRecentCasePanel.colName.path=\u30d1\u30b9 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.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 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.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 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.clearRecentCases.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u30af\u30ea\u30a2
UpdateRecentCases.menuItem.empty=-\u7a7a\u767d- UpdateRecentCases.menuItem.empty=-\u7a7a\u767d-

View File

@ -384,7 +384,8 @@ public class Case implements SleuthkitCase.ErrorObserver {
@Override @Override
public void receiveError(String context, String errorMessage) { 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 * This is ok as long as we only read the value of tskErrorReporter
* because tskErrorReporter is declared as volatile. * 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 * Creates a single-user new case.
* for API consistency, defaults to a single-user case.
* *
* @param caseDir The directory to store case data in. Will be created if * @param caseDir The full path of the case directory. It will be created
* it doesn't already exist. If it exists, it should have * if it doesn't already exist; if it exists, it should
* all of the needed sub dirs that createCaseDirectory() * have been created using Case.createCaseDirectory() to
* will create. * ensure that the required sub-directories aere created.
* @param caseName the name of case * @param caseName The name of case.
* @param caseNumber the case number * @param caseNumber The case number, can be the empty string.
* @param examiner the examiner for this case * @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 { public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException {
create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE); 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 * @param caseDir The full path of the case directory. It will be created
* it doesn't already exist. If it exists, it should have * if it doesn't already exist; if it exists, it should
* all of the needed sub dirs that createCaseDirectory() * have been created using Case.createCaseDirectory() to
* will create. * ensure that the required sub-directories aere created.
* @param caseName the name of case * @param caseName The name of case.
* @param caseNumber the case number * @param caseNumber The case number, can be the empty string.
* @param examiner the examiner for this case * @param examiner The examiner to associate with the case, can be the
* @param caseType the type of case, single-user or multi-user * 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 { 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) { if (new File(caseDir).exists() == false) {
Case.createCaseDirectory(caseDir, caseType); Case.createCaseDirectory(caseDir, caseType);
} }
String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION; /*
* Sanitize the case name, create a unique keyword search index name,
XMLCaseManagement xmlcm = new XMLCaseManagement(); * and create a standard (single-user) or unique (multi-user) case
* database name.
*/
String santizedCaseName = sanitizeCaseName(caseName);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
Date date = new Date(); Date date = new Date();
String santizedCaseName = sanitizeCaseName(caseName);
String indexName = santizedCaseName + "_" + dateFormat.format(date); String indexName = santizedCaseName + "_" + dateFormat.format(date);
String dbName = null; String dbName = null;
// figure out the database name and index name for text extraction
if (caseType == CaseType.SINGLE_USER_CASE) { if (caseType == CaseType.SINGLE_USER_CASE) {
dbName = caseDir + File.separator + "autopsy.db"; //NON-NLS dbName = caseDir + File.separator + "autopsy.db"; //NON-NLS
} else if (caseType == CaseType.MULTI_USER_CASE) { } else if (caseType == CaseType.MULTI_USER_CASE) {
dbName = indexName; 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(); xmlcm.writeFile();
/*
* Create the case database.
*/
SleuthkitCase db = null; SleuthkitCase db = null;
try { try {
if (caseType == CaseType.SINGLE_USER_CASE) { if (caseType == CaseType.SINGLE_USER_CASE) {
@ -463,24 +488,23 @@ public class Case implements SleuthkitCase.ErrorObserver {
db = SleuthkitCase.newCase(dbName, UserPreferences.getDatabaseConnectionInfo(), caseDir); db = SleuthkitCase.newCase(dbName, UserPreferences.getDatabaseConnectionInfo(), caseDir);
} }
} catch (TskCoreException ex) { } 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(() -> { SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 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 throw new CaseActionException(ex.getMessage(), ex); //NON-NLS
} catch (UserPreferencesException ex) { } catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}); });
throw new CaseActionException( throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
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); Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType);
changeCase(newCase); changeCase(newCase);
} }
@ -549,20 +573,28 @@ public class Case implements SleuthkitCase.ErrorObserver {
/** /**
* Opens an existing case. * Opens an existing case.
* *
* @param caseMetadataFilePath The path of the case metadata file for the * @param caseMetadataFilePath The path of the case metadata file.
* case to be opened.
* *
* @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 { 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)) { if (!caseMetadataFilePath.endsWith(CASE_DOT_EXTENSION)) {
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.checkFile.msg", 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 { 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)); CaseMetadata metadata = new CaseMetadata(Paths.get(caseMetadataFilePath));
String caseName = metadata.getCaseName(); String caseName = metadata.getCaseName();
@ -571,7 +603,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
CaseType caseType = metadata.getCaseType(); CaseType caseType = metadata.getCaseType();
String caseDir = metadata.getCaseDirectory(); String caseDir = metadata.getCaseDirectory();
/** /*
* Open the case database. * Open the case database.
*/ */
SleuthkitCase db; SleuthkitCase db;
@ -585,40 +617,57 @@ public class Case implements SleuthkitCase.ErrorObserver {
try { try {
db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir); db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir);
} catch (UserPreferencesException ex) { } 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); 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 (RuntimeProperties.coreComponentsAreActive()) {
/** /*
* If the case database was upgraded for a new schema, notify * If the case database was upgraded for a new schema, notify
* the user. * the user.
*/ */
if (null != db.getBackupDatabasePath()) { if (null != db.getBackupDatabasePath()) {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(
NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg", WindowManager.getDefault().getMainWindow(),
db.getBackupDatabasePath()), NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.msg", db.getBackupDatabasePath()),
NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"), NbBundle.getMessage(Case.class, "Case.open.msgDlg.updated.title"),
JOptionPane.INFORMATION_MESSAGE); JOptionPane.INFORMATION_MESSAGE);
}); });
} }
/** /*
* TODO: This currently has no value if it there is no user to * Look for the files for the data sources listed in the case
* interact with a fid missing images dialog. * 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 * TODO (AUT-1885): Replace use of obsolete and unsafe
* constructor. TODO: Remove use of obsolete XMLCaseManagement * XMLCaseManagement class with use of CaseMetadata class.
* class.
*/ */
XMLCaseManagement xmlcm = new XMLCaseManagement(); XMLCaseManagement xmlcm = new XMLCaseManagement();
xmlcm.open(caseMetadataFilePath); xmlcm.open(caseMetadataFilePath);
@ -626,28 +675,16 @@ public class Case implements SleuthkitCase.ErrorObserver {
changeCase(openedCase); changeCase(openedCase);
} catch (CaseMetadataException ex) { } catch (CaseMetadataException ex) {
/** throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.metaDataFileCorrupt.exception.msg"), ex); //NON-NLS
* Attempt clean up.
*/
try {
Case badCase = Case.getCurrentCase();
badCase.closeCase();
} catch (IllegalStateException ignored) {
}
throw new CaseActionException(ex.getMessage(), ex); //NON-NLS
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
/**
* Attempt clean up.
*/
try {
Case badCase = Case.getCurrentCase();
badCase.closeCase();
} catch (IllegalStateException ignored) {
}
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 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; 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. * Adds the image to the current case after it has been added to the DB.
* Sends out event and reopens windows if needed. * Sends out event and reopens windows if needed.
@ -1585,10 +1593,10 @@ public class Case implements SleuthkitCase.ErrorObserver {
if (RuntimeProperties.coreComponentsAreActive()) { if (RuntimeProperties.coreComponentsAreActive()) {
// enable these menus // enable these menus
CallableSystemAction.get(AddImageAction.class).setEnabled(true); CallableSystemAction.get(AddImageAction.class).setEnabled(true);
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu
if (toChangeTo.hasData()) { if (toChangeTo.hasData()) {
// open all top components // open all top components

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

View File

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

View File

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

View File

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