Fix assorted Case action bugs

This commit is contained in:
Richard Cordovano 2017-05-02 15:22:32 -04:00
parent a4d2196484
commit ee43f71137
25 changed files with 1253 additions and 1210 deletions

View File

@ -96,10 +96,10 @@ Case.databaseConnectionInfo.error.msg=Error accessing database server connection
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.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=One of the images associated with \n\
this case are missing. Would you like to search for them now?\n\
Previously, the image was located at\:\n\
{1}\n\
{0}\n\
Please note that you will still be able to browse directories and generate reports\n\
if you choose No, but you will not be able to view file content or run the ingest process.
Case.checkImgExist.confDlg.doesntExist.title=Missing Image
@ -136,12 +136,6 @@ IntervalErrorReport.NewIssues=new issue(s)
IntervalErrorReport.TotalIssues=total issue(s)
IntervalErrorReport.ErrorText=Database Connection Error
CasePropertiesAction.window.title=Case Properties
CasePropertiesForm.updateCaseName.msgDlg.empty.msg=The caseName cannot be empty.
CasePropertiesForm.updateCaseName.msgDlg.empty.title=Error
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg=The Case Name cannot contain any of this following symbol\: \\ / \: * ? " < > |
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title=Error
CasePropertiesForm.updateCaseName.confMsg.msg=Are you sure you want to update the case name from "{0}" to "{1}"?
CasePropertiesForm.updateCaseName.confMsg.title=Change Case Name
CueBannerPanel.title.text=Open Recent Case
GeneralFilter.rawImageDesc.text=Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)
GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)

View File

@ -73,10 +73,6 @@ Case.getCurCase.exception.noneOpen=\u4f5c\u696d\u4e2d\u306e\u30b1\u30fc\u30b9\u3
Case.open.msgDlg.updated.msg=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30b9\u30ad\u30fc\u30de\u3092\u66f4\u65b0\u3057\u307e\u3057\u305f\u3002\n\u6b21\u306e\u30d1\u30b9\u3092\u6301\u3064\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u30b3\u30d4\u30fc\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f\uff1a\n\
{0}
Case.open.msgDlg.updated.title=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30b9\u30ad\u30fc\u30de\u3092\u66f4\u65b0
Case.checkImgExist.confDlg.doesntExist.msg={0} \u304c\u3053\u306e\u30b1\u30fc\u30b9\u306b\u95a2\u9023\u3059\u308b\u30a4\u30e1\u30fc\u30b8\u306e\u3046\u3061\uff11\u3064\u304c\u6b20\u843d\u3057\u3066\u3044\u308b\u306e\u3092\u691c\u51fa\u3057\u307e\u3057\u305f\u3002\u305d\u308c\u3092\u4eca\u304b\u3089\u691c\u7d22\u3057\u307e\u3059\u304b\uff1f\n\n\
\u4ee5\u524d\u3001\u30a4\u30e1\u30fc\u30b8\u306f\u6b21\u306b\u3042\u308a\u307e\u3057\u305f\uff1a\n\
{1}\n\
\u3044\u3044\u3048\u3092\u9078\u629e\u3057\u3066\u3082\u3001\u4eca\u5f8c\u3082\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u95b2\u89a7\u3057\u3001\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u304c\u3067\u304d\u307e\u3059\u304c\u3001\n\u30d5\u30a1\u30a4\u30eb\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u8868\u793a\u307e\u305f\u306f\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30d7\u30ed\u30bb\u30b9\u306e\u5b9f\u884c\u304c\u3067\u304d\u306a\u304f\u306a\u308a\u307e\u3059\u3002
Case.checkImgExist.confDlg.doesntExist.title=\u6b20\u843d\u3057\u3066\u3044\u308b\u30a4\u30e1\u30fc\u30b8
Case.addImg.exception.msg=\u30b1\u30fc\u30b9\u306b\u30a4\u30e1\u30fc\u30b8\u3092\u8ffd\u52a0\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
Case.updateCaseName.exception.msg=\u30b1\u30fc\u30b9\u540d\u3092\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
@ -99,10 +95,6 @@ CaseDeleteAction.msgDlg.caseDelete.msg=\u30b1\u30fc\u30b9\u304c\u524a\u9664\u305
CaseOpenAction.autFilter.title={0} \u30b1\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb ( {1})
CaseOpenAction.msgDlg.cantOpenCase.title=\u30b1\u30fc\u30b9\u3092\u958b\u304f\u969b\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
CasePropertiesAction.window.title=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3
CasePropertiesForm.updateCaseName.msgDlg.empty.msg=\u30b1\u30fc\u30b9\u540d\u306f\u7a7a\u767d\u3067\u306f\u3044\u3051\u307e\u305b\u3093\u3002
CasePropertiesForm.updateCaseName.msgDlg.empty.title=\u30a8\u30e9\u30fc
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg=\u30b1\u30fc\u30b9\u540d\u306b\u306f\u6b21\u306e\u8a18\u53f7\u3092\u542b\u3081\u307e\u305b\u3093\uff1a\\ / \: * ? " < > |
CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title=\u30a8\u30e9\u30fc
CueBannerPanel.title.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f
GeneralFilter.rawImageDesc.text=\u30ed\u30fc\u30a4\u30e1\u30fc\u30b8(*.img, *.dd, *.001, *.aa, *.raw, *.bin)
GeneralFilter.encaseImageDesc.text=\u30a8\u30f3\u30b1\u30fc\u30b9\u30a4\u30e1\u30fc\u30b8(*.e01)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
/**
* Exception thrown when a case action (e.g., create, open, close, delete) is
* cancelled before it is completed.
*/
class CaseActionCancelledException extends CaseActionException {
private static final long serialVersionUID = 1L;
/**
* Constructs an exception thrown when a case action (e.g., create, open,
* close, delete) is cancelled before it is completed.
*
* @param message An error message.
*/
CaseActionCancelledException(String message) {
super(message);
}
/**
* Constructs an exception thrown when a case action (e.g., create, open,
* close, delete) is cancelled before it is completed.
*
* @param message An error message.
* @param cause An excception that caused this exception to be thrown.
*/
CaseActionCancelledException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,15 +19,30 @@
package org.sleuthkit.autopsy.casemodule;
/**
* Exception thrown when case action (such as open, close, create) resulted in
* an error
* Exception thrown when a case action (e.g., create, open, close, delete)
* experiences an error condition.
*/
public class CaseActionException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Constructs an exception thrown when a case action (e.g., create, open,
* close, delete) experiences an error condition.
*
* @param message An error message.
*/
public CaseActionException(String message) {
super(message);
}
/**
* Constructs an exception thrown when a case action (e.g., create, open,
* close, delete) experiences an error condition.
*
* @param message An error message.
* @param cause An excception that caused this exception to be thrown.
*/
public CaseActionException(String message, Throwable cause) {
super(message, cause);
}

View File

@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,10 +19,6 @@
package org.sleuthkit.autopsy.casemodule;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.event.ChangeEvent;
import org.openide.util.NbBundle.Messages;
@ -32,44 +28,40 @@ import org.openide.util.NbBundle.Messages;
*/
class CaseInformationPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(CaseInformationPanel.class.getName());
private static final long serialVersionUID = 1L;
/**
* Creates new form CaseInformationPanel
* Constructs a panel for displaying the case information, including both
* case details and ingest job history.
*/
CaseInformationPanel() {
initComponents();
customizeComponents();
}
@Messages({"CaseInformationPanel.caseDetails.header=Case Details",
"CaseInformationPanel.ingestJobInfo.header=Ingest History",
"CaseInformationPanel.loadMetadataFail.message=Failed to load case metadata.",
"CaseInformationPanel.loadMetadataFail.title=Metadata load failure",})
@Messages({
"CaseInformationPanel.caseDetails.header=Case Details",
"CaseInformationPanel.ingestJobInfo.header=Ingest History"
})
private void customizeComponents() {
try {
Case currentCase = Case.getCurrentCase();
String crDate = currentCase.getCreatedDate();
String caseDir = currentCase.getCaseDirectory();
// put the image paths information into hashmap
Map<Long, String> imgPaths = Case.getImagePaths(currentCase.getSleuthkitCase());
CasePropertiesPanel cpf = new CasePropertiesPanel(currentCase, crDate, caseDir, imgPaths);
cpf.setSize(cpf.getPreferredSize());
this.tabbedPane.addTab(Bundle.CaseInformationPanel_caseDetails_header(), cpf);
this.tabbedPane.addTab(Bundle.CaseInformationPanel_ingestJobInfo_header(), new IngestJobInfoPanel());
this.tabbedPane.addChangeListener((ChangeEvent e) -> {
tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize());
});
} catch (CaseMetadata.CaseMetadataException ex) {
logger.log(Level.SEVERE, "Failed to load case metadata.", ex);
JOptionPane.showMessageDialog(null, Bundle.IngestJobInfoPanel_loadIngestJob_error_text(), Bundle.IngestJobInfoPanel_loadIngestJob_error_title(), JOptionPane.ERROR_MESSAGE);
}
CasePropertiesPanel propertiesPanel = new CasePropertiesPanel(Case.getCurrentCase());
propertiesPanel.setSize(propertiesPanel.getPreferredSize());
this.tabbedPane.addTab(Bundle.CaseInformationPanel_caseDetails_header(), propertiesPanel);
this.tabbedPane.addTab(Bundle.CaseInformationPanel_ingestJobInfo_header(), new IngestJobInfoPanel());
this.tabbedPane.addChangeListener((ChangeEvent e) -> {
tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize());
});
}
/**
* Adds an action listener to the Close button of the panel.
*
* @param action
*/
void addCloseButtonAction(ActionListener action) {
this.closeButton.addActionListener(action);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -127,7 +119,7 @@ class CaseInformationPanel extends javax.swing.JPanel {
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
// TODO add your handling code here:
// Used by CasePropertiesAction
}//GEN-LAST:event_closeButtonActionPerformed

View File

@ -54,7 +54,9 @@ public final class CaseMetadata {
private static final String FILE_EXTENSION = ".aut";
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)");
//fields from schema version 1
/*
* Fields from schema version 1
*/
private static final String SCHEMA_VERSION_ONE = "1.0";
private final static String ROOT_ELEMENT_NAME = "AutopsyCase"; //NON-NLS
private final static String SCHEMA_VERSION_ELEMENT_NAME = "SchemaVersion"; //NON-NLS
@ -68,22 +70,28 @@ public final class CaseMetadata {
private final static String CASE_DATABASE_NAME_ELEMENT_NAME = "DatabaseName"; //NON-NLS
private final static String TEXT_INDEX_NAME_ELEMENT = "TextIndexName"; //NON-NLS
//fields from schema version 2
/*
* Fields from schema version 2
*/
private static final String SCHEMA_VERSION_TWO = "2.0";
private final static String AUTOPSY_CREATED_BY_ELEMENT_NAME = "CreatedByAutopsyVersion"; //NON-NLS
private final static String CASE_DATABASE_ABSOLUTE_PATH_ELEMENT_NAME = "Database"; //NON-NLS
private final static String CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME = "Database"; //NON-NLS
private final static String TEXT_INDEX_ELEMENT = "TextIndex"; //NON-NLS
//fields from schema version 3
/*
* Fields from schema version 3
*/
private static final String SCHEMA_VERSION_THREE = "3.0";
private final static String CASE_DISPLAY_NAME_ELEMENT_NAME = "DisplayName"; //NON-NLS
private final static String CASE_DATABASE_NAME_RELATIVE_ELEMENT_NAME = "CaseDatabase"; //NON-NLS
private final static String CASE_DB_NAME_RELATIVE_ELEMENT_NAME = "CaseDatabase"; //NON-NLS
//unread fields, these are regenerated on save
/*
* Unread fields, regenerated on save.
*/
private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS
private final static String AUTOPSY_SAVED_BY_ELEMENT_NAME = "SavedByAutopsyVersion"; //NON-NLS
private static final String CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_THREE;
private final static String CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_THREE;
private final Path metadataFilePath;
private Case.CaseType caseType;
@ -92,8 +100,8 @@ public final class CaseMetadata {
private String caseNumber;
private String examiner;
private String caseDatabaseName;
private String caseDatabasePath;
private String textIndexName;
private String caseDatabasePath; // Legacy
private String textIndexName; // Legacy
private String createdDate;
private String createdByVersion;
@ -107,8 +115,9 @@ public final class CaseMetadata {
}
/**
* Constructs an object that provides access to the case metadata stored in
* a new case metadata file that is created using the supplied metadata.
* Constructs a CaseMetadata object for a new case. The metadata is not
* persisted to the case metadata file until writeFile or a setX method is
* called.
*
* @param caseDirectory The case directory.
* @param caseType The type of case.
@ -117,29 +126,24 @@ public final class CaseMetadata {
* user.
* @param caseNumber The case number.
* @param examiner The name of the case examiner.
* @param caseDatabase For a single-user case, the full path to the case
* database file. For a multi-user case, the case
* database name.
*
* @throws CaseMetadataException If the new case metadata file cannot be
* created.
*/
CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseDisplayName, String caseNumber, String examiner, String caseDatabase) throws CaseMetadataException {
CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseDisplayName, String caseNumber, String examiner) {
metadataFilePath = Paths.get(caseDirectory, caseDisplayName + FILE_EXTENSION);
this.caseType = caseType;
this.caseName = caseName;
this.caseDisplayName = caseDisplayName;
this.caseNumber = caseNumber;
this.examiner = examiner;
this.caseDatabaseName = caseDatabase;
caseDatabaseName = "";
caseDatabasePath = "";
textIndexName = "";
createdByVersion = Version.getVersion();
createdDate = CaseMetadata.DATE_FORMAT.format(new Date());
writeToFile();
}
/**
* Constructs an object that provides access to the case metadata stored in
* an existing case metadata file.
* Constructs a CaseMetadata object for an existing case. The metadata is
* read from an existing case metadata file.
*
* @param metadataFilePath The full path to the case metadata file.
*
@ -179,7 +183,7 @@ public final class CaseMetadata {
}
/**
* Gets the immutable case name, set at case creation.
* Gets the unique and immutable case name.
*
* @return The case display name.
*/
@ -193,22 +197,23 @@ public final class CaseMetadata {
* @return The case display name.
*/
public String getCaseDisplayName() {
return this.caseDisplayName;
return caseDisplayName;
}
/**
* Sets the case display name. This does not change the name of the case
* directory, the case database, or the text index name.
* Sets the case display name.
*
* @param caseName A case display name.
* @param caseDisplayName A case display name.
*
* @throws CaseMetadataException If the operation fails.
*/
void setCaseDisplayName(String caseName) throws CaseMetadataException {
String oldCaseName = caseName;
this.caseDisplayName = caseName;
void setCaseDisplayName(String caseDisplayName) throws CaseMetadataException {
String oldCaseDisplayName = this.caseDisplayName;
this.caseDisplayName = caseDisplayName;
try {
writeToFile();
} catch (CaseMetadataException ex) {
this.caseDisplayName = oldCaseName;
this.caseDisplayName = oldCaseDisplayName;
throw ex;
}
}
@ -234,32 +239,35 @@ public final class CaseMetadata {
/**
* Gets the name of the case database.
*
* @return The case database name.
* @return The case database name, may be empty.
*/
public String getCaseDatabaseName() {
return caseDatabaseName;
}
/**
* Sets the text index name.
* Sets the name of the case database.
*
* @param caseTextIndexName The text index name.
* @param caseDatabaseName The case database name.
*
* @throws CaseMetadataException If the operation fails.
*/
void setTextIndexName(String caseTextIndexName) throws CaseMetadataException {
String oldIndexName = caseTextIndexName;
this.textIndexName = caseTextIndexName;
void setCaseDatabaseName(String caseDatabaseName) throws CaseMetadataException {
String oldCaseDatabaseName = this.caseDatabaseName;
this.caseDatabaseName = caseDatabaseName;
try {
writeToFile();
} catch (CaseMetadataException ex) {
this.textIndexName = oldIndexName;
this.caseDatabaseName = oldCaseDatabaseName;
throw ex;
}
}
/**
* Gets the text index name.
* Gets the text index name. This is a legacy field and will be empty for
* cases created with Autopsy 4.4.0 and above.
*
* @return The name of the text index for the case.
* @return The name of the text index for the case, may be empty.
*/
public String getTextIndexName() {
return textIndexName;
@ -268,7 +276,7 @@ public final class CaseMetadata {
/**
* Gets the date the case was created.
*
* @return The date this case was created as a string
* @return The date this case was created, as a string.
*/
String getCreatedDate() {
return createdDate;
@ -278,7 +286,9 @@ public final class CaseMetadata {
* Sets the date the case was created. Used for preserving the case creation
* date during single-user to multi-user case conversion.
*
* @param createdDate The date the case was created as a string.
* @param createdDate The date the case was created, as a string.
*
* @throws CaseMetadataException If the operation fails.
*/
void setCreatedDate(String createdDate) throws CaseMetadataException {
String oldCreatedDate = createdDate;
@ -304,13 +314,15 @@ public final class CaseMetadata {
* Sets the Autopsy version that created the case. Used for preserving this
* metadata during single-user to multi-user case conversion.
*
* @param buildVersion An build version identifier.
* @param buildVersion A build version identifier.
*
* @throws CaseMetadataException If the operation fails.
*/
void setCreatedByVersion(String buildVersion) throws CaseMetadataException {
String oldCreatedByVersion = this.createdByVersion;
this.createdByVersion = buildVersion;
try {
this.writeToFile();
writeToFile();
} catch (CaseMetadataException ex) {
this.createdByVersion = oldCreatedByVersion;
throw ex;
@ -381,8 +393,8 @@ public final class CaseMetadata {
createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, caseNumber);
createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, examiner);
createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, caseType.toString());
createChildElement(doc, caseElement, CASE_DATABASE_ABSOLUTE_PATH_ELEMENT_NAME, caseDatabasePath);
createChildElement(doc, caseElement, CASE_DATABASE_NAME_RELATIVE_ELEMENT_NAME, caseDatabaseName);
createChildElement(doc, caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, caseDatabasePath);
createChildElement(doc, caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, caseDatabaseName);
createChildElement(doc, caseElement, TEXT_INDEX_ELEMENT, textIndexName);
}
@ -451,15 +463,19 @@ public final class CaseMetadata {
if (null == this.caseType) {
throw new CaseMetadataException("Case metadata file corrupted");
}
if (schemaVersion.equals(SCHEMA_VERSION_ONE)) {
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DATABASE_NAME_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true);
} else if (schemaVersion.equals(SCHEMA_VERSION_TWO)) {
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DATABASE_ABSOLUTE_PATH_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
} else {
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DATABASE_NAME_RELATIVE_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
switch (schemaVersion) {
case SCHEMA_VERSION_ONE:
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DATABASE_NAME_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true);
break;
case SCHEMA_VERSION_TWO:
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
break;
default:
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
break;
}
/*
@ -489,7 +505,7 @@ public final class CaseMetadata {
* @param elementName The element name.
* @param contentIsRequired Whether or not the content is required.
*
* @return The text content, may be empty if not required.
* @return The text content, may be empty If not required.
*
* @throws CaseMetadataException If the element is missing or content is
* required and it is empty.
@ -530,7 +546,7 @@ public final class CaseMetadata {
* @return The full path to the case database file for a single-user case.
*
* @throws UnsupportedOperationException If called for a multi-user case.
* @deprecated
* @deprecated Do not use.
*/
@Deprecated
public String getCaseDatabasePath() throws UnsupportedOperationException {

View File

@ -125,13 +125,15 @@ public final class CaseOpenAction extends CallableSystemAction implements Action
JOptionPane.ERROR_MESSAGE);
StartupWindowProvider.getInstance().open();
} catch (ExecutionException ex) {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", path), ex); //NON-NLS
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getCause().getMessage(), //get the message of the wrapped exception
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", path), ex); //NON-NLS
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getCause().getMessage(), //get the message of the wrapped exception
NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
}
StartupWindowProvider.getInstance().open();
}
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

View File

@ -22,7 +22,6 @@ import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Action;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;
@ -43,11 +42,11 @@ final class CasePropertiesAction extends CallableSystemAction {
CasePropertiesAction() {
putValue(Action.NAME, NbBundle.getMessage(CasePropertiesAction.class, "CTL_CasePropertiesAction"));
this.setEnabled(false);
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
setEnabled(null != evt.getNewValue());
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), (PropertyChangeEvent evt) -> {
if (null == evt.getNewValue()) {
casePropertiesDialog = null;
}
setEnabled(null != evt.getNewValue());
});
}

View File

@ -16,63 +16,57 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import java.nio.file.Paths;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/**
* A panel that allows the user to view various properties of the current case
* and change the display name of the case.
* A panel that allows the user to view various properties of a case and change
* the display name of the case.
*/
class CasePropertiesPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private Case current = null;
private static JPanel caller; // panel for error
private static final Logger LOGGER = Logger.getLogger(CasePropertiesPanel.class.getName());
private final Case theCase;
CasePropertiesPanel(Case currentCase, String crDate, String caseDir, Map<Long, String> imgPaths) throws CaseMetadata.CaseMetadataException {
/**
* Constructs a panel that allows the user to view various properties of the
* current case and change the display name of the case.
*
* @param aCase A case.
*/
CasePropertiesPanel(Case aCase) {
initComponents();
caseNameTextField.setText(currentCase.getDisplayName());
String caseNumber = currentCase.getNumber();
theCase = aCase;
caseNameTextField.setText(theCase.getDisplayName());
String caseNumber = theCase.getNumber();
if (!caseNumber.isEmpty()) {
caseNumberField.setText(caseNumber);
} else {
caseNumberField.setText("N/A");
}
String examiner = currentCase.getExaminer();
String examiner = theCase.getExaminer();
if (!examiner.isEmpty()) {
examinerField.setText(examiner);
} else {
examinerField.setText("N/A");
}
crDateField.setText(crDate);
caseDirField.setText(caseDir);
current = currentCase;
CaseMetadata caseMetadata = currentCase.getCaseMetadata();
if (caseMetadata.getCaseType() == Case.CaseType.SINGLE_USER_CASE) {
dbNameField.setText(Paths.get(caseMetadata.getCaseDirectory(), caseMetadata.getCaseDatabaseName()).toString());
crDateField.setText(theCase.getCreatedDate());
caseDirField.setText(theCase.getCaseDirectory());
if (Case.CaseType.SINGLE_USER_CASE == theCase.getCaseType()) {
dbNameField.setText(Paths.get(theCase.getCaseDirectory(), theCase.getMetadata().getCaseDatabaseName()).toString());
} else {
dbNameField.setText(caseMetadata.getCaseDatabaseName());
}
Case.CaseType caseType = caseMetadata.getCaseType();
caseTypeField.setText(caseType.getLocalizedDisplayName());
if (caseType == Case.CaseType.SINGLE_USER_CASE) {
deleteCaseButton.setEnabled(true);
} else {
deleteCaseButton.setEnabled(false);
dbNameField.setText(theCase.getMetadata().getCaseDatabaseName());
}
Case.CaseType caseType = theCase.getCaseType();
caseTypeField.setText(caseType.getLocalizedDisplayName());
deleteCaseButton.setEnabled(Case.CaseType.SINGLE_USER_CASE == caseType);
}
/**
@ -259,59 +253,35 @@ class CasePropertiesPanel extends javax.swing.JPanel {
}// </editor-fold>//GEN-END:initComponents
/**
* Updates the case name.
* Updates the case display name.
*
* @param evt The action event
*/
@NbBundle.Messages({
"CasePropertiesPanel.errorDialog.emptyCaseNameMessage=No case name entered.",
"CasePropertiesPanel.errorDialog.invalidCaseNameMessage=Case names cannot include the following symbols: \\, /, :, *, ?, \", <, >, |"
})
private void updateCaseNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateCaseNameButtonActionPerformed
String oldCaseName = Case.getCurrentCase().getDisplayName();
String newCaseName = caseNameTextField.getText();
// check if the old and new case name is not equal
if (!oldCaseName.equals(newCaseName)) {
String newCaseDisplayName = caseNameTextField.getText();
if (newCaseDisplayName.equals(theCase.getDisplayName())) {
return;
}
// check if the case name is empty
if (newCaseName.trim().isEmpty()) {
JOptionPane.showMessageDialog(caller,
NbBundle.getMessage(this.getClass(),
"CasePropertiesForm.updateCaseName.msgDlg.empty.msg"),
NbBundle.getMessage(this.getClass(),
"CasePropertiesForm.updateCaseName.msgDlg.empty.title"),
JOptionPane.ERROR_MESSAGE);
} else // check if case Name contain one of this following symbol:
// \ / : * ? " < > |
{
if (newCaseName.contains("\\") || newCaseName.contains("/") || newCaseName.contains(":")
|| newCaseName.contains("*") || newCaseName.contains("?") || newCaseName.contains("\"")
|| newCaseName.contains("<") || newCaseName.contains(">") || newCaseName.contains("|")) {
String errorMsg = NbBundle
.getMessage(this.getClass(), "CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.msg");
JOptionPane.showMessageDialog(caller, errorMsg,
NbBundle.getMessage(this.getClass(),
"CasePropertiesForm.updateCaseName.msgDlg.invalidSymbols.title"),
JOptionPane.ERROR_MESSAGE);
} else {
// ask for the confirmation first
String confMsg = NbBundle
.getMessage(this.getClass(), "CasePropertiesForm.updateCaseName.confMsg.msg", oldCaseName,
newCaseName);
NotifyDescriptor d = new NotifyDescriptor.Confirmation(confMsg,
NbBundle.getMessage(this.getClass(),
"CasePropertiesForm.updateCaseName.confMsg.title"),
NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE);
d.setValue(NotifyDescriptor.NO_OPTION);
if (newCaseDisplayName.trim().isEmpty()) {
MessageNotifyUtil.Message.error(Bundle.CasePropertiesPanel_errorDialog_emptyCaseNameMessage());
return;
}
Object res = DialogDisplayer.getDefault().notify(d);
if (res != null && res == DialogDescriptor.YES_OPTION) {
// if user select "Yes"
String oldPath = current.getCaseMetadata().getFilePath().toString();
try {
current.updateCaseName(oldCaseName, oldPath, newCaseName, oldPath);
} catch (CaseActionException ex) {
Logger.getLogger(CasePropertiesPanel.class.getName()).log(Level.WARNING, "Error: problem updating case name.", ex); //NON-NLS
}
}
}
}
if (!Case.isValidName(newCaseDisplayName)) {
MessageNotifyUtil.Message.error(Bundle.CasePropertiesPanel_errorDialog_invalidCaseNameMessage());
return;
}
try {
theCase.updateDisplayName(newCaseDisplayName);
} catch (CaseActionException ex) {
MessageNotifyUtil.Message.error(ex.getLocalizedMessage());
LOGGER.log(Level.SEVERE, "Failed to update case display name", ex); //NON-NLS
}
}//GEN-LAST:event_updateCaseNameButtonActionPerformed

View File

@ -94,15 +94,17 @@ final class NewCaseWizardAction extends CallableSystemAction {
AddImageAction addImageAction = SystemAction.get(AddImageAction.class);
addImageAction.actionPerformed(null);
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, String.format("Error creating case %s", wizardDescriptor.getProperty("caseName")), ex); //NON-NLS
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);
if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) {
logger.log(Level.SEVERE, String.format("Error creating case %s", wizardDescriptor.getProperty("caseName")), ex); //NON-NLS
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);
}
doFailedCaseCleanup(wizardDescriptor);
StartupWindowProvider.getInstance().close();
StartupWindowProvider.getInstance().open();
doFailedCaseCleanup(wizardDescriptor);
} finally {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}

View File

@ -38,29 +38,21 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
/**
* The "New Case" wizard panel with a component on it. This class represents
* data of wizard step. It defers creation and initialization of UI component of
* wizard panel into getComponent() method.
* The first panel of the New Case wizard.
*/
class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDescriptor> {
/**
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
*/
private NewCaseVisualPanel1 component;
private Boolean isFinish = false;
private static String createdDirectory;
private static final String PROP_BASECASE = "LBL_BaseCase_PATH"; //NON-NLS
private static final Logger logger = Logger.getLogger(NewCaseWizardPanel1.class.getName());
private static final String PROP_BASECASE = "LBL_BaseCase_PATH"; //NON-NLS
private static String createdDirectory;
private final Set<ChangeListener> listeners = new HashSet<>(1);
private NewCaseVisualPanel1 component;
private boolean isFinish;
/**
* 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.
* Get the visual component for the panel.
*
* @return component the UI component of this wizard panel
* @return The UI component of this wizard panel
*/
@Override
public NewCaseVisualPanel1 getComponent() {
@ -71,65 +63,57 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
}
/**
* Help for this panel. When the panel is active, this is used as the help
* for the wizard dialog.
* Gets the help object for this panel. When the panel is active, this is
* used as the help for the wizard dialog.
*
* @return HelpCtx.DEFAULT_HELP the help for this panel
* @return The help for this panel.
*/
@Override
public HelpCtx getHelp() {
// Show no Help button for this panel:
/*
* Currently, no help is provided for this panel.
*/
return HelpCtx.DEFAULT_HELP;
// If you have context help:
// return new HelpCtx(SampleWizardPanel1.class);
}
/**
* Tests whether the panel is finished. If the panel is valid, the "Finish"
* button will be enabled.
*
* @return boolean true if all the fields are correctly filled, false
* otherwise
* @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 isFinish;
// If it depends on some condition (form filled out...), then:
// return someCondition();
// and when this condition changes (last form field filled in...) then:
// fireChangeEvent();
// and uncomment the complicated stuff below.
}
private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
/**
* Adds a listener to changes of the panel's validity.
* Adds a change listener to this panel.
*
* @param l the change listener to add
* @param listener The change listener to add.
*/
@Override
public final void addChangeListener(ChangeListener l) {
public final void addChangeListener(ChangeListener listener) {
synchronized (listeners) {
listeners.add(l);
listeners.add(listener);
}
}
/**
* Removes a listener to changes of the panel's validity.
* Removes a change listener from this panel.
*
* @param l the change listener to move
* @param listener The change listener to remove.
*/
@Override
public final void removeChangeListener(ChangeListener l) {
public final void removeChangeListener(ChangeListener listener) {
synchronized (listeners) {
listeners.remove(l);
listeners.remove(listener);
}
}
/**
* This method is auto-generated. It seems that this method is used to
* listen to any change in this wizard panel.
* Notifies any registerd change listeners of a change in the panel.
*/
protected final void fireChangeEvent() {
Iterator<ChangeListener> it;
@ -153,12 +137,8 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
fireChangeEvent();
}
// 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
* 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.
@ -322,4 +302,5 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -28,35 +28,19 @@ import org.openide.WizardValidationException;
import org.openide.util.HelpCtx;
import org.openide.windows.WindowManager;
import java.awt.Cursor;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
/**
* The "New Case" wizard panel with a component on it. This class represents
* data of wizard step. It defers creation and initialization of UI component of
* wizard panel into getComponent() method.
*
* @author jantonius
* The second panel of the New Case wizard.
*/
class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDescriptor> {
/**
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
*/
private NewCaseVisualPanel2 component;
private Boolean isFinish = true;
private String caseName;
private String caseDir;
private String createdDirectory;
private CaseType caseType;
private final Set<ChangeListener> listeners = new HashSet<>(1);
/**
* 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.
* Get the visual component for the panel.
*
* @return component the UI component of this wizard panel
* @return component The UI component of this wizard panel.
*/
@Override
public NewCaseVisualPanel2 getComponent() {
@ -67,17 +51,17 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
}
/**
* Help for this panel. When the panel is active, this is used as the help
* for the wizard dialog.
* Gets the help object for this panel. When the panel is active, this is
* used as the help for the wizard dialog.
*
* @return HelpCtx.DEFAULT_HELP the help for this panel
* @return The help for this panel.
*/
@Override
public HelpCtx getHelp() {
// Show no Help button for this panel:
/*
* Currently, no help is provided for this panel.
*/
return HelpCtx.DEFAULT_HELP;
// If you have context help:
// return new HelpCtx(SampleWizardPanel1.class);
}
/**
@ -89,43 +73,35 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
*/
@Override
public boolean isValid() {
// If it is always OK to press Next or Finish, then:
return isFinish;
// If it depends on some condition (form filled out...), then:
// return someCondition();
// and when this condition changes (last form field filled in...) then:
// fireChangeEvent();
// and uncomment the complicated stuff below.
return true;
}
private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(1); // or can use ChangeSupport in NB 6.0
/**
* Adds a listener to changes of the panel's validity.
* Adds a change listener to this panel.
*
* @param l the change listener to add
* @param listener The change listener to add.
*/
@Override
public final void addChangeListener(ChangeListener l) {
public final void addChangeListener(ChangeListener listener) {
synchronized (listeners) {
listeners.add(l);
listeners.add(listener);
}
}
/**
* Removes a listener to changes of the panel's validity.
* Removes a change listener from this panel.
*
* @param l the change listener to move
* @param listener The change listener to remove.
*/
@Override
public final void removeChangeListener(ChangeListener l) {
public final void removeChangeListener(ChangeListener listener) {
synchronized (listeners) {
listeners.remove(l);
listeners.remove(listener);
}
}
/**
* This method is auto-generated. It seems that this method is used to
* listen to any change in this wizard panel.
* Notifies any registerd change listeners of a change in the panel.
*/
protected final void fireChangeEvent() {
Iterator<ChangeListener> it;
@ -138,10 +114,6 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
}
}
// 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
@ -152,10 +124,6 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
*/
@Override
public void readSettings(WizardDescriptor settings) {
caseName = (String) settings.getProperty("caseName"); //NON-NLS
caseDir = (String) settings.getProperty("caseParentDir"); //NON-NLS
createdDirectory = (String) settings.getProperty("createdDirectory"); //NON-NLS
caseType = CaseType.values()[(int) settings.getProperty("caseType")]; //NON-NLS
}
/**

View File

@ -125,13 +125,15 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
try {
Case.openAsCurrentCase(casePath);
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", casePath), ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
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 (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", casePath), ex); //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);
}
StartupWindowProvider.getInstance().open();
});
}

View File

@ -407,9 +407,11 @@ final class RecentCases extends CallableSystemAction implements Presenter.Menu {
String[] casePaths = new String[LENGTH];
String currentCasePath = null;
try {
currentCasePath = Case.getCurrentCase().getCaseMetadata().getFilePath().toString();
currentCasePath = Case.getCurrentCase().getMetadata().getFilePath().toString();
} catch (IllegalStateException ex) {
// in case there is no current case.
/*
* There may be no current case.
*/
}
Iterator<RecentCase> mostRecentFirst = recentCases.descendingIterator();

View File

@ -65,17 +65,20 @@ class RecentItems implements ActionListener {
try {
Case.openAsCurrentCase(caseMetaDataFilePath);
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetaDataFilePath), ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getMessage(),
NbBundle.getMessage(RecentItems.this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) {
logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetaDataFilePath), ex); //NON-NLS
JOptionPane.showMessageDialog(
WindowManager.getDefault().getMainWindow(),
ex.getMessage(),
NbBundle.getMessage(RecentItems.this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), //NON-NLS
JOptionPane.ERROR_MESSAGE);
}
StartupWindowProvider.getInstance().open();
});
}
}).start();
}).
start();
}
}
}

View File

@ -204,8 +204,8 @@ public class SingleUserCaseConverter {
icd.getNewCaseName(),
icd.getNewCaseName(),
oldCaseMetadata.getCaseNumber(),
oldCaseMetadata.getExaminer(),
dbName);
oldCaseMetadata.getExaminer());
newCaseMetadata.setCaseDatabaseName(dbName);
// Set created date. This calls writefile, no need to call it again
newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate());
newCaseMetadata.setCreatedByVersion(oldCaseMetadata.getCreatedByVersion());

View File

@ -59,7 +59,7 @@ public final class LoggingProgressIndicator implements ProgressIndicator {
@Override
public void progress(int workUnitsCompleted) {
LOGGER.log(Level.INFO, "{1} of {2} total work units completed", new Object[]{workUnitsCompleted, this.totalWorkUnits});
LOGGER.log(Level.INFO, "{0} of {1} total work units completed", new Object[]{workUnitsCompleted, this.totalWorkUnits});
}
@Override
@ -68,8 +68,8 @@ public final class LoggingProgressIndicator implements ProgressIndicator {
}
@Override
public void finish(String message) {
LOGGER.log(Level.INFO, "{0} finished", message);
public void finish() {
LOGGER.log(Level.INFO, "Finished");
}
}

View File

@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.framework;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.event.ActionListener;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;
import org.openide.DialogDescriptor;
@ -30,14 +32,17 @@ import org.openide.util.HelpCtx;
/**
* A progress indicator that displays progress using a modal dialog with a
* message label, a progress bar, and optionally, a configurable set of buttons
* with a button listener.
* with a button listener. Setting a cancelling flag which locks in a cancelling
* message and an indeterminate progress bar is supported.
*/
@ThreadSafe
public final class ModalDialogProgressIndicator implements ProgressIndicator {
private final Frame parent;
private final ProgressPanel progressPanel;
private final Dialog dialog;
private final ActionListener buttonListener;
@GuardedBy("this")
private boolean cancelling;
/**
* Creates a progress indicator that displays progress using a modal dialog
@ -54,6 +59,7 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
public ModalDialogProgressIndicator(Frame parent, String title, Object[] buttonLabels, Object focusedButtonLabel, ActionListener buttonListener) {
this.parent = parent;
progressPanel = new ProgressPanel();
progressPanel.setIndeterminate(true);
DialogDescriptor dialogDescriptor = new DialogDescriptor(
progressPanel,
title,
@ -64,7 +70,6 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
HelpCtx.DEFAULT_HELP,
buttonListener);
dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
this.buttonListener = buttonListener;
}
/**
@ -77,31 +82,10 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
public ModalDialogProgressIndicator(Frame parent, String title) {
this.parent = parent;
progressPanel = new ProgressPanel();
progressPanel.setIndeterminate(true);
dialog = new JDialog(parent, title, true);
dialog.add(progressPanel);
dialog.pack();
buttonListener = null;
}
/**
* Calls setVisible on the underlying modal dialog.
*
* @param isVisible True or false.
*/
public void setVisible(boolean isVisible) {
if (isVisible) {
dialog.setLocationRelativeTo(parent);
}
this.dialog.setVisible(isVisible);
}
/**
* Gets the button listener for the dialog, if there is one.
*
* @return The button listener or null.
*/
public ActionListener getButtonListener() {
return buttonListener;
}
/**
@ -112,14 +96,14 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param totalWorkUnits The total number of work units.
*/
@Override
public void start(String message, int totalWorkUnits) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressPanel.setInderminate(false);
progressPanel.setMessage(message);
progressPanel.setMaximum(totalWorkUnits);
}
public synchronized void start(String message, int totalWorkUnits) {
cancelling = false;
SwingUtilities.invokeLater(() -> {
progressPanel.setIndeterminate(false);
progressPanel.setMessage(message);
progressPanel.setMaximum(totalWorkUnits);
dialog.setLocationRelativeTo(parent);
this.dialog.setVisible(true);
});
}
@ -130,13 +114,28 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param message The initial progress message.
*/
@Override
public void start(String message) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressPanel.setInderminate(true);
progressPanel.setMessage(message);
}
public synchronized void start(String message) {
cancelling = false;
SwingUtilities.invokeLater(() -> {
progressPanel.setIndeterminate(true);
progressPanel.setMessage(message);
dialog.setLocationRelativeTo(parent);
this.dialog.setVisible(true);
});
}
/**
* Sets a cancelling message and makes the progress bar indeterminate. Once
* cancel has been called, the progress indicator no longer accepts updates
* unless start is called again.
*
* @param cancellingMessage
*/
public synchronized void setCancelling(String cancellingMessage) {
cancelling = true;
SwingUtilities.invokeLater(() -> {
progressPanel.setIndeterminate(false);
progressPanel.setMessage(cancellingMessage);
});
}
@ -147,14 +146,13 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param message The initial progress message.
*/
@Override
public void switchToIndeterminate(String message) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressPanel.setInderminate(true);
public synchronized void switchToIndeterminate(String message) {
if (!cancelling) {
SwingUtilities.invokeLater(() -> {
progressPanel.setIndeterminate(true);
progressPanel.setMessage(message);
}
});
});
}
}
/**
@ -166,16 +164,15 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param totalWorkUnits The total number of work units to be completed.
*/
@Override
public void switchToDeterminate(String message, int workUnitsCompleted, int totalWorkUnits) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressPanel.setInderminate(false);
public synchronized void switchToDeterminate(String message, int workUnitsCompleted, int totalWorkUnits) {
if (!cancelling) {
SwingUtilities.invokeLater(() -> {
progressPanel.setIndeterminate(false);
progressPanel.setMessage(message);
progressPanel.setMaximum(totalWorkUnits);
progressPanel.setCurrent(workUnitsCompleted);
}
});
});
}
}
/**
@ -184,13 +181,12 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param message The progress message.
*/
@Override
public void progress(String message) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
public synchronized void progress(String message) {
if (!cancelling) {
SwingUtilities.invokeLater(() -> {
progressPanel.setMessage(message);
}
});
});
}
}
/**
@ -201,13 +197,12 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param workUnitsCompleted Number of work units completed so far.
*/
@Override
public void progress(int workUnitsCompleted) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
public synchronized void progress(int workUnitsCompleted) {
if (!cancelling) {
SwingUtilities.invokeLater(() -> {
progressPanel.setCurrent(workUnitsCompleted);
}
});
});
}
}
/**
@ -219,28 +214,22 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator {
* @param workUnitsCompleted Number of work units completed so far.
*/
@Override
public void progress(String message, int workUnitsCompleted) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
public synchronized void progress(String message, int workUnitsCompleted) {
if (!cancelling) {
SwingUtilities.invokeLater(() -> {
progressPanel.setMessage(message);
progressPanel.setCurrent(workUnitsCompleted);
}
});
});
}
}
/**
* Finishes the progress indicator when the task is completed.
*
* @param message The finished message.
*/
@Override
public void finish(String message) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressPanel.setMessage(message);
}
public synchronized void finish() {
SwingUtilities.invokeLater(() -> {
this.dialog.setVisible(false);
});
}

View File

@ -46,6 +46,7 @@ public interface ProgressIndicator {
/**
* Switches the progress indicator to indeterminate mode (the total number
* of work units to be completed is unknown).
*
* @param message The initial progress message.
*/
public void switchToIndeterminate(String message);
@ -54,7 +55,7 @@ public interface ProgressIndicator {
* Switches the progress indicator to determinate mode (the total number of
* work units to be completed is known).
*
* @param message The initial progress message.
* @param message The initial progress message.
* @param workUnitsCompleted The number of work units completed so far.
* @param totalWorkUnits The total number of work units to be completed.
*/
@ -88,9 +89,7 @@ public interface ProgressIndicator {
/**
* Finishes the progress indicator when the task is completed.
*
* @param message The finished message.
*/
void finish(String message);
void finish();
}

View File

@ -35,7 +35,7 @@ class ProgressPanel extends javax.swing.JPanel {
this.progressMessage.setText(message);
}
void setInderminate(boolean indeterminate) {
void setIndeterminate(boolean indeterminate) {
this.progressBar.setIndeterminate(indeterminate);
}

View File

@ -54,7 +54,7 @@ public class SilentProgressIndicator implements ProgressIndicator {
}
@Override
public void finish(String message) {
public void finish() {
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,98 +25,99 @@ import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.framework.AutopsyService;
@ServiceProviders(value = {@ServiceProvider(service = AutopsyService.class)})
/**
* Creates and handles closing of ImageWriter objects.
* Currently, ImageWriter is only enabled for local disks, and local disks can
* not be processed in multi user mode. If ImageWriter is ever enabled for multi user
* cases this code will need to be revised.
* Creates and handles closing of ImageWriter objects. Currently, ImageWriter is
* only enabled for local disks, and local disks can not be processed in multi
* user mode. If ImageWriter is ever enabled for multi user cases this code will
* need to be revised.
*/
@ServiceProvider(service = AutopsyService.class)
public class ImageWriterService implements AutopsyService {
private static final List<ImageWriter> imageWriters = new ArrayList<>(); // Contains all Image Writer objects
private static final Object imageWritersLock = new Object(); // Get this lock before accessing currentImageWriters
/**
* Create an image writer object for the given data source ID.
*
* @param imageId ID for the image
*/
public static void createImageWriter(Long imageId, ImageWriterSettings settings){
public static void createImageWriter(Long imageId, ImageWriterSettings settings) {
// ImageWriter objects are created during the addImageTask. They can not arrive while
// we're closing case resources so we don't need to worry about one showing up while
// doing our close/cleanup.
synchronized(imageWritersLock){
synchronized (imageWritersLock) {
ImageWriter writer = new ImageWriter(imageId, settings);
writer.subscribeToEvents();
imageWriters.add(writer);
}
}
@Override
public String getServiceName() {
return NbBundle.getMessage(this.getClass(), "ImageWriterService.serviceName");
}
@Override
public void closeCaseResources(CaseContext context) throws AutopsyServiceException {
context.getProgressIndicator().progress(NbBundle.getMessage(this.getClass(), "ImageWriterService.waitingForVHDs"));
synchronized(imageWritersLock){
synchronized (imageWritersLock) {
if (imageWriters.isEmpty()) {
return;
}
context.getProgressIndicator().progress(NbBundle.getMessage(this.getClass(), "ImageWriterService.waitingForVHDs"));
// If any of our ImageWriter objects haven't started the finish task, set the cancel flag
// to make sure they don't start now. The reason they haven't started is that
// ingest was not complete, and the user already confirmed that they want to exit
// even though ingest is not complete so we will take that to mean that they
// also don't want to wait for Image Writer.
for(ImageWriter writer: imageWriters){
for (ImageWriter writer : imageWriters) {
writer.cancelIfNotStarted();
}
// Test whether any finishImage tasks are in progress
boolean jobsAreInProgress = false;
for(ImageWriter writer: imageWriters){
if(writer.jobIsInProgress()){
for (ImageWriter writer : imageWriters) {
if (writer.jobIsInProgress()) {
jobsAreInProgress = true;
break;
}
}
if(jobsAreInProgress){
if (jobsAreInProgress) {
// If jobs are in progress, ask the user if they want to wait for them to complete
NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation(
NbBundle.getMessage(this.getClass(), "ImageWriterService.shouldWait"),
NbBundle.getMessage(this.getClass(), "ImageWriterService.localDisk"),
NotifyDescriptor.YES_NO_OPTION,
NotifyDescriptor.WARNING_MESSAGE);
NbBundle.getMessage(this.getClass(), "ImageWriterService.shouldWait"),
NbBundle.getMessage(this.getClass(), "ImageWriterService.localDisk"),
NotifyDescriptor.YES_NO_OPTION,
NotifyDescriptor.WARNING_MESSAGE);
descriptor.setValue(NotifyDescriptor.NO_OPTION);
Object response = DialogDisplayer.getDefault().notify(descriptor);
if(response == DialogDescriptor.NO_OPTION){
if (response == DialogDescriptor.NO_OPTION) {
// Cancel all the jobs
for(ImageWriter writer: imageWriters){
for (ImageWriter writer : imageWriters) {
writer.cancelJob();
}
}
// Wait for all finishImage jobs to complete. If the jobs got cancelled
// this will be very fast.
for(ImageWriter writer: imageWriters){
for (ImageWriter writer : imageWriters) {
writer.waitForJobToFinish();
}
}
// Stop listening for events
for(ImageWriter writer: imageWriters){
for (ImageWriter writer : imageWriters) {
writer.unsubscribeFromEvents();
}
// Clear out the list of Image Writers
imageWriters.clear();
}

View File

@ -53,7 +53,7 @@ public class TestAutopsyService implements AutopsyService {
progressIndicator.progress(80);
Thread.sleep(1000L);
progressIndicator.progress(100);
progressIndicator.finish("First task completed by Test Autopsy Service.");
progressIndicator.finish();
progressIndicator.start("Test Autopsy Service doing second task...");
for (int i = 0; i < 10000; ++i) {
logger.log(Level.INFO, "Test Autopsy Service simulating work on second task");
@ -62,7 +62,7 @@ public class TestAutopsyService implements AutopsyService {
break;
}
}
progressIndicator.finish("Second task completed by Test Autopsy Service.");
progressIndicator.finish();
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Test Autopsy Service interrupted (cancelled) while doing first task, cancel requested = {0}", context.cancelRequested());
}

View File

@ -200,6 +200,10 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
"SolrSearch.openCore.msg=Opening text index",
"SolrSearch.complete.msg=Text index successfully opened"})
public void openCaseResources(CaseContext context) throws AutopsyServiceException {
if (context.cancelRequested()) {
return;
}
ProgressIndicator progress = context.getProgressIndicator();
int totalNumProgressUnits = 7;
int progressUnitsCompleted = 0;