diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index b78e9fecdf..1d172a96ed 100755 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -237,6 +237,55 @@ + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.jellytools.java + + + + org.netbeans.modules.jellytools.platform + + + + org.netbeans.modules.jemmy + + + + org.netbeans.modules.nbjunit + + + + + qa-functional + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.jellytools.java + + + + org.netbeans.modules.jellytools.platform + + + + org.netbeans.modules.jemmy + + + + org.netbeans.modules.nbjunit + + + + + net.sf.sevenzipjbinding net.sf.sevenzipjbinding.impl @@ -260,6 +309,7 @@ org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch + org.sleuthkit.autopsy.guiutils org.sleuthkit.autopsy.ingest org.sleuthkit.autopsy.keywordsearchservice org.sleuthkit.autopsy.menuactions @@ -366,6 +416,14 @@ ext/c3p0-0.9.5.jar release/modules/ext/c3p0-0.9.5.jar + + ext/commons-dbcp2-2.1.1.jar + release\modules\ext\commons-dbcp2-2.1.1.jar + + + ext/commons-pool2-2.4.2.jar + release\modules\ext\commons-pool2-2.4.2.jar + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 1fc2209750..60db8edaf8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -1,14 +1,13 @@ -CTL_AddImage=Add Data Source... +CTL_AddImage=Add Data Source CTL_AddImageButton=Add Data Source CTL_CaseCloseAct=Close Case -CTL_CaseNewAction=New Case... -CTL_CasePropertiesAction=Case Properties... +CTL_CaseNewAction=New Case +CTL_CasePropertiesAction=Case Properties CTL_CaseDeleteAction=Delete Case -CTL_OpenAction=Open Case... +CTL_CaseOpenAction=Open Case Menu/Case/OpenRecentCase=Open Recent Case CTL_CaseDeleteAction=Delete Case OpenIDE-Module-Name=Case -NewCaseVisualPanel1.jLabel1.text_1=Enter New Case Information: NewCaseVisualPanel1.caseNameLabel.text_1=Case Name: NewCaseVisualPanel1.caseDirLabel.text=Base Directory: NewCaseVisualPanel1.caseDirBrowseButton.text=Browse @@ -20,11 +19,6 @@ CueBannerPanel.autopsyLogo.text= CueBannerPanel.closeButton.text=Close OpenRecentCasePanel.cancelButton.text=Cancel OpenRecentCasePanel.jLabel1.text=Recent Cases -NewCaseVisualPanel2.caseNumberTextField.text= -NewCaseVisualPanel2.examinerLabel.text=Examiner: -NewCaseVisualPanel2.caseNumberLabel.text=Case Number: -NewCaseVisualPanel2.examinerTextField.text= -NewCaseVisualPanel2.optionalLabel.text=Optional: Set Case Number and Examiner AddImageErrorsDialog.title=Add Image Log AddImageErrorsDialog.copyButton.toolTipText=Copy errors to clipboard AddImageErrorsDialog.copyButton.text=Copy @@ -152,10 +146,10 @@ MissingImageDialog.display.title=Search for Missing Image MissingImageDialog.confDlg.noFileSel.msg=No image file has been selected, are you sure you\nwould like to exit without finding the image. MissingImageDialog.confDlg.noFileSel.title=Missing Image MissingImageDialog.ErrorSettingImage=Error setting image path. Please try again. -NewCaseVisualPanel1.getName.text=Case Info +NewCaseVisualPanel1.getName.text=Case Information NewCaseVisualPanel1.caseDirBrowse.selectButton.text=Select NewCaseVisualPanel1.badCredentials.text=Bad multi-user settings (see Tools, Options, Multi-user) or services are down. -NewCaseVisualPanel2.getName.text=Additional Information +NewCaseVisualPanel2.getName.text=Optional Information NewCaseWizardAction.newCase.windowTitle.text=New Case Information NewCaseWizardAction.getName.text=New Case Wizard NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case creation. @@ -209,21 +203,39 @@ LocalDiskPanel.imageWriterErrorLabel.text=Error Label LocalDiskPanel.jLabel1.text=Note that at least one ingest module must be run to create a complete copy LocalDiskPanel.pathTextField.text= LocalDiskPanel.browseButton.text=Browse -CasePropertiesPanel.updateCaseNameButton.text=Update Name -CasePropertiesPanel.caseNameTextField.text= CasePropertiesPanel.caseDirLabel.text=Case Directory: CasePropertiesPanel.crDateLabel.text=Created Date: CasePropertiesPanel.caseNameLabel.text=Case Name: CasePropertiesPanel.lbDbName.text=Database Name: CasePropertiesPanel.lbDbType.text=Case Type: -CasePropertiesPanel.examinerLabel.text=Examiner: CasePropertiesPanel.caseNumberLabel.text=Case Number: LocalDiskPanel.changeDatabasePathCheckbox.text=Update case to use VHD file upon completion -CueBannerPanel.openAutoIngestCaseButton.text= +CueBannerPanel.openMultiUserCaseButton.text= CueBannerPanel.openExistingCaseButton.text= CueBannerPanel.openRecentCaseButton.text= CueBannerPanel.createNewCaseButton.text= CueBannerPanel.createNewCaseLabel.text=Create New Case CueBannerPanel.openRecentCaseLabel.text=Open Recent Case CueBannerPanel.openExistingCaseLabel.text=Open Existing Case -CueBannerPanel.openAutoIngestCaseLabel.text=Open Auto Ingest Case +CueBannerPanel.openMultiUserCaseLabel.text=Open Multi-User Case +ReviewModeCasePanel.cannotOpenCase=Cannot Open Case +ReviewModeCasePanel.casePathNotFound=Case path not found +ReviewModeCasePanel.caseIsLocked=Single-user case is locked. +ReviewModeCasePanel.CaseHeaderText=Case +ReviewModeCasePanel.CreatedTimeHeaderText=Created Time +ReviewModeCasePanel.StatusIconHeaderText=Status +ReviewModeCasePanel.OutputFolderHeaderText=Output Folder +ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time +ReviewModeCasePanel.MetadataFileHeaderText=Metadata File +OpenMultiUserCasePanel.jLabel1.text=Recent Cases +OpenMultiUserCasePanel.openButton.text=Open +OpenMultiUserCasePanel.cancelButton.text=Cancel +MultiUserCasesPanel.rbWeeks.text=Weeks +MultiUserCasesPanel.rbDays.text=Days +MultiUserCasesPanel.bnShowLog.toolTipText=Display case log file for selected case +MultiUserCasesPanel.bnShowLog.text=&Show Auto Ingest Case Log +MultiUserCasesPanel.rbAllCases.text=Everything +MultiUserCasesPanel.bnRefresh.text=&Refresh +MultiUserCasesPanel.bnOpen.text=&Open +MultiUserCasesPanel.rbGroupLabel.text=Show cases accessed in the last 10: +MultiUserCasesPanel.rbMonths.text=Months diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index fd00f725e5..de333e790f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -1,13 +1,12 @@ CTL_AddImageButton=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0 CTL_CaseCloseAct=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u308b -CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9... -CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3... +CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9 +CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3 CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 -CTL_OpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f... +CTL_CaseOpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f Menu/Case/OpenRecentCase=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 OpenIDE-Module-Name=\u30b1\u30fc\u30b9 -NewCaseVisualPanel1.jLabel1.text_1=\u65b0\u898f\u30b1\u30fc\u30b9\u60c5\u5831\u3092\u5165\u529b\uff1a NewCaseVisualPanel1.caseNameLabel.text_1=\u30b1\u30fc\u30b9\u540d\uff1a NewCaseVisualPanel1.caseDirLabel.text=\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff1a NewCaseVisualPanel1.caseDirBrowseButton.text=\u95b2\u89a7 @@ -15,9 +14,6 @@ NewCaseVisualPanel1.jLabel2.text_1=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u306f\u6 CueBannerPanel.closeButton.text=\u9589\u3058\u308b OpenRecentCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb OpenRecentCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb -NewCaseVisualPanel2.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a -NewCaseVisualPanel2.caseNumberLabel.text=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a -NewCaseVisualPanel2.optionalLabel.text=\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\uff1a\u30b1\u30fc\u30b9\u756a\u53f7\u304a\u3088\u3073\u8abf\u67fb\u62c5\u5f53\u8005\u3092\u8a2d\u5b9a AddImageErrorsDialog.title=\u30a4\u30e1\u30fc\u30b8\u30ed\u30b0\u3092\u8ffd\u52a0 AddImageErrorsDialog.copyButton.toolTipText=\u30a8\u30e9\u30fc\u3092\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u306b\u30b3\u30d4\u30fc\u3057\u307e\u3059 AddImageErrorsDialog.copyButton.text=\u30b3\u30d4\u30fc @@ -185,15 +181,19 @@ Case_caseType_multiUser=\u8907\u6570\u30e6\u30fc\u30b6\u30fc\u30b1\u30fc\u30b9 Case_caseType_singleUser=\u5358\u6570\u30e6\u30fc\u30b6\u30fc\u30b1\u30fc\u30b9 CasePropertiesForm.imagesTable.columnModel.title0=\u30d1\u30b9 CasePropertiesForm.imagesTable.columnModel.title1=\u524a\u9664 -CasePropertiesPanel.updateCaseNameButton.text=\u66f4\u65b0 CasePropertiesPanel.caseDirLabel.text=\u30b1\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff1a CasePropertiesPanel.crDateLabel.text=\u4f5c\u6210\u65e5\uff1a CasePropertiesPanel.caseNameLabel.text=\u30b1\u30fc\u30b9\u540d\uff1a CasePropertiesPanel.lbDbName.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u540d\uff1a CasePropertiesPanel.lbDbType.text=\u30b1\u30fc\u30b9\u30bf\u30a4\u30d7\uff1a -CasePropertiesPanel.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a CasePropertiesPanel.caseNumberLabel.text=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a +CasePropertiesPanel.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a +OptionalCasePropertiesPanel.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a +OptionalCasePropertiesPanel.caseDisplayNameLabel.text=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a CueBannerPanel.createNewCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5c\u6210 CueBannerPanel.openRecentCaseLabel.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openExistingCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openAutoIngestCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f +OpenMultiUserCasePanel.openButton.text=\u958b\u304f +OpenMultiUserCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +OpenMultiUserCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index ee45d53944..00ce2cca5d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -91,6 +91,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.events.AutopsyEvent; @@ -129,7 +130,6 @@ public class Case { private static final String REPORTS_FOLDER = "Reports"; //NON-NLS private static final String TEMP_FOLDER = "Temp"; //NON-NLS private static final String MODULE_FOLDER = "ModuleOutput"; //NON-NLS - private static final long EXECUTOR_AWAIT_TIMEOUT_SECS = 5; private static final String CASE_ACTION_THREAD_NAME = "%s-case-action"; private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources"; private static final Logger logger = Logger.getLogger(Case.class.getName()); @@ -250,19 +250,28 @@ public class Case { * The name of the current case has changed. The old value of the * PropertyChangeEvent is the old case name (type: String), the new * value is the new case name (type: String). + * + * @Deprecated CASE_DETAILS event should be used instead */ + @Deprecated NAME, /** * The number of the current case has changed. The old value of the * PropertyChangeEvent is the old case number (type: String), the new * value is the new case number (type: String). + * + * @Deprecated CASE_DETAILS event should be used instead */ + @Deprecated NUMBER, /** * The examiner associated with the current case has changed. The old * value of the PropertyChangeEvent is the old examiner (type: String), * the new value is the new examiner (type: String). + * + * @Deprecated CASE_DETAILS event should be used instead */ + @Deprecated EXAMINER, /** * An attempt to add a new data source to the current case is being @@ -347,7 +356,14 @@ public class Case { * The old value of the PropertyChangeEvent is is the tag info (type: * ContentTagDeletedEvent.DeletedContentTagInfo), the new value is null. */ - CONTENT_TAG_DELETED; + CONTENT_TAG_DELETED, + /** + * The case display name or an optional detail which can be provided + * regarding a case has been changed. The optional details include the + * case number, the examiner name, examiner phone, examiner email, and + * the case notes. + */ + CASE_DETAILS; }; /** @@ -478,19 +494,46 @@ public class Case { * @throws CaseActionException If there is a problem creating the * case. * @throws CaseActionCancelledException If creating the case is cancelled. + * + * @Deprecated use createAsCurrentCase(CaseType caseType, String caseDir, + * CaseDetails caseDetails) instead + */ + @Deprecated + public static void createAsCurrentCase(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException, CaseActionCancelledException { + createAsCurrentCase(caseType, caseDir, new CaseDetails(caseDisplayName, caseNumber, examiner, "", "", "")); + } + + /** + * Creates a new case and makes it the current case. + * + * IMPORTANT: This method should not be called in the event dispatch thread + * (EDT). + * + * @param caseDir The full path of the case directory. The directory + * will be created if it doesn't already exist; if it + * exists, it is ASSUMED it was created by calling + * createCaseDirectory. + * @param caseType The type of case (single-user or multi-user). + * @param caseDetails Contains the modifiable details of the case such as + * the case display name, the case number, and the + * examiner related data. + * + * @throws CaseActionException If there is a problem creating the + * case. + * @throws CaseActionCancelledException If creating the case is cancelled. */ @Messages({ "Case.exceptionMessage.emptyCaseName=Must specify a case name.", "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path." }) - public static void createAsCurrentCase(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException, CaseActionCancelledException { - if (caseDisplayName.isEmpty()) { + public static void createAsCurrentCase(CaseType caseType, String caseDir, CaseDetails caseDetails) throws CaseActionException, CaseActionCancelledException { + if (caseDetails.getCaseDisplayName().isEmpty()) { throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseName()); } if (caseDir.isEmpty()) { throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseDir()); } - openAsCurrentCase(new Case(caseType, caseDir, caseDisplayName, caseNumber, examiner), true); + openAsCurrentCase(new Case(caseType, caseDir, caseDetails), true); } /** @@ -1158,6 +1201,33 @@ public class Case { return metadata.getExaminer(); } + /** + * Gets the examiner phone number. + * + * @return The examiner phone number. + */ + public String getExaminerPhone() { + return metadata.getExaminerPhone(); + } + + /** + * Gets the examiner email address. + * + * @return The examiner email address. + */ + public String getExaminerEmail() { + return metadata.getExaminerEmail(); + } + + /** + * Gets the case notes. + * + * @return The case notes. + */ + public String getCaseNotes() { + return metadata.getCaseNotes(); + } + /** * Gets the path to the top-level case directory. * @@ -1475,24 +1545,37 @@ public class Case { } /** - * Updates the case display name name. + * Updates the case display name. + * + * @param newDisplayName the new display name for the case + * + * @throws org.sleuthkit.autopsy.casemodule.CaseActionException */ @Messages({ - "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata, cannot change case display name." + "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata" }) - void updateDisplayName(String newDisplayName) throws CaseActionException { - String oldDisplayName = metadata.getCaseDisplayName(); + void updateCaseDetails(CaseDetails caseDetails) throws CaseActionException { + CaseDetails oldCaseDetails = metadata.getCaseDetails(); try { - metadata.setCaseDisplayName(newDisplayName); + metadata.setCaseDetails(caseDetails); } catch (CaseMetadataException ex) { - throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError()); + throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError(), ex); } - eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldDisplayName, newDisplayName)); + if (!oldCaseDetails.getCaseNumber().equals(caseDetails.getCaseNumber())) { + eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getCaseNumber(), caseDetails.getCaseNumber())); + } + if (!oldCaseDetails.getExaminerName().equals(caseDetails.getExaminerName())) { + eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getExaminerName(), caseDetails.getExaminerName())); + } + if (!oldCaseDetails.getCaseDisplayName().equals(caseDetails.getCaseDisplayName())) { + eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseDetails.getCaseDisplayName(), caseDetails.getCaseDisplayName())); + } + eventPublisher.publish(new AutopsyEvent(Events.CASE_DETAILS.toString(), oldCaseDetails, caseDetails)); if (RuntimeProperties.runningWithGUI()) { SwingUtilities.invokeLater(() -> { - mainFrame.setTitle(newDisplayName + " - " + UserPreferences.getAppName()); + mainFrame.setTitle(caseDetails.getCaseDisplayName() + " - " + UserPreferences.getAppName()); try { - RecentCases.getInstance().updateRecentCase(oldDisplayName, metadata.getFilePath().toString(), newDisplayName, metadata.getFilePath().toString()); + RecentCases.getInstance().updateRecentCase(oldCaseDetails.getCaseDisplayName(), metadata.getFilePath().toString(), caseDetails.getCaseDisplayName(), metadata.getFilePath().toString()); } catch (Exception ex) { logger.log(Level.SEVERE, "Error updating case name in UI", ex); //NON-NLS } @@ -1514,8 +1597,8 @@ public class Case { * @param examiner The examiner to associate with the case, can be * the empty string. */ - private Case(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner) { - metadata = new CaseMetadata(caseDir, caseType, displayNameToUniqueName(caseDisplayName), caseDisplayName, caseNumber, examiner); + private Case(CaseType caseType, String caseDir, CaseDetails caseDetails) { + metadata = new CaseMetadata(caseType, caseDir, displayNameToUniqueName(caseDetails.getCaseDisplayName()), caseDetails); } /** @@ -1636,7 +1719,7 @@ public class Case { } else { future.cancel(true); } - Case.shutDownTaskExecutor(caseLockingExecutor); + ThreadUtils.shutDownTaskExecutor(caseLockingExecutor); } catch (CancellationException discarded) { /* * The create/open task has been cancelled. Wait for it to finish, @@ -1645,7 +1728,7 @@ public class Case { * will have been closed and the case directory lock released will * have been released. */ - Case.shutDownTaskExecutor(caseLockingExecutor); + ThreadUtils.shutDownTaskExecutor(caseLockingExecutor); throw new CaseActionCancelledException(Bundle.Case_exceptionMessage_cancelledByUser()); } catch (ExecutionException ex) { /* @@ -1655,7 +1738,7 @@ public class Case { * case will have been closed and the case directory lock released * will have been released. */ - Case.shutDownTaskExecutor(caseLockingExecutor); + ThreadUtils.shutDownTaskExecutor(caseLockingExecutor); throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex); } finally { progressIndicator.finish(); @@ -1983,7 +2066,7 @@ public class Case { * would be possible to start the next task before the current * task responded to a cancellation request. */ - shutDownTaskExecutor(executor); + ThreadUtils.shutDownTaskExecutor(executor); progressIndicator.finish(); } @@ -2054,7 +2137,7 @@ public class Case { } catch (ExecutionException ex) { throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex); } finally { - shutDownTaskExecutor(caseLockingExecutor); + ThreadUtils.shutDownTaskExecutor(caseLockingExecutor); progressIndicator.finish(); } } @@ -2165,7 +2248,7 @@ public class Case { Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage()))); } } finally { - shutDownTaskExecutor(executor); + ThreadUtils.shutDownTaskExecutor(executor); progressIndicator.finish(); } } @@ -2222,41 +2305,6 @@ public class Case { } - /** - * Shuts down a task executor service, waiting until all tasks are - * terminated. The current policy is to wait for the tasks to finish so that - * the case for which the executor is running can be left in a consistent - * state. - * - * @param executor The executor. - */ - private static void shutDownTaskExecutor(ExecutorService executor) { - executor.shutdown(); - boolean taskCompleted = false; - while (!taskCompleted) { - try { - taskCompleted = executor.awaitTermination(EXECUTOR_AWAIT_TIMEOUT_SECS, TimeUnit.SECONDS); - } catch (InterruptedException ignored) { - /* - * The current policy is to wait for the task to finish so that - * the case can be left in a consistent state. - * - * For a specific example of the motivation for this policy, - * note that a application service (Solr search service) - * experienced an error condition when opening case resources - * that left the service blocked uninterruptibly on a socket - * read. This eventually led to a mysterious "freeze" as the - * user-cancelled service task continued to run holdiong a lock - * that a UI thread soon tried to acquire. Thus it has been - * deemed better to make the "freeze" happen in a more - * informative way, i.e., with the progress indicator for the - * unfinished task on the screen, if a similar error condition - * arises again. - */ - } - } - } - /** * A case operation Cancel button listener for use with a * ModalDialogProgressIndicator when running with a GUI. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 3ef30f2594..66e983b1ce 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -33,7 +33,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -45,13 +44,16 @@ import org.sleuthkit.autopsy.coreutils.Logger; final class CaseDeleteAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(CaseDeleteAction.class.getName()); + private static final Logger LOGGER = Logger.getLogger(CaseDeleteAction.class.getName()); CaseDeleteAction() { putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction")); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { - setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW); + /* + * A value of 'null' signifies that there is no case open. + */ + setEnabled(null != evt.getNewValue()); }); } @@ -93,7 +95,7 @@ final class CaseDeleteAction extends CallableSystemAction { try { get(); } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectory), ex); + LOGGER.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectory), ex); JOptionPane.showMessageDialog( null, Bundle.Case_deleteCaseFailureMessageBox_message(ex.getLocalizedMessage()), @@ -108,7 +110,7 @@ final class CaseDeleteAction extends CallableSystemAction { }.execute(); } } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "Case delete action called with no current case", ex); + LOGGER.log(Level.SEVERE, "Case delete action called with no current case", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDetails.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDetails.java new file mode 100644 index 0000000000..d1cd8861eb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDetails.java @@ -0,0 +1,121 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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; + +/** + * Wrapper to contain the modifiable details of a case, such as case display + * name, case number, and examiner related fields. + */ +public final class CaseDetails { + + private final String caseDisplayName; + private final String caseNumber; + private final String examinerName; + private final String examinerPhone; + private final String examinerEmail; + private final String caseNotes; + + /** + * Create a case details object with all optional fields set to default + * values. + * + * @param displayName the display name of the case + */ + public CaseDetails(String displayName) { + caseDisplayName = displayName; + caseNumber = ""; + examinerName = ""; + examinerPhone = ""; + examinerEmail = ""; + caseNotes = ""; + } + + /** + * Create a case details object with the specified values. + * + * @param displayName the display name of the case + * @param number the case number + * @param exName the examiner name + * @param exPhone the examiner phone number + * @param exEmail the examiner email address + * @param notes the case notes + */ + public CaseDetails(String displayName, String number, String exName, String exPhone, String exEmail, String notes) { + caseDisplayName = displayName; + caseNumber = number; + examinerName = exName; + examinerPhone = exPhone; + examinerEmail = exEmail; + caseNotes = notes; + } + + /** + * Get the case display name + * + * @return caseDisplayName - the display name of the case + */ + public String getCaseDisplayName() { + return caseDisplayName; + } + + /** + * Get the case number + * + * @return caseNumber - the optional number assiciated with the case + */ + public String getCaseNumber() { + return caseNumber; + } + + /** + * Get the examiner name + * + * @return name - the name associated with the examiner + */ + public String getExaminerName() { + return examinerName; + } + + /** + * Get the examiner phone number + * + * @return phone - the phone number associated with the examiner + */ + public String getExaminerPhone() { + return examinerPhone; + } + + /** + * Get the examiner email address + * + * @return email - the email address associated with the examiner + */ + public String getExaminerEmail() { + return examinerEmail; + } + + /** + * Get the case notes + * + * @return notes - the note asssociated with the case + */ + public String getCaseNotes() { + return caseNotes; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.form index 74892fe40d..932f370478 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.form @@ -18,38 +18,43 @@ - + - + - + - + + + - - + + - - - - + + + + + + + @@ -70,8 +75,15 @@ + + + + + + + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java index b51f0d8a63..b03a17920e 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java @@ -18,9 +18,15 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import javax.swing.JDialog; import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; /** * Panel for displaying the case information, including both case details and @@ -29,6 +35,7 @@ import org.openide.util.NbBundle.Messages; class CaseInformationPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; + CasePropertiesPanel propertiesPanel; /** * Constructs a panel for displaying the case information, including both @@ -40,16 +47,21 @@ class CaseInformationPanel extends javax.swing.JPanel { } @Messages({ - "CaseInformationPanel.caseDetails.header=Case Details", - "CaseInformationPanel.ingestJobInfo.header=Ingest History" + "CaseInformationPanel.caseDetails.header=Details", + "CaseInformationPanel.ingestJobInfo.header=Ingest History", + "CaseInformationPanel.editDetailsButton.text=Edit Details", + "CaseInformationPanel.editDetailsDialog.title=Edit Case Details" }) private void customizeComponents() { - CasePropertiesPanel propertiesPanel = new CasePropertiesPanel(Case.getCurrentCase()); + 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()); + this.tabbedPane.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize()); + } }); } @@ -71,36 +83,46 @@ class CaseInformationPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - jPanel1 = new javax.swing.JPanel(); + outerDetailsPanel = new javax.swing.JPanel(); tabbedPane = new javax.swing.JTabbedPane(); closeButton = new javax.swing.JButton(); + editDetailsButton = new javax.swing.JButton(); tabbedPane.setPreferredSize(new java.awt.Dimension(420, 200)); org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(CaseInformationPanel.class, "CaseInformationPanel.closeButton.text")); // NOI18N - closeButton.addActionListener(new java.awt.event.ActionListener() { + + org.openide.awt.Mnemonics.setLocalizedText(editDetailsButton, org.openide.util.NbBundle.getMessage(CaseInformationPanel.class, "CaseInformationPanel.editDetailsButton.text")); // NOI18N + editDetailsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - closeButtonActionPerformed(evt); + editDetailsButtonActionPerformed(evt); } }); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + javax.swing.GroupLayout outerDetailsPanelLayout = new javax.swing.GroupLayout(outerDetailsPanel); + outerDetailsPanel.setLayout(outerDetailsPanelLayout); + outerDetailsPanelLayout.setHorizontalGroup( + outerDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 709, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(outerDetailsPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(editDetailsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(closeButton) - .addGap(5, 5, 5)) + .addContainerGap()) ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 223, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(closeButton) - .addGap(5, 5, 5)) + + outerDetailsPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, editDetailsButton}); + + outerDetailsPanelLayout.setVerticalGroup( + outerDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(outerDetailsPanelLayout.createSequentialGroup() + .addComponent(tabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 228, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addGroup(outerDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(editDetailsButton)) + .addContainerGap()) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -109,23 +131,45 @@ class CaseInformationPanel extends javax.swing.JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(0, 0, 0) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(outerDetailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGap(0, 0, 0)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(outerDetailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); }// //GEN-END:initComponents - private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed - // Used by CasePropertiesAction - }//GEN-LAST:event_closeButtonActionPerformed + private void editDetailsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editDetailsButtonActionPerformed + JDialog editCasePropertiesDialog = new JDialog(WindowManager.getDefault().getMainWindow(), Bundle.CaseInformationPanel_editDetailsDialog_title(), true); + EditOptionalCasePropertiesPanel editCasePropertiesPanel = new EditOptionalCasePropertiesPanel(); + editCasePropertiesPanel.addCancelButtonAction((ActionEvent e) -> { + editCasePropertiesDialog.setVisible(false); + }); + editCasePropertiesPanel.addSaveButtonAction((ActionEvent e) -> { + editCasePropertiesDialog.setVisible(false); + editCasePropertiesPanel.saveProperties(); + propertiesPanel.updateCaseInfo(); + }); + + editCasePropertiesDialog.add(editCasePropertiesPanel); + editCasePropertiesDialog.setResizable(true); + editCasePropertiesDialog.pack(); + + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + double w = editCasePropertiesDialog.getSize().getWidth(); + double h = editCasePropertiesDialog.getSize().getHeight(); + editCasePropertiesDialog.setLocation((int) ((screenDimension.getWidth() - w) / 2), (int) ((screenDimension.getHeight() - h) / 2)); + editCasePropertiesDialog.setVisible(true); + editCasePropertiesDialog.toFront(); + propertiesPanel.updateCaseInfo(); + }//GEN-LAST:event_editDetailsButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton closeButton; - private javax.swing.JPanel jPanel1; + private javax.swing.JButton editDetailsButton; + private javax.swing.JPanel outerDetailsPanel; private javax.swing.JTabbedPane tabbedPane; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 1f4c5b7912..6e47363db5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -85,20 +85,25 @@ public final class CaseMetadata { private final static String CASE_DISPLAY_NAME_ELEMENT_NAME = "DisplayName"; //NON-NLS private final static String CASE_DB_NAME_RELATIVE_ELEMENT_NAME = "CaseDatabase"; //NON-NLS + /* + * Fields from schema version 4 + */ + private static final String SCHEMA_VERSION_FOUR = "4.0"; + private final static String EXAMINER_ELEMENT_PHONE = "ExaminerPhone"; //NON-NLS + private final static String EXAMINER_ELEMENT_EMAIL = "ExaminerEmail"; //NON-NLS + private final static String CASE_ELEMENT_NOTES = "CaseNotes"; //NON-NLS /* * 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 final static String CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_THREE; + private final static String CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_FOUR; private final Path metadataFilePath; private Case.CaseType caseType; private String caseName; - private String caseDisplayName; - private String caseNumber; - private String examiner; + private CaseDetails caseDetails; private String caseDatabaseName; private String caseDatabasePath; // Legacy private String textIndexName; // Legacy @@ -127,13 +132,11 @@ public final class CaseMetadata { * @param caseNumber The case number. * @param examiner The name of the case examiner. */ - CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseDisplayName, String caseNumber, String examiner) { - metadataFilePath = Paths.get(caseDirectory, caseDisplayName + FILE_EXTENSION); + CaseMetadata(Case.CaseType caseType, String caseDirectory, String caseName, CaseDetails caseDetails) { + metadataFilePath = Paths.get(caseDirectory, caseDetails.getCaseDisplayName() + FILE_EXTENSION); this.caseType = caseType; this.caseName = caseName; - this.caseDisplayName = caseDisplayName; - this.caseNumber = caseNumber; - this.examiner = examiner; + this.caseDetails = caseDetails; caseDatabaseName = ""; caseDatabasePath = ""; textIndexName = ""; @@ -191,29 +194,31 @@ public final class CaseMetadata { return caseName; } + /** + * Get current values for the case details which are user modifiable. + * + * @return the case details + */ + public CaseDetails getCaseDetails() { + return caseDetails; + } + /** * Gets the case display name. * * @return The case display name. */ public String getCaseDisplayName() { - return caseDisplayName; + return caseDetails.getCaseDisplayName(); } - /** - * Sets the case display name. - * - * @param caseDisplayName A case display name. - * - * @throws CaseMetadataException If the operation fails. - */ - void setCaseDisplayName(String caseDisplayName) throws CaseMetadataException { - String oldCaseDisplayName = this.caseDisplayName; - this.caseDisplayName = caseDisplayName; + void setCaseDetails(CaseDetails newCaseDetails) throws CaseMetadataException { + CaseDetails oldCaseDetails = this.caseDetails; + this.caseDetails = newCaseDetails; try { writeToFile(); } catch (CaseMetadataException ex) { - this.caseDisplayName = oldCaseDisplayName; + this.caseDetails = oldCaseDetails; throw ex; } } @@ -224,7 +229,7 @@ public final class CaseMetadata { * @return The case number, may be empty. */ public String getCaseNumber() { - return caseNumber; + return caseDetails.getCaseNumber(); } /** @@ -233,7 +238,19 @@ public final class CaseMetadata { * @return The examiner, may be empty. */ public String getExaminer() { - return examiner; + return caseDetails.getExaminerName(); + } + + public String getExaminerPhone() { + return caseDetails.getExaminerPhone(); + } + + public String getExaminerEmail() { + return caseDetails.getExaminerEmail(); + } + + public String getCaseNotes() { + return caseDetails.getCaseNotes(); } /** @@ -389,9 +406,12 @@ public final class CaseMetadata { * Create the children of the case element. */ createChildElement(doc, caseElement, CASE_NAME_ELEMENT_NAME, caseName); - createChildElement(doc, caseElement, CASE_DISPLAY_NAME_ELEMENT_NAME, caseDisplayName); - createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, caseNumber); - createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, examiner); + createChildElement(doc, caseElement, CASE_DISPLAY_NAME_ELEMENT_NAME, caseDetails.getCaseDisplayName()); + createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, caseDetails.getCaseNumber()); + createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, caseDetails.getExaminerName()); + createChildElement(doc, caseElement, EXAMINER_ELEMENT_PHONE, caseDetails.getExaminerPhone()); + createChildElement(doc, caseElement, EXAMINER_ELEMENT_EMAIL, caseDetails.getExaminerEmail()); + createChildElement(doc, caseElement, CASE_ELEMENT_NOTES, caseDetails.getCaseNotes()); createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, caseType.toString()); createChildElement(doc, caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, caseDatabasePath); createChildElement(doc, caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, caseDatabaseName); @@ -452,13 +472,28 @@ public final class CaseMetadata { } Element caseElement = (Element) caseElements.item(0); this.caseName = getElementTextContent(caseElement, CASE_NAME_ELEMENT_NAME, true); + String caseDisplayName; + String caseNumber; if (schemaVersion.equals(SCHEMA_VERSION_ONE) || schemaVersion.equals(SCHEMA_VERSION_TWO)) { - this.caseDisplayName = caseName; + caseDisplayName = caseName; } else { - this.caseDisplayName = getElementTextContent(caseElement, CASE_DISPLAY_NAME_ELEMENT_NAME, true); + caseDisplayName = getElementTextContent(caseElement, CASE_DISPLAY_NAME_ELEMENT_NAME, true); } - this.caseNumber = getElementTextContent(caseElement, CASE_NUMBER_ELEMENT_NAME, false); - this.examiner = getElementTextContent(caseElement, EXAMINER_ELEMENT_NAME, false); + caseNumber = getElementTextContent(caseElement, CASE_NUMBER_ELEMENT_NAME, false); + String examinerName = getElementTextContent(caseElement, EXAMINER_ELEMENT_NAME, false); + String examinerPhone; + String examinerEmail; + String caseNotes; + if (schemaVersion.equals(SCHEMA_VERSION_ONE) || schemaVersion.equals(SCHEMA_VERSION_TWO) || schemaVersion.equals(SCHEMA_VERSION_THREE)) { + examinerPhone = ""; //case had metadata file written before additional examiner details were included + examinerEmail = ""; + caseNotes = ""; + } else { + examinerPhone = getElementTextContent(caseElement, EXAMINER_ELEMENT_PHONE, false); + examinerEmail = getElementTextContent(caseElement, EXAMINER_ELEMENT_EMAIL, false); + caseNotes = getElementTextContent(caseElement, CASE_ELEMENT_NOTES, false); + } + this.caseDetails = new CaseDetails(caseDisplayName, caseNumber, examinerName, examinerPhone, examinerEmail, caseNotes); this.caseType = Case.CaseType.fromString(getElementTextContent(caseElement, CASE_TYPE_ELEMENT_NAME, true)); if (null == this.caseType) { throw new CaseMetadataException("Case metadata file corrupted"); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 533cab58c5..e4ed92d897 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -141,7 +141,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action @Override public String getName() { - return NbBundle.getMessage(CaseOpenAction.class, "CTL_OpenAction"); + return NbBundle.getMessage(CaseOpenAction.class, "CTL_CaseOpenAction"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java new file mode 100755 index 0000000000..7a12b69cf7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -0,0 +1,91 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JDialog; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.core.UserPreferences; + +/** + * The action associated with the Open Multi-User Case menu item via the + * layer.xml file. + * + * This action should only be invoked in the event dispatch thread (EDT). + */ +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.CaseOpenMultiUserAction") +@ActionReference(path = "Menu/Case", position = 102) +@ActionRegistration(displayName = "#CTL_CaseOpenMultiUserAction", lazy = false) +@NbBundle.Messages({"CTL_CaseOpenMultiUserAction=Open Multi-User Case"}) +public final class CaseOpenMultiUserAction extends CallableSystemAction implements ActionListener { + + private static final long serialVersionUID = 1L; + private static JDialog multiUserCaseWindow; + + private static final String DISPLAY_NAME = Bundle.CTL_CaseOpenMultiUserAction(); + + public CaseOpenMultiUserAction() {} + + @Override + public boolean isEnabled() { + return UserPreferences.getIsMultiUserModeEnabled(); + } + + /** + * Pops up a case selection panel to allow the user to select a multi-user + * case to open. + * + * @param event The action event. + */ + @Override + public void actionPerformed(ActionEvent event) { + if(multiUserCaseWindow == null) { + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + } + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + } + + @Override + public void performAction() { + actionPerformed(null); + } + + @Override + public String getName() { + return DISPLAY_NAME; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; // run on edt + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java index c50c561564..886ea011b7 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java @@ -52,7 +52,7 @@ final class CasePropertiesAction extends CallableSystemAction { public void performAction() { SwingUtilities.invokeLater(() -> { String title = NbBundle.getMessage(this.getClass(), "CasePropertiesAction.window.title"); - casePropertiesDialog = new JDialog(WindowManager.getDefault().getMainWindow(), title, false); + casePropertiesDialog = new JDialog(WindowManager.getDefault().getMainWindow(), title, true); CaseInformationPanel caseInformationPanel = new CaseInformationPanel(); caseInformationPanel.addCloseButtonAction((ActionEvent e) -> { casePropertiesDialog.setVisible(false); @@ -66,7 +66,6 @@ final class CasePropertiesAction extends CallableSystemAction { double h = casePropertiesDialog.getSize().getHeight(); casePropertiesDialog.setLocation((int) ((screenDimension.getWidth() - w) / 2), (int) ((screenDimension.getHeight() - h) / 2)); casePropertiesDialog.setVisible(true); - casePropertiesDialog.setVisible(true); casePropertiesDialog.toFront(); }); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.form index d373e58a6e..ab036f2e87 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.form @@ -33,258 +33,656 @@ - + + + + + - + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java index 7a513d7261..23e9d0b1c8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java @@ -20,19 +20,22 @@ package org.sleuthkit.autopsy.casemodule; import java.nio.file.Paths; import java.util.logging.Level; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * 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 { +final class CasePropertiesPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(CasePropertiesPanel.class.getName()); - private final Case theCase; + private Case theCase; /** * Constructs a panel that allows the user to view various properties of the @@ -40,22 +43,19 @@ class CasePropertiesPanel extends javax.swing.JPanel { * * @param aCase A case. */ - CasePropertiesPanel(Case aCase) { + CasePropertiesPanel(Case caseInfo) { initComponents(); - theCase = aCase; - caseNameTextField.setText(theCase.getDisplayName()); - String caseNumber = theCase.getNumber(); - if (!caseNumber.isEmpty()) { - caseNumberField.setText(caseNumber); - } else { - caseNumberField.setText("N/A"); - } - String examiner = theCase.getExaminer(); - if (!examiner.isEmpty()) { - examinerField.setText(examiner); - } else { - examinerField.setText("N/A"); - } + updateCaseInfo(); + } + + void updateCaseInfo() { + theCase = Case.getCurrentCase(); + lbCaseNameText.setText(theCase.getDisplayName()); + lbCaseNumberText.setText(theCase.getNumber()); + lbExaminerNameText.setText(theCase.getExaminer()); + lbExaminerPhoneText.setText(theCase.getExaminerPhone()); + lbExaminerEmailText.setText(theCase.getExaminerEmail()); + taNotesText.setText(theCase.getCaseNotes()); crDateField.setText(theCase.getCreatedDate()); caseDirField.setText(theCase.getCaseDirectory()); if (Case.CaseType.SINGLE_USER_CASE == theCase.getCaseType()) { @@ -63,10 +63,63 @@ class CasePropertiesPanel extends javax.swing.JPanel { } else { dbNameField.setText(theCase.getMetadata().getCaseDatabaseName()); } + boolean cREnabled = EamDb.isEnabled(); + lbOrganizationNameLabel.setEnabled(cREnabled); + lbOrganizationNameText.setEnabled(cREnabled); + lbPointOfContactEmailLabel.setEnabled(cREnabled); + lbPointOfContactEmailText.setEnabled(cREnabled); + lbPointOfContactNameLabel.setEnabled(cREnabled); + lbPointOfContactNameText.setEnabled(cREnabled); + lbPointOfContactPhoneLabel.setEnabled(cREnabled); + lbPointOfContactPhoneText.setEnabled(cREnabled); + pnOrganization.setEnabled(cREnabled); + EamOrganization currentOrg = null; + if (cREnabled) { + try { + EamDb dbManager = EamDb.getInstance(); + if (dbManager != null) { + CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + if (null == correlationCase) { + dbManager.newCase(Case.getCurrentCase()); + correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + } + currentOrg = correlationCase.getOrg(); + } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Unable to access Correlation Case when Central Repo is enabled", ex); + } + } + if (currentOrg != null) { + lbOrganizationNameText.setText(currentOrg.getName()); + lbPointOfContactNameText.setText(currentOrg.getPocName()); + lbPointOfContactPhoneText.setText(currentOrg.getPocPhone()); + lbPointOfContactEmailText.setText(currentOrg.getPocEmail()); + } else { + lbOrganizationNameText.setText(""); + lbPointOfContactNameText.setText(""); + lbPointOfContactPhoneText.setText(""); + lbPointOfContactEmailText.setText(""); + } Case.CaseType caseType = theCase.getCaseType(); - caseTypeField.setText(caseType.getLocalizedDisplayName()); + caseTypeField.setText(caseType.getLocalizedDisplayName()); + lbCaseUIDText.setText(theCase.getName()); + validate(); + repaint(); } + @Messages({"CasePropertiesPanel.casePanel.border.title=Case", + "CasePropertiesPanel.lbCaseUUIDLabel.text=Case UUID:", + "CasePropertiesPanel.examinerPanel.border.title=Examiner", + "CasePropertiesPanel.examinerLabel.text=Name:", + "CasePropertiesPanel.lbExaminerPhoneLabel.text=Phone:", + "CasePropertiesPanel.lbExaminerEmailLabel.text=Email:", + "CasePropertiesPanel.lbNotesLabel.text=Notes:", + "CasePropertiesPanel.pnOrganization.border.title=Organization", + "CasePropertiesPanel.lbOrganizationNameLabel.text=Name:", + "CasePropertiesPanel.lbPointOfContactNameLabel.text=Point of Contact:", + "CasePropertiesPanel.lbPointOfContactPhoneLabel.text=Phone:", + "CasePropertiesPanel.lbPointOfContactEmailLabel.text=Email:"}) + /** * In this generated code below, there are 2 strings "Path" and "Remove" * that are table column headers in the DefaultTableModel. When this model @@ -87,208 +140,393 @@ class CasePropertiesPanel extends javax.swing.JPanel { jScrollPane1 = new javax.swing.JScrollPane(); jTextArea1 = new javax.swing.JTextArea(); - jPanel1 = new javax.swing.JPanel(); + detailsPanel = new javax.swing.JPanel(); + casePanel = new javax.swing.JPanel(); caseNameLabel = new javax.swing.JLabel(); - crDateLabel = new javax.swing.JLabel(); - caseDirLabel = new javax.swing.JLabel(); - caseNameTextField = new javax.swing.JTextField(); - updateCaseNameButton = new javax.swing.JButton(); - caseNumberLabel = new javax.swing.JLabel(); - examinerLabel = new javax.swing.JLabel(); lbDbType = new javax.swing.JLabel(); - lbDbName = new javax.swing.JLabel(); - caseNumberField = new javax.swing.JLabel(); - examinerField = new javax.swing.JLabel(); - crDateField = new javax.swing.JLabel(); - caseDirField = new javax.swing.JLabel(); - dbNameField = new javax.swing.JLabel(); + lbCaseUUIDLabel = new javax.swing.JLabel(); caseTypeField = new javax.swing.JLabel(); + dbNameField = new javax.swing.JLabel(); + lbDbName = new javax.swing.JLabel(); + caseNumberLabel = new javax.swing.JLabel(); + caseDirLabel = new javax.swing.JLabel(); + caseDirField = new javax.swing.JLabel(); + crDateLabel = new javax.swing.JLabel(); + crDateField = new javax.swing.JLabel(); + lbCaseUIDText = new javax.swing.JLabel(); + lbCaseNameText = new javax.swing.JLabel(); + lbCaseNumberText = new javax.swing.JLabel(); + examinerPanel = new javax.swing.JPanel(); + lbExaminerNameText = new javax.swing.JLabel(); + lbNotesLabel = new javax.swing.JLabel(); + examinerLabel = new javax.swing.JLabel(); + caseNotesScrollPane = new javax.swing.JScrollPane(); + taNotesText = new javax.swing.JTextArea(); + lbExaminerEmailLabel = new javax.swing.JLabel(); + lbExaminerPhoneLabel = new javax.swing.JLabel(); + lbExaminerPhoneText = new javax.swing.JLabel(); + lbExaminerEmailText = new javax.swing.JLabel(); + pnOrganization = new javax.swing.JPanel(); + lbOrganizationNameLabel = new javax.swing.JLabel(); + lbPointOfContactNameLabel = new javax.swing.JLabel(); + lbPointOfContactEmailLabel = new javax.swing.JLabel(); + lbPointOfContactPhoneLabel = new javax.swing.JLabel(); + lbPointOfContactNameText = new javax.swing.JLabel(); + lbPointOfContactEmailText = new javax.swing.JLabel(); + lbPointOfContactPhoneText = new javax.swing.JLabel(); + lbOrganizationNameText = new javax.swing.JLabel(); jTextArea1.setColumns(20); jTextArea1.setRows(5); jScrollPane1.setViewportView(jTextArea1); + casePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.casePanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N + caseNameLabel.setFont(caseNameLabel.getFont().deriveFont(caseNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); caseNameLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.caseNameLabel.text")); // NOI18N - - crDateLabel.setFont(crDateLabel.getFont().deriveFont(crDateLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - crDateLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.crDateLabel.text")); // NOI18N - - caseDirLabel.setFont(caseDirLabel.getFont().deriveFont(caseDirLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - caseDirLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.caseDirLabel.text")); // NOI18N - - caseNameTextField.setFont(caseNameTextField.getFont().deriveFont(caseNameTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - caseNameTextField.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.caseNameTextField.text")); // NOI18N - - updateCaseNameButton.setFont(updateCaseNameButton.getFont().deriveFont(updateCaseNameButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - updateCaseNameButton.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.updateCaseNameButton.text")); // NOI18N - updateCaseNameButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - updateCaseNameButtonActionPerformed(evt); - } - }); - - caseNumberLabel.setFont(caseNumberLabel.getFont().deriveFont(caseNumberLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - caseNumberLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.caseNumberLabel.text")); // NOI18N - - examinerLabel.setFont(examinerLabel.getFont().deriveFont(examinerLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - examinerLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.examinerLabel.text")); // NOI18N + caseNameLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + caseNameLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + caseNameLabel.setPreferredSize(new java.awt.Dimension(82, 14)); lbDbType.setFont(lbDbType.getFont().deriveFont(lbDbType.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); lbDbType.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbDbType.text")); // NOI18N + lbDbType.setMaximumSize(new java.awt.Dimension(82, 14)); + lbDbType.setMinimumSize(new java.awt.Dimension(82, 14)); + lbDbType.setPreferredSize(new java.awt.Dimension(82, 14)); - lbDbName.setFont(lbDbName.getFont().deriveFont(lbDbName.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - lbDbName.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbDbName.text")); // NOI18N - - caseDirField.setMinimumSize(new java.awt.Dimension(25, 14)); - - dbNameField.setMinimumSize(new java.awt.Dimension(25, 14)); + lbCaseUUIDLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbCaseUUIDLabel.text")); // NOI18N + lbCaseUUIDLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbCaseUUIDLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbCaseUUIDLabel.setPreferredSize(new java.awt.Dimension(82, 14)); caseTypeField.setMaximumSize(new java.awt.Dimension(1, 0)); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() + dbNameField.setMinimumSize(new java.awt.Dimension(25, 14)); + + lbDbName.setFont(lbDbName.getFont().deriveFont(lbDbName.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + lbDbName.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbDbName.text")); // NOI18N + lbDbName.setMaximumSize(new java.awt.Dimension(82, 14)); + lbDbName.setMinimumSize(new java.awt.Dimension(82, 14)); + lbDbName.setPreferredSize(new java.awt.Dimension(82, 14)); + + caseNumberLabel.setFont(caseNumberLabel.getFont().deriveFont(caseNumberLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + caseNumberLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.caseNumberLabel.text")); // NOI18N + caseNumberLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + caseNumberLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + caseNumberLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + caseDirLabel.setFont(caseDirLabel.getFont().deriveFont(caseDirLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + caseDirLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.caseDirLabel.text")); // NOI18N + caseDirLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + caseDirLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + caseDirLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + caseDirField.setMinimumSize(new java.awt.Dimension(25, 14)); + + crDateLabel.setFont(crDateLabel.getFont().deriveFont(crDateLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + crDateLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.crDateLabel.text")); // NOI18N + crDateLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + crDateLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + crDateLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + lbCaseNameText.setMinimumSize(new java.awt.Dimension(25, 14)); + + lbCaseNumberText.setMinimumSize(new java.awt.Dimension(25, 14)); + + javax.swing.GroupLayout casePanelLayout = new javax.swing.GroupLayout(casePanel); + casePanel.setLayout(casePanelLayout); + casePanelLayout.setHorizontalGroup( + casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbDbName) - .addComponent(lbDbType) - .addComponent(caseDirLabel)) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createSequentialGroup() + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(caseNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseNumberLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCaseNumberText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbCaseNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(casePanelLayout.createSequentialGroup() + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(lbCaseUUIDLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbDbName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbDbType, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseDirLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(crDateLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(crDateField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(caseDirField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(caseTypeField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(dbNameField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(crDateLabel) - .addComponent(examinerLabel) - .addComponent(caseNumberLabel)) - .addGap(18, 18, 18) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(examinerField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(caseNumberField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(caseNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(updateCaseNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(crDateField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addComponent(dbNameField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbCaseUIDText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) .addContainerGap()) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(caseNameLabel) - .addContainerGap(392, Short.MAX_VALUE))) ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + casePanelLayout.setVerticalGroup( + casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(updateCaseNameButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(caseNumberField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(caseNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbCaseNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(caseNumberLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbCaseNumberText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(crDateLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(crDateField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(caseDirLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(caseDirField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(caseTypeField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbDbType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbDbName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(dbNameField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbCaseUUIDLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbCaseUIDText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6)) + ); + + examinerPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.examinerPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N + + lbNotesLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbNotesLabel.text")); // NOI18N + lbNotesLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbNotesLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbNotesLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + lbNotesLabel.setRequestFocusEnabled(false); + + examinerLabel.setFont(examinerLabel.getFont().deriveFont(examinerLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + examinerLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.examinerLabel.text")); // NOI18N + examinerLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + examinerLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + examinerLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + caseNotesScrollPane.setBorder(null); + + taNotesText.setEditable(false); + taNotesText.setBackground(new java.awt.Color(240, 240, 240)); + taNotesText.setColumns(20); + taNotesText.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + taNotesText.setLineWrap(true); + taNotesText.setRows(2); + taNotesText.setWrapStyleWord(true); + taNotesText.setBorder(null); + taNotesText.setFocusable(false); + caseNotesScrollPane.setViewportView(taNotesText); + + lbExaminerEmailLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbExaminerEmailLabel.text")); // NOI18N + lbExaminerEmailLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbExaminerEmailLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbExaminerEmailLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + lbExaminerPhoneLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbExaminerPhoneLabel.text")); // NOI18N + lbExaminerPhoneLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbExaminerPhoneLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbExaminerPhoneLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + javax.swing.GroupLayout examinerPanelLayout = new javax.swing.GroupLayout(examinerPanel); + examinerPanel.setLayout(examinerPanelLayout); + examinerPanelLayout.setHorizontalGroup( + examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbExaminerPhoneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbNotesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(examinerField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(examinerLabel)) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbExaminerPhoneText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(caseNotesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 411, Short.MAX_VALUE))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, examinerPanelLayout.createSequentialGroup() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbExaminerEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(examinerLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(crDateField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(crDateLabel, javax.swing.GroupLayout.Alignment.TRAILING)) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbExaminerNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbExaminerEmailText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addContainerGap()) + ); + examinerPanelLayout.setVerticalGroup( + examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(examinerLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbExaminerNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbExaminerPhoneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbExaminerPhoneText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbExaminerEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbExaminerEmailText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbNotesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseNotesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6)) + ); + + pnOrganization.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.pnOrganization.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N + + lbOrganizationNameLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbOrganizationNameLabel.text")); // NOI18N + lbOrganizationNameLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbOrganizationNameLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbOrganizationNameLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + lbPointOfContactNameLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbPointOfContactNameLabel.text")); // NOI18N + + lbPointOfContactEmailLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbPointOfContactEmailLabel.text")); // NOI18N + lbPointOfContactEmailLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactEmailLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactEmailLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + lbPointOfContactPhoneLabel.setText(org.openide.util.NbBundle.getMessage(CasePropertiesPanel.class, "CasePropertiesPanel.lbPointOfContactPhoneLabel.text")); // NOI18N + lbPointOfContactPhoneLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactPhoneLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactPhoneLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + javax.swing.GroupLayout pnOrganizationLayout = new javax.swing.GroupLayout(pnOrganization); + pnOrganization.setLayout(pnOrganizationLayout); + pnOrganizationLayout.setHorizontalGroup( + pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnOrganizationLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnOrganizationLayout.createSequentialGroup() + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbPointOfContactNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(lbOrganizationNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(caseDirLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(caseDirField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lbPointOfContactNameText, javax.swing.GroupLayout.DEFAULT_SIZE, 411, Short.MAX_VALUE) + .addComponent(lbOrganizationNameText, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactEmailText, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(pnOrganizationLayout.createSequentialGroup() + .addComponent(lbPointOfContactPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(caseTypeField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbDbType)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbDbName) - .addComponent(dbNameField, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addComponent(caseNumberLabel)) - .addGap(44, 44, 44)) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(caseNameLabel) - .addContainerGap(173, Short.MAX_VALUE))) + .addComponent(lbPointOfContactPhoneText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) + ); + pnOrganizationLayout.setVerticalGroup( + pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnOrganizationLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbOrganizationNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbOrganizationNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbPointOfContactPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbPointOfContactPhoneText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactEmailText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6)) + ); + + javax.swing.GroupLayout detailsPanelLayout = new javax.swing.GroupLayout(detailsPanel); + detailsPanel.setLayout(detailsPanelLayout); + detailsPanelLayout.setHorizontalGroup( + detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(casePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(examinerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnOrganization, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + detailsPanelLayout.setVerticalGroup( + detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, detailsPanelLayout.createSequentialGroup() + .addComponent(casePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(examinerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(pnOrganization, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(detailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 169, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(detailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); }// //GEN-END:initComponents - /** - * 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 newCaseDisplayName = caseNameTextField.getText(); - if (newCaseDisplayName.equals(theCase.getDisplayName())) { - return; - } - - if (newCaseDisplayName.trim().isEmpty()) { - MessageNotifyUtil.Message.error(Bundle.CasePropertiesPanel_errorDialog_emptyCaseNameMessage()); - return; - } - - 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 - - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel caseDirField; private javax.swing.JLabel caseDirLabel; private javax.swing.JLabel caseNameLabel; - private javax.swing.JTextField caseNameTextField; - private javax.swing.JLabel caseNumberField; + private javax.swing.JScrollPane caseNotesScrollPane; private javax.swing.JLabel caseNumberLabel; + private javax.swing.JPanel casePanel; private javax.swing.JLabel caseTypeField; private javax.swing.JLabel crDateField; private javax.swing.JLabel crDateLabel; private javax.swing.JLabel dbNameField; - private javax.swing.JLabel examinerField; + private javax.swing.JPanel detailsPanel; private javax.swing.JLabel examinerLabel; - private javax.swing.JPanel jPanel1; + private javax.swing.JPanel examinerPanel; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextArea jTextArea1; + private javax.swing.JLabel lbCaseNameText; + private javax.swing.JLabel lbCaseNumberText; + private javax.swing.JLabel lbCaseUIDText; + private javax.swing.JLabel lbCaseUUIDLabel; private javax.swing.JLabel lbDbName; private javax.swing.JLabel lbDbType; - private javax.swing.JButton updateCaseNameButton; + private javax.swing.JLabel lbExaminerEmailLabel; + private javax.swing.JLabel lbExaminerEmailText; + private javax.swing.JLabel lbExaminerNameText; + private javax.swing.JLabel lbExaminerPhoneLabel; + private javax.swing.JLabel lbExaminerPhoneText; + private javax.swing.JLabel lbNotesLabel; + private javax.swing.JLabel lbOrganizationNameLabel; + private javax.swing.JLabel lbOrganizationNameText; + private javax.swing.JLabel lbPointOfContactEmailLabel; + private javax.swing.JLabel lbPointOfContactEmailText; + private javax.swing.JLabel lbPointOfContactNameLabel; + private javax.swing.JLabel lbPointOfContactNameText; + private javax.swing.JLabel lbPointOfContactPhoneLabel; + private javax.swing.JLabel lbPointOfContactPhoneText; + private javax.swing.JPanel pnOrganization; + private javax.swing.JTextArea taNotesText; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form index 75819e41d0..0d6525db8b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form @@ -28,14 +28,14 @@ - + - + @@ -66,9 +66,9 @@ - + - + @@ -216,13 +216,13 @@ - + - + @@ -237,18 +237,18 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 2d7b17458e..2c81d100e4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -26,14 +26,11 @@ import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.JPanel; import javax.swing.KeyStroke; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; /* * The panel in the default Autopsy startup window. @@ -41,14 +38,11 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Cases" + " (" + LOCAL_HOST_NAME + ")"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. */ private static JDialog recentCasesWindow; - private static JDialog autoIngestCasePanelWindow; public static void closeOpenRecentCasesWindow() { if (null != recentCasesWindow) { @@ -56,15 +50,9 @@ public class CueBannerPanel extends javax.swing.JPanel { } } - public static void closeAutoIngestCasesWindow() { - if (null != autoIngestCasePanelWindow) { - autoIngestCasePanelWindow.setVisible(false); - } - } - public CueBannerPanel() { initComponents(); - customizeComponents(); + initRecentCasesWindow(); enableComponents(); } @@ -75,7 +63,7 @@ public class CueBannerPanel extends javax.swing.JPanel { ImageIcon icon = new ImageIcon(cl.getResource(welcomeLogo)); autopsyLogo.setIcon(icon); } - customizeComponents(); + initRecentCasesWindow(); enableComponents(); } @@ -90,11 +78,6 @@ public class CueBannerPanel extends javax.swing.JPanel { public void refresh() { enableComponents(); } - - private void customizeComponents() { - initRecentCasesWindow(); - initAutoIngestCasesWindow(); - } private void initRecentCasesWindow() { recentCasesWindow = new JDialog( @@ -118,39 +101,15 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.pack(); recentCasesWindow.setResizable(false); } - - private void initAutoIngestCasesWindow() { - autoIngestCasePanelWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - autoIngestCasePanelWindow.getRootPane().registerKeyboardAction( - e -> { - autoIngestCasePanelWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - OpenRecentCasePanel recentCasesPanel = OpenRecentCasePanel.getInstance(); - recentCasesPanel.setCloseButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - autoIngestCasePanelWindow.setVisible(false); - } - }); - AutoIngestCasePanelInterface autoIngestCasePanel = Lookup.getDefault().lookup(AutoIngestCasePanelInterface.class); - autoIngestCasePanel.addWindowStateListener(autoIngestCasePanelWindow); - autoIngestCasePanelWindow.add((JPanel)autoIngestCasePanel); - autoIngestCasePanelWindow.pack(); - autoIngestCasePanelWindow.setResizable(false); - } private void enableComponents() { boolean enableOpenRecentCaseButton = (RecentCases.getInstance().getTotalRecentCases() > 0); openRecentCaseButton.setEnabled(enableOpenRecentCaseButton); openRecentCaseLabel.setEnabled(enableOpenRecentCaseButton); - boolean showOpenAutoIngestCaseButton = (UserPreferences.getMode() == UserPreferences.SelectedMode.REVIEW); - openAutoIngestCaseButton.setVisible(showOpenAutoIngestCaseButton); - openAutoIngestCaseLabel.setVisible(showOpenAutoIngestCaseButton); + boolean enableOpenMultiUserCaseButton = UserPreferences.getIsMultiUserModeEnabled(); + openMultiUserCaseButton.setEnabled(enableOpenMultiUserCaseButton); + openMultiUserCaseLabel.setEnabled(enableOpenMultiUserCaseButton); } /** @@ -172,8 +131,8 @@ public class CueBannerPanel extends javax.swing.JPanel { openExistingCaseLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); jSeparator1 = new javax.swing.JSeparator(); - openAutoIngestCaseButton = new javax.swing.JButton(); - openAutoIngestCaseLabel = new javax.swing.JLabel(); + openMultiUserCaseButton = new javax.swing.JButton(); + openMultiUserCaseLabel = new javax.swing.JLabel(); autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N autopsyLogo.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.autopsyLogo.text")); // NOI18N @@ -229,21 +188,21 @@ public class CueBannerPanel extends javax.swing.JPanel { jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); - openAutoIngestCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N - openAutoIngestCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseButton.text")); // NOI18N - openAutoIngestCaseButton.setBorder(null); - openAutoIngestCaseButton.setBorderPainted(false); - openAutoIngestCaseButton.setContentAreaFilled(false); - openAutoIngestCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); - openAutoIngestCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); - openAutoIngestCaseButton.addActionListener(new java.awt.event.ActionListener() { + openMultiUserCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N + openMultiUserCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseButton.text")); // NOI18N + openMultiUserCaseButton.setBorder(null); + openMultiUserCaseButton.setBorderPainted(false); + openMultiUserCaseButton.setContentAreaFilled(false); + openMultiUserCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); + openMultiUserCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); + openMultiUserCaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - openAutoIngestCaseButtonActionPerformed(evt); + openMultiUserCaseButtonActionPerformed(evt); } }); - openAutoIngestCaseLabel.setFont(openAutoIngestCaseLabel.getFont().deriveFont(openAutoIngestCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); - openAutoIngestCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseLabel.text")); // NOI18N + openMultiUserCaseLabel.setFont(openMultiUserCaseLabel.getFont().deriveFont(openMultiUserCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); + openMultiUserCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -261,13 +220,13 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(createNewCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openRecentCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openExistingCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(createNewCaseLabel) .addComponent(openRecentCaseLabel) .addComponent(openExistingCaseLabel) - .addComponent(openAutoIngestCaseLabel))) + .addComponent(openMultiUserCaseLabel))) .addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -290,9 +249,9 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(openExistingCaseLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(openAutoIngestCaseLabel) + .addComponent(openMultiUserCaseLabel) .addGap(20, 20, 20)))) .addComponent(jSeparator1) .addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -316,10 +275,11 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.setVisible(true); }//GEN-LAST:event_openRecentCaseButtonActionPerformed - private void openAutoIngestCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openAutoIngestCaseButtonActionPerformed - autoIngestCasePanelWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - autoIngestCasePanelWindow.setVisible(true); - }//GEN-LAST:event_openAutoIngestCaseButtonActionPerformed + private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed + MultiUserCasesDialog multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel autopsyLogo; @@ -327,8 +287,8 @@ public class CueBannerPanel extends javax.swing.JPanel { private javax.swing.JButton createNewCaseButton; private javax.swing.JLabel createNewCaseLabel; private javax.swing.JSeparator jSeparator1; - private javax.swing.JButton openAutoIngestCaseButton; - private javax.swing.JLabel openAutoIngestCaseLabel; + private javax.swing.JButton openMultiUserCaseButton; + private javax.swing.JLabel openMultiUserCaseLabel; private javax.swing.JButton openExistingCaseButton; private javax.swing.JLabel openExistingCaseLabel; private javax.swing.JButton openRecentCaseButton; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/EditOptionalCasePropertiesPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/EditOptionalCasePropertiesPanel.form new file mode 100644 index 0000000000..c9f71e0b0e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/EditOptionalCasePropertiesPanel.form @@ -0,0 +1,70 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/EditOptionalCasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/EditOptionalCasePropertiesPanel.java new file mode 100644 index 0000000000..d1c726d3eb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/EditOptionalCasePropertiesPanel.java @@ -0,0 +1,128 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.event.ActionListener; +import org.openide.util.NbBundle.Messages; + +/** + * + * @author wschaefer + */ +class EditOptionalCasePropertiesPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + + private final OptionalCasePropertiesPanel propertiesPanel; + + /** + * Creates new form EditOptionalCasePropertiesPanel + */ + EditOptionalCasePropertiesPanel() { + initComponents(); + propertiesPanel = new OptionalCasePropertiesPanel(true); + + optionsPanel.add(propertiesPanel); + optionsPanel.setVisible(true); + propertiesPanel.setVisible(true); + } + + @Messages({ + "EditOptionalCasePropertiesPanel.saveButton.text=Save", + "EditOptionalCasePropertiesPanel.cancelButton.text=Cancel" + }) + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + optionsPanel = new javax.swing.JPanel(); + cancelButton = new javax.swing.JButton(); + saveButton = new javax.swing.JButton(); + + optionsPanel.setLayout(new java.awt.BorderLayout()); + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(EditOptionalCasePropertiesPanel.class, "EditOptionalCasePropertiesPanel.cancelButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(saveButton, org.openide.util.NbBundle.getMessage(EditOptionalCasePropertiesPanel.class, "EditOptionalCasePropertiesPanel.saveButton.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(254, Short.MAX_VALUE) + .addComponent(saveButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton) + .addContainerGap()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(optionsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, saveButton}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(266, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(saveButton)) + .addContainerGap()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(optionsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE) + .addGap(38, 38, 38))) + ); + }// //GEN-END:initComponents + + void saveProperties() { + this.propertiesPanel.saveUpdatedCaseDetails(); + } + + /** + * Adds an action listener to the Save button of the panel. + * + * @param action + */ + void addSaveButtonAction(ActionListener action) { + this.saveButton.addActionListener(action); + } + + /** + * Adds an action listener to the Cancel button of the panel. + * + * @param action + */ + void addCancelButtonAction(ActionListener action) { + this.cancelButton.addActionListener(action); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton cancelButton; + private javax.swing.JPanel optionsPanel; + private javax.swing.JButton saveButton; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java new file mode 100755 index 0000000000..d0baf94bc9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -0,0 +1,388 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Handles locating and opening multi-user cases. + */ +final class MultiUserCaseManager { + + private static final Logger LOGGER = Logger.getLogger(MultiUserCaseManager.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static MultiUserCaseManager instance; + private CoordinationService coordinationService; + + /** + * Gets the multi-user case manager. + * + * @return The multi-user case manager singleton. + * + * @throws MultiUserCaseManagerException + */ + synchronized static MultiUserCaseManager getInstance() throws MultiUserCaseManager.MultiUserCaseManagerException { + if (null == instance) { + instance = new MultiUserCaseManager(); + } + return instance; + } + + /** + * Constructs an object that handles locating and opening multi-user cases. + * + * @throws MultiUserCaseManagerException + */ + private MultiUserCaseManager() throws MultiUserCaseManagerException { + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationServiceException ex) { + throw new MultiUserCaseManager.MultiUserCaseManagerException("Failed to get the coordination service.", ex); + } + } + + /** + * Gets a list of the cases in the top level case folder + * + * @return List of cases. + * + * @throws CoordinationServiceException + */ + List getCases() throws CoordinationServiceException { + List cases = new ArrayList<>(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); + for (String node : nodeList) { + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if(caseFolder.exists()) { + File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); + if(autFiles != null && autFiles.length > 0) { + try { + CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFiles[0].getAbsolutePath())); + cases.add(new MultiUserCase(casePath, caseMetadata)); + } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFiles[0].getAbsolutePath()), ex); + } + } + } + } + return cases; + } + + /** + * Opens a multi-user case. + * + * @param caseMetadataFilePath Path to the case metadata file. + * + * @throws CaseActionException + */ + synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { + /* + * Open the case. + */ + Case.openAsCurrentCase(caseMetadataFilePath.toString()); + } + + /** + * Exception type thrown when there is an error completing a multi-user case + * manager operation. + */ + static final class MultiUserCaseManagerException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + */ + private MultiUserCaseManagerException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private MultiUserCaseManagerException(String message, Throwable cause) { + super(message, cause); + } + + } + + /** + * A representation of a multi-user case. + */ + static class MultiUserCase implements Comparable { + + private final Path caseDirectoryPath; + private final String caseDisplayName; + private final String metadataFileName; + private final Date createDate; + private final Date lastAccessedDate; + + /** + * Constructs a representation of a multi-user case + * + * @param caseDirectoryPath The case directory path. + * @param caseMetadata The case metadata. + * + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + MultiUserCase(Path caseDirectoryPath, CaseMetadata caseMetadata) throws MultiUserCaseException { + this.caseDirectoryPath = caseDirectoryPath; + caseDisplayName = caseMetadata.getCaseDisplayName(); + metadataFileName = caseMetadata.getFilePath().getFileName().toString(); + BasicFileAttributes fileAttrs = null; + try { + fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); + } + if (null != fileAttrs) { + createDate = new Date(fileAttrs.creationTime().toMillis()); + lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); + } else { + createDate = new Date(); + lastAccessedDate = new Date(); + } + } + + /** + * Gets the case directory path. + * + * @return The case directory path. + */ + Path getCaseDirectoryPath() { + return this.caseDirectoryPath; + } + + /** + * Gets the case display name. This may differ from the name supplied to the + * directory or metadata file names if a case has been renamed. + * + * @return The case display name. + */ + String getCaseDisplayName() { + return this.caseDisplayName; + } + + /** + * Gets the creation date for the case, defined as the create time of the + * case metadata file. + * + * @return The case creation date. + */ + Date getCreationDate() { + return this.createDate; + } + + /** + * Gets the last accessed date for the case, defined as the last accessed + * time of the case metadata file. + * + * @return The last accessed date. + */ + Date getLastAccessedDate() { + return this.lastAccessedDate; + } + + /** + * Gets metadata (.aut) file name. + * + * @return The metadata file name. + */ + String getMetadataFileName() { + return this.metadataFileName; + } + + /** + * Gets the status of this case based on the auto ingest result file in the + * case directory. + * + * @return See CaseStatus enum definition. + */ + CaseStatus getStatus() { + if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { + return CaseStatus.ALERT; + } else { + return CaseStatus.OK; + } + } + + /** + * Gets the case metadata from a case directory path. + * + * @param caseDirectoryPath The case directory path. + * + * @return Case metadata. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + private CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + File directory = new File(caseDirectoryPath.toString()); + if (directory.isDirectory()) { + File autFile = null; + + /* + * Attempt to find an AUT file via a directory scan. + */ + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; + } + } + + if(autFile == null || !autFile.isFile()) { + throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); + } + + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); + } + + return caseMetadata; + } + + /** + * Indicates whether or not some other object is "equal to" this + * MultiUserCase object. + * + * @param other The other object. + * + * @return True or false. + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof MultiUserCase)) { + return false; + } + if (other == this) { + return true; + } + return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); + } + + /** + * Returns a hash code value for this MultiUserCase object. + * + * @return The has code. + */ + @Override + public int hashCode() { + int hash = 7; + hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); + hash = 71 * hash + Objects.hashCode(this.createDate); + hash = 71 * hash + Objects.hashCode(this.caseDisplayName); + return hash; + } + + /** + * Compares this MultiUserCase object with another MultiUserCase object + * for order. + */ + @Override + public int compareTo(MultiUserCase other) { + return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); + } + + /** + * Comparator for a descending order sort on date created. + */ + static class LastAccessedDateDescendingComparator implements Comparator { + + /** + * Compares two MultiUserCase objects for order based on last accessed + * date (descending). + * + * @param object The first MultiUserCase object + * @param otherObject The second MultiUserCase object. + * + * @return A negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + @Override + public int compare(MultiUserCase object, MultiUserCase otherObject) { + return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); + } + } + + /** + * Exception thrown when there is a problem creating a multi-user case. + */ + final class MultiUserCaseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + */ + private MultiUserCaseException(String message) { + super(message); + } + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + * @param cause The cause of the exception, if it was an exception. + */ + private MultiUserCaseException(String message, Throwable cause) { + super(message, cause); + } + } + + } + + static enum CaseStatus { + OK, + ALERT + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java new file mode 100755 index 0000000000..8c90aeccb4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java @@ -0,0 +1,89 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.Dialog; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +import org.openide.windows.WindowManager; + +/** + * This class extends a JDialog and maintains the MultiUserCasesPanel. + */ +final class MultiUserCasesDialog extends JDialog { + + private static final long serialVersionUID = 1L; + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; + private static MultiUserCasesPanel multiUserCasesPanel; + private static MultiUserCasesDialog instance; + + /** + * Gets the instance of the MultiuserCasesDialog. + * + * @return The instance. + */ + static public MultiUserCasesDialog getInstance() { + if(instance == null) { + instance = new MultiUserCasesDialog(); + instance.init(); + } + return instance; + } + + /** + * Constructs a MultiUserCasesDialog object. + */ + private MultiUserCasesDialog() { + super(WindowManager.getDefault().getMainWindow(), + REVIEW_MODE_TITLE, + Dialog.ModalityType.APPLICATION_MODAL); + } + + /** + * Initializes the multi-user cases panel. + */ + private void init() { + getRootPane().registerKeyboardAction( + e -> { + setVisible(false); + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + multiUserCasesPanel = new MultiUserCasesPanel(this); + add(multiUserCasesPanel); + pack(); + setResizable(false); + } + + /** + * Set the dialog visibility. When setting it to visible, the contents will + * refresh. + * + * @param value True or false. + */ + @Override + public void setVisible(boolean value) { + if(value) { + multiUserCasesPanel.refresh(); + } + super.setVisible(value); + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form similarity index 84% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form index cb0f275809..179bc23bb8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form @@ -45,7 +45,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -165,10 +165,10 @@ - + - + @@ -182,7 +182,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -222,7 +222,7 @@ - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java similarity index 64% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 2bcd335916..7e87ce8947 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -16,52 +16,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; import java.awt.Desktop; -import java.awt.EventQueue; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import javax.swing.JDialog; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import org.sleuthkit.autopsy.casemodule.MultiUserCaseManager.MultiUserCase; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; -import org.sleuthkit.autopsy.casemodule.CueBannerPanel; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; -import org.sleuthkit.autopsy.experimental.configuration.StartupWindow; +import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A panel that allows a user to open cases created by auto ingest. */ -@ServiceProvider(service = AutoIngestCasePanelInterface.class) -public final class AutoIngestCasePanel extends JPanel implements AutoIngestCasePanelInterface { +final class MultiUserCasesPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(AutoIngestCasePanel.class.getName()); - private static final AutoIngestCase.LastAccessedDateDescendingComparator reverseDateModifiedComparator = new AutoIngestCase.LastAccessedDateDescendingComparator(); + private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static final MultiUserCaseManager.MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCaseManager.MultiUserCase.LastAccessedDateDescendingComparator(); private static final int CASE_COL_MIN_WIDTH = 30; private static final int CASE_COL_MAX_WIDTH = 2000; private static final int CASE_COL_PREFERRED_WIDTH = 300; @@ -71,9 +57,6 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private static final int STATUS_COL_MIN_WIDTH = 55; private static final int STATUS_COL_MAX_WIDTH = 250; private static final int STATUS_COL_PREFERRED_WIDTH = 60; - private static final int MILLIS_TO_WAIT_BEFORE_STARTING = 500; - private static final int MILLIS_TO_WAIT_BETWEEN_UPDATES = 300000; - private ScheduledThreadPoolExecutor casesTableRefreshExecutor; /* * The JTable table model for the cases table presented by this view is @@ -82,11 +65,12 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * TODO (RC): Consider unifying this stuff in an enum as in * AutoIngestDashboard to make it less error prone. */ - private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CaseHeaderText"); + private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); + private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); + private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); + private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String METADATA_FILE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.MetadataFileHeaderText"); enum COLUMN_HEADERS { @@ -94,51 +78,20 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP CREATEDTIME, COMPLETEDTIME, STATUS_ICON, - OUTPUTFOLDER + OUTPUTFOLDER, + METADATA_FILE } - private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; + private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER, METADATA_FILE_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; - - public AutoIngestCasePanel() { - init(null); - } - - @Override - public void addWindowStateListener(JDialog parent) { - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } + private JDialog parentDialog; /** * Constructs a panel that allows a user to open cases created by automated * ingest. - * - * @param parent The parent dialog for this panel. */ - public AutoIngestCasePanel(JDialog parent) { - init(parent); - } - - public void init(JDialog parent) { + MultiUserCasesPanel(JDialog parentDialog) { + this.parentDialog = parentDialog; caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -146,6 +99,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP public boolean isCellEditable(int row, int column) { return false; } + @Override public Class getColumnClass(int col) { if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { @@ -184,13 +138,14 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); theColumn = casesTable.getColumn(STATUS_ICON_HEADER); - theColumn.setCellRenderer(new CaseStatusIconCellRenderer()); + theColumn.setCellRenderer(new StatusIconCellRenderer()); theColumn.setMinWidth(STATUS_COL_MIN_WIDTH); theColumn.setMaxWidth(STATUS_COL_MAX_WIDTH); theColumn.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); + casesTable.removeColumn(casesTable.getColumn(METADATA_FILE_HEADER)); /* * Listen for row selection changes and set button state for the current @@ -203,75 +158,39 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP } setButtons(); }); - - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - if (parent != null) { - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } - } - - /** - * Start doing periodic refreshes of the cases table. - */ - private void startCasesTableRefreshes() { - if (null == casesTableRefreshExecutor) { - casesTableRefreshExecutor = new ScheduledThreadPoolExecutor(1); - this.casesTableRefreshExecutor.scheduleAtFixedRate(() -> { - refreshCasesTable(); - }, MILLIS_TO_WAIT_BEFORE_STARTING, MILLIS_TO_WAIT_BETWEEN_UPDATES, TimeUnit.MILLISECONDS); - } - } - - /** - * Stop doing periodic refreshes of the cases table. - */ - private void stopCasesTableRefreshes() { - if (null != casesTableRefreshExecutor) { - casesTableRefreshExecutor.shutdown(); - } - this.casesTableRefreshExecutor = null; - } - - /* - * Updates the view presented by the panel. - */ - public void updateView() { - Thread thread = new Thread(() -> { - refreshCasesTable(); - }); - thread.start(); } /** * Gets the list of cases known to the review mode cases manager and * refreshes the cases table. */ - private void refreshCasesTable() { + void refresh() { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { currentlySelectedCase = getSelectedCase(); - AutoIngestCaseManager manager = AutoIngestCaseManager.getInstance(); - List theModel = manager.getCases(); - EventQueue.invokeLater(new CaseTableRefreshTask(theModel)); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseDisplayName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCaseManager.CaseStatus.OK != autoIngestCase.getStatus()) ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, + autoIngestCase.getCaseDirectoryPath().toString(), + autoIngestCase.getMetadataFileName()}); + } + } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (MultiUserCaseManager.MultiUserCaseManagerException | CoordinationService.CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } finally { + setCursor(null); } } @@ -320,103 +239,78 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * in the cases table. */ private void setButtons() { - boolean enabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); - bnOpen.setEnabled(enabled); - bnShowLog.setEnabled(enabled); + boolean openEnabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); + bnOpen.setEnabled(openEnabled); + + Path pathToLog = getSelectedCaseLogFilePath(); + boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); + bnShowLog.setEnabled(showLogEnabled); } /** - * Opens a case. + * Retrieves the log file path for the selected case in the cases table. + * + * @return The case log path. + */ + private Path getSelectedCaseLogFilePath() { + Path retValue = null; + + int selectedRow = casesTable.getSelectedRow(); + int rowCount = casesTable.getRowCount(); + if (selectedRow >= 0 && selectedRow < rowCount) { + String caseDirectory = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + retValue = Paths.get(caseDirectory, LOG_FILE_NAME); + } + + return retValue; + } + + /** + * Open a case. * * @param caseMetadataFilePath The path to the case metadata file. */ private void openCase(Path caseMetadataFilePath) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - AutoIngestCaseManager.getInstance().openCase(caseMetadataFilePath); - stopCasesTableRefreshes(); - StartupWindowProvider.getInstance().close(); - CueBannerPanel.closeAutoIngestCasesWindow(); - return null; + try { + StartupWindowProvider.getInstance().close(); + if (parentDialog != null) { + parentDialog.setVisible(false); } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - 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 - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - StartupWindowProvider.getInstance().open(); - } finally { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } + MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); + } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { + 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 + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); } - }.execute(); + StartupWindowProvider.getInstance().open(); + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } } /** - * A task that refreshes the cases table using a list of auto ingest cases. + * Indicates whether or not a time satisfies a time filter defined by this + * panel's time filter radio buttons. + * + * @param currentTime The current date and time in milliseconds from the + * Unix epoch. + * @param inputTime The date and time to be tested as milliseconds from + * the Unix epoch. */ - private class CaseTableRefreshTask implements Runnable { - - private final List cases; - - CaseTableRefreshTask(List cases) { - setButtons(); - this.cases = cases; + private boolean passesTimeFilter(long currentTime, long inputTime) { + long numberOfUnits = 10; + long multiplier = 1; + if (rbAllCases.isSelected()) { + return true; + } else if (rbMonths.isSelected()) { + multiplier = 31; + } else if (rbWeeks.isSelected()) { + multiplier = 7; + } else if (rbDays.isSelected()) { + multiplier = 1; } - - /** - * @inheritDoc - */ - @Override - public void run() { - cases.sort(reverseDateModifiedComparator); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (AutoIngestCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (AutoIngestCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString()}); - } - } - setSelectedCase(currentlySelectedCase); - } - - /** - * Indicates whether or not a time satisfies a time filter defined by - * this panel's time filter radio buttons. - * - * @param currentTime The current date and time in milliseconds from the - * Unix epoch. - * @param inputTime The date and time to be tested as milliseconds - * from the Unix epoch. - */ - private boolean passesTimeFilter(long currentTime, long inputTime) { - long numberOfUnits = 10; - long multiplier = 1; - if (rbAllCases.isSelected()) { - return true; - } else if (rbMonths.isSelected()) { - multiplier = 31; - } else if (rbWeeks.isSelected()) { - multiplier = 7; - } else if (rbDays.isSelected()) { - multiplier = 1; - } - return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); - } - + return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); } /** @@ -443,7 +337,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP setName("Completed Cases"); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnOpen.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpen.text")); // NOI18N bnOpen.setEnabled(false); bnOpen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -463,7 +357,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); scrollPaneTable.setViewportView(casesTable); - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnRefresh.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnRefresh.text")); // NOI18N bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -472,7 +366,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP rbGroupHistoryLength.add(rbAllCases); rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbAllCases.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbAllCases.text")); // NOI18N rbAllCases.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbAllCasesItemStateChanged(evt); @@ -494,8 +388,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addComponent(rbAllCases)) ); - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.toolTipText")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.text")); // NOI18N + bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.toolTipText")); // NOI18N bnShowLog.setEnabled(false); bnShowLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -504,7 +398,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbDays.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbDays.text")); // NOI18N rbDays.setName(""); // NOI18N rbDays.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { @@ -513,7 +407,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbWeeks.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbWeeks.text")); // NOI18N rbWeeks.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbWeeksItemStateChanged(evt); @@ -521,7 +415,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbMonths.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbMonths.text")); // NOI18N rbMonths.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbMonthsItemStateChanged(evt); @@ -529,7 +423,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbGroupLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbGroupLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -556,7 +450,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(bnRefresh) .addGap(4, 4, 4)) - .addComponent(scrollPaneTable, javax.swing.GroupLayout.DEFAULT_SIZE, 1007, Short.MAX_VALUE)) + .addComponent(scrollPaneTable)) .addContainerGap()) ); layout.setVerticalGroup( @@ -588,10 +482,12 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP */ private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); - openCase(caseMetadataFilePath); + String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); + + new Thread(() -> { + openCase(caseMetadataFilePath); + }).start(); }//GEN-LAST:event_bnOpenActionPerformed /** @@ -599,53 +495,50 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * * @param evt -- The event that caused this to be called */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bnRefreshActionPerformed - {//GEN-HEADEREND:event_bnRefreshActionPerformed - updateView(); - }//GEN-LAST:event_bnRefreshActionPerformed + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { + refresh(); + } - private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbDaysItemStateChanged + private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { if (rbDays.isSelected()) { - updateView(); + refresh(); } - }//GEN-LAST:event_rbDaysItemStateChanged + } private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged if (rbAllCases.isSelected()) { - updateView(); + refresh(); } }//GEN-LAST:event_rbAllCasesItemStateChanged private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged if (rbMonths.isSelected()) { - updateView(); + refresh(); } }//GEN-LAST:event_rbMonthsItemStateChanged private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged if (rbWeeks.isSelected()) { - updateView(); + refresh(); } }//GEN-LAST:event_rbWeeksItemStateChanged private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed - int selectedRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - int rowCount = casesTable.getRowCount(); - if (selectedRow >= 0 && selectedRow < rowCount) { - String thePath = (String) caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - Path pathToLog = AutoIngestJobLogger.getLogPath(Paths.get(thePath)); + Path pathToLog = getSelectedCaseLogFilePath(); + if (pathToLog != null) { try { if (pathToLog.toFile().exists()) { Desktop.getDesktop().edit(pathToLog.toFile()); + } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); } } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); + LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.PLAIN_MESSAGE); } } @@ -654,9 +547,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked if (evt.getClickCount() == 2) { int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); + String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); openCase(caseMetadataFilePath); } }//GEN-LAST:event_casesTableMouseClicked diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form index 72b0a6cb9b..5eb64d5756 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.form @@ -29,10 +29,6 @@ - - - - @@ -49,7 +45,7 @@ - + @@ -72,9 +68,7 @@ - - - + @@ -97,24 +91,12 @@ - + - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index d3f19f872c..d736aae980 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -202,7 +202,6 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { private void initComponents() { caseTypeButtonGroup = new javax.swing.ButtonGroup(); - jLabel1 = new javax.swing.JLabel(); caseNameLabel = new javax.swing.JLabel(); caseDirLabel = new javax.swing.JLabel(); caseNameTextField = new javax.swing.JTextField(); @@ -215,9 +214,6 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { caseParentDirWarningLabel = new javax.swing.JLabel(); caseTypeLabel = new javax.swing.JLabel(); - jLabel1.setFont(jLabel1.getFont().deriveFont(jLabel1.getFont().getStyle() | java.awt.Font.BOLD, 14)); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N - caseNameLabel.setFont(caseNameLabel.getFont().deriveFont(caseNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(caseNameLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseNameLabel.text_1")); // NOI18N @@ -283,9 +279,6 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(jLabel1) - .addGap(0, 227, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addComponent(caseNameLabel) .addGap(26, 26, 26) @@ -300,7 +293,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { .addComponent(singleUserCaseRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(multiUserCaseRadioButton) - .addGap(0, 0, Short.MAX_VALUE)) + .addGap(0, 192, Short.MAX_VALUE)) .addComponent(caseParentDirTextField)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(caseDirBrowseButton))) @@ -312,9 +305,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(31, 31, 31) - .addComponent(jLabel1) - .addGap(18, 18, 18) + .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(caseNameLabel) .addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -334,7 +325,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { .addComponent(caseDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(27, 27, 27) .addComponent(caseParentDirWarningLabel) - .addContainerGap(21, Short.MAX_VALUE)) + .addContainerGap(115, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -377,7 +368,6 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { private javax.swing.JLabel caseParentDirWarningLabel; private javax.swing.ButtonGroup caseTypeButtonGroup; private javax.swing.JLabel caseTypeLabel; - private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JRadioButton multiUserCaseRadioButton; private javax.swing.JRadioButton singleUserCaseRadioButton; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.form b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.form index fcce5c4033..1acb2b02db 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.form @@ -11,110 +11,8 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java index e20fce9aea..2098fc91b3 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel2.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. + * + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit 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. @@ -17,7 +17,7 @@ * limitations under the License. */ -/* + /* * NewCaseVisualPanel2.java * * Created on Mar 7, 2012, 11:01:48 AM @@ -26,19 +26,25 @@ package org.sleuthkit.autopsy.casemodule; import org.openide.util.NbBundle; -import java.awt.*; - /** * * @author dfickling */ -class NewCaseVisualPanel2 extends javax.swing.JPanel { +final class NewCaseVisualPanel2 extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + + private final OptionalCasePropertiesPanel propertiesPanel; /** * Creates new form NewCaseVisualPanel2 */ - public NewCaseVisualPanel2() { + NewCaseVisualPanel2() { initComponents(); + propertiesPanel = new OptionalCasePropertiesPanel(); + this.add(propertiesPanel); + propertiesPanel.setVisible(true); + } /** @@ -61,75 +67,61 @@ class NewCaseVisualPanel2 extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - caseNumberTextField = new javax.swing.JTextField(); - examinerTextField = new javax.swing.JTextField(); - caseNumberLabel = new javax.swing.JLabel(); - examinerLabel = new javax.swing.JLabel(); - optionalLabel = new javax.swing.JLabel(); - - caseNumberTextField.setFont(caseNumberTextField.getFont().deriveFont(caseNumberTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - caseNumberTextField.setText(org.openide.util.NbBundle.getMessage(NewCaseVisualPanel2.class, "NewCaseVisualPanel2.caseNumberTextField.text")); // NOI18N - - examinerTextField.setFont(examinerTextField.getFont().deriveFont(examinerTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - examinerTextField.setText(org.openide.util.NbBundle.getMessage(NewCaseVisualPanel2.class, "NewCaseVisualPanel2.examinerTextField.text")); // NOI18N - - caseNumberLabel.setFont(caseNumberLabel.getFont().deriveFont(caseNumberLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - caseNumberLabel.setText(org.openide.util.NbBundle.getMessage(NewCaseVisualPanel2.class, "NewCaseVisualPanel2.caseNumberLabel.text")); // NOI18N - - examinerLabel.setFont(examinerLabel.getFont().deriveFont(examinerLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - examinerLabel.setText(org.openide.util.NbBundle.getMessage(NewCaseVisualPanel2.class, "NewCaseVisualPanel2.examinerLabel.text")); // NOI18N - - optionalLabel.setFont(optionalLabel.getFont().deriveFont(optionalLabel.getFont().getStyle() | java.awt.Font.BOLD, 14)); - optionalLabel.setText(org.openide.util.NbBundle.getMessage(NewCaseVisualPanel2.class, "NewCaseVisualPanel2.optionalLabel.text")); // NOI18N - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(optionalLabel) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(caseNumberLabel) - .addGap(25, 25, 25) - .addComponent(caseNumberTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(examinerLabel) - .addGap(45, 45, 45) - .addComponent(examinerTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE))) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(optionalLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(caseNumberLabel) - .addComponent(caseNumberTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(examinerLabel) - .addComponent(examinerTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); + setLayout(new java.awt.BorderLayout()); }// //GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel caseNumberLabel; - private javax.swing.JTextField caseNumberTextField; - private javax.swing.JLabel examinerLabel; - private javax.swing.JTextField examinerTextField; - private javax.swing.JLabel optionalLabel; - // End of variables declaration//GEN-END:variables + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables String getCaseNumber() { - return caseNumberTextField.getText(); + return propertiesPanel.getCaseNumber(); } - String getExaminer() { - return examinerTextField.getText(); + String getExaminerName() { + return propertiesPanel.getExaminerName(); + } + + String getExaminerPhone() { + return propertiesPanel.getExaminerPhone(); + } + + String getExaminerEmail() { + return propertiesPanel.getExaminerEmail(); + } + + String getCaseNotes() { + return propertiesPanel.getCaseNotes(); + } + + String getOrganization() { + return propertiesPanel.getOrganization(); + } + + void setCaseNumber(String caseNumber) { + propertiesPanel.setCaseNumberField(caseNumber); + } + + void setExaminerName(String examinerName) { + propertiesPanel.setExaminerNameField(examinerName); + } + + void setExaminerPhone(String examinerPhone) { + propertiesPanel.setExaminerPhoneField(examinerPhone); + } + + void setExaminerEmail(String examinerEmail) { + propertiesPanel.setExaminerEmailField(examinerEmail); + } + + void setCaseNotes(String caseNotes) { + propertiesPanel.setCaseNotesField(caseNotes); + } + + void setOrganization(String organizationName) { + propertiesPanel.setCurrentlySelectedOrganization(organizationName); + } + + void refreshCaseDetailsFields() { + propertiesPanel.setUpCaseDetailsFields(); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java index 3679587491..7a4a1f7bf4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java @@ -37,6 +37,10 @@ import org.openide.util.actions.SystemAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.IngestRunningCheck; import org.sleuthkit.autopsy.casemodule.Case.CaseType; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; @@ -75,11 +79,32 @@ final class NewCaseWizardAction extends CallableSystemAction { @Override protected Void doInBackground() throws Exception { String caseNumber = (String) wizardDescriptor.getProperty("caseNumber"); //NON-NLS - String examiner = (String) wizardDescriptor.getProperty("caseExaminer"); //NON-NLS + String examinerName = (String) wizardDescriptor.getProperty("caseExaminerName"); //NON-NLS + String examinerPhone = (String) wizardDescriptor.getProperty("caseExaminerPhone"); //NON-NLS + String examinerEmail = (String) wizardDescriptor.getProperty("caseExaminerEmail"); //NON-NLS + String caseNotes = (String) wizardDescriptor.getProperty("caseNotes"); //NON-NLS + String organizationName = (String) wizardDescriptor.getProperty("caseOrganization"); //NON-NLS final String caseName = (String) wizardDescriptor.getProperty("caseName"); //NON-NLS String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS CaseType caseType = CaseType.values()[(int) wizardDescriptor.getProperty("caseType")]; //NON-NLS - Case.createAsCurrentCase(createdDirectory, caseName, caseNumber, examiner, caseType); + Case.createAsCurrentCase(caseType, createdDirectory, new CaseDetails(caseName, caseNumber, examinerName, examinerPhone, examinerEmail, caseNotes)); + if (EamDb.isEnabled()) { //if the eam is enabled we need to save the case organization information now + EamDb dbManager = EamDb.getInstance(); + if (dbManager != null) { + CorrelationCase cRCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + if (cRCase == null) { + cRCase = dbManager.newCase(Case.getCurrentCase()); + } + if (!organizationName.isEmpty()) { + for (EamOrganization org : dbManager.getOrganizations()) { + if (org.getName().equals(organizationName)) { + cRCase.setOrg(org); + dbManager.updateCase(cRCase); + } + } + } + } + } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java index d8888a8865..7752611202 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel2.java @@ -28,12 +28,22 @@ import org.openide.WizardValidationException; import org.openide.util.HelpCtx; import org.openide.windows.WindowManager; import java.awt.Cursor; +import java.util.logging.Level; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * The second panel of the New Case wizard. */ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel { + private static final Logger logger = Logger.getLogger(NewCaseWizardPanel2.class.getName()); + private static final String PROP_EXAMINER_NAME = "LBL_EXAMINER_NAME"; //NON-NLS + private static final String PROP_EXAMINER_PHONE = "LBL_EXAMINER_PHONE"; //NON-NLS + private static final String PROP_EXAMINER_EMAIL = "LBL_EXAMINER_EMAIL"; //NON-NLS + private static final String PROP_CASE_NOTES = "LBL_CASE_NOTES"; //NON-NLS + private static final String PROP_ORGANIZATION_NAME = "LBL_ORGANIZATION_NAME"; //NON-NLS private NewCaseVisualPanel2 component; private final Set listeners = new HashSet<>(1); @@ -46,7 +56,10 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java new file mode 100644 index 0000000000..a2793ec295 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java @@ -0,0 +1,609 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.Cursor; +import java.util.logging.Level; +import javax.swing.JComboBox; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; + +/** + * Panel which allows for editing and setting of the case details which are + * optional or otherwise able to be edited. + */ +final class OptionalCasePropertiesPanel extends javax.swing.JPanel { + + private final static Logger LOGGER = Logger.getLogger(OptionalCasePropertiesPanel.class.getName()); + private static final long serialVersionUID = 1L; + private EamOrganization selectedOrg = null; + private java.util.List orgs = null; + + /** + * Creates new form OptionalCasePropertiesPanel + */ + OptionalCasePropertiesPanel() { + initComponents(); + caseDisplayNameLabel.setVisible(false); + caseDisplayNameTextField.setVisible(false); + lbPointOfContactNameLabel.setVisible(false); + lbPointOfContactNameText.setVisible(false); + lbPointOfContactPhoneLabel.setVisible(false); + lbPointOfContactPhoneText.setVisible(false); + lbPointOfContactEmailLabel.setVisible(false); + lbPointOfContactEmailText.setVisible(false); + setUpCaseDetailsFields(); + } + + OptionalCasePropertiesPanel(boolean editCurrentCase) { + initComponents(); + if (editCurrentCase) { + caseDisplayNameTextField.setText(Case.getCurrentCase().getDisplayName()); + caseNumberTextField.setText(Case.getCurrentCase().getNumber()); + examinerTextField.setText(Case.getCurrentCase().getExaminer()); + tfExaminerEmailText.setText(Case.getCurrentCase().getExaminerEmail()); + tfExaminerPhoneText.setText(Case.getCurrentCase().getExaminerPhone()); + taNotesText.setText(Case.getCurrentCase().getCaseNotes()); + setUpCaseDetailsFields(); + setUpOrganizationData(); + } else { + caseDisplayNameLabel.setVisible(false); + caseDisplayNameTextField.setVisible(false); + lbPointOfContactNameLabel.setVisible(false); + lbPointOfContactNameText.setVisible(false); + lbPointOfContactPhoneLabel.setVisible(false); + lbPointOfContactPhoneText.setVisible(false); + lbPointOfContactEmailLabel.setVisible(false); + lbPointOfContactEmailText.setVisible(false); + setUpCaseDetailsFields(); + } + + } + + private void setUpOrganizationData() { + if (EamDb.isEnabled()) { + Case currentCase = Case.getCurrentCase(); + if (currentCase != null) { + try { + EamDb dbManager = EamDb.getInstance(); + selectedOrg = dbManager.getCaseByUUID(currentCase.getName()).getOrg(); + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex); + } + } + if (selectedOrg != null) { + setCurrentlySelectedOrganization(selectedOrg.getName()); + } + } + } + + void setUpCaseDetailsFields() { + boolean cREnabled = EamDb.isEnabled(); + comboBoxOrgName.setEnabled(cREnabled); + bnNewOrganization.setEnabled(cREnabled); + lbPointOfContactNameText.setEnabled(cREnabled); + lbPointOfContactEmailText.setEnabled(cREnabled); + lbPointOfContactPhoneText.setEnabled(cREnabled); + lbOrganizationNameLabel.setEnabled(cREnabled); + lbPointOfContactNameLabel.setEnabled(cREnabled); + lbPointOfContactEmailLabel.setEnabled(cREnabled); + lbPointOfContactPhoneLabel.setEnabled(cREnabled); + orgainizationPanel.setEnabled(cREnabled); + if (!cREnabled) { + clearOrganization(); + } else { + loadOrganizationData(); + } + + } + + private void loadOrganizationData() { + Object selectedBeforeLoad = comboBoxOrgName.getSelectedItem(); + comboBoxOrgName.removeAllItems(); + try { + comboBoxOrgName.addItem(""); // for when a case has a null Org + EamDb dbManager = EamDb.getInstance(); + orgs = dbManager.getOrganizations(); + orgs.forEach((org) -> { + comboBoxOrgName.addItem(org.getName()); + }); + comboBoxOrgName.setSelectedItem(selectedBeforeLoad); + } catch (EamDbException ex) { + LOGGER.log(Level.WARNING, "Unable to populate list of Organizations from Central Repo", ex); + } + } + + private void clearOrganization() { + selectedOrg = null; + lbPointOfContactNameText.setText(""); + lbPointOfContactEmailText.setText(""); + lbPointOfContactPhoneText.setText(""); + } + + String getCaseNumber() { + return caseNumberTextField.getText(); + } + + String getExaminerName() { + return examinerTextField.getText(); + } + + String getExaminerPhone() { + return tfExaminerPhoneText.getText(); + } + + String getExaminerEmail() { + return tfExaminerEmailText.getText(); + } + + String getCaseNotes() { + return taNotesText.getText(); + } + + String getOrganization() { + if (selectedOrg != null) { + return selectedOrg.getName(); + } else { + return ""; + } + } + + void setCaseNumberField(String caseNumber) { + caseNumberTextField.setText(caseNumber == null ? "" : caseNumber); + } + + void setExaminerNameField(String examinerName) { + examinerTextField.setText(examinerName == null ? "" : examinerName); + } + + void setExaminerPhoneField(String examinerPhone) { + tfExaminerPhoneText.setText(examinerPhone == null ? "" : examinerPhone); + } + + void setExaminerEmailField(String examinerEmail) { + tfExaminerEmailText.setText(examinerEmail == null ? "" : examinerEmail); + } + + void setCaseNotesField(String caseNotes) { + taNotesText.setText(caseNotes == null ? "" : caseNotes); + } + + @Messages({"OptionalCasePropertiesPanel.caseDisplayNameLabel.text=Name:", + "OptionalCasePropertiesPanel.lbPointOfContactEmailLabel.text=Email:", + "OptionalCasePropertiesPanel.lbOrganizationNameLabel.text=Organization analysis is being done for:", + "OptionalCasePropertiesPanel.bnNewOrganization.text=Manage Organizations", + "OptionalCasePropertiesPanel.lbPointOfContactNameLabel.text=Point of Contact:", + "OptionalCasePropertiesPanel.lbPointOfContactPhoneLabel.text=Phone:", + "OptionalCasePropertiesPanel.orgainizationPanel.border.title=Organization", + "OptionalCasePropertiesPanel.lbNotesLabel.text=Notes:", + "OptionalCasePropertiesPanel.examinerLabel.text=Name:", + "OptionalCasePropertiesPanel.lbExaminerEmailLabel.text=Email:", + "OptionalCasePropertiesPanel.lbExaminerPhoneLabel.text=Phone:", + "OptionalCasePropertiesPanel.examinerPanel.border.title=Examiner", + "OptionalCasePropertiesPanel.caseNumberLabel.text=Number:", + "OptionalCasePropertiesPanel.casePanel.border.title=Case" + }) + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + casePanel = new javax.swing.JPanel(); + caseNumberLabel = new javax.swing.JLabel(); + caseNumberTextField = new javax.swing.JTextField(); + caseDisplayNameLabel = new javax.swing.JLabel(); + caseDisplayNameTextField = new javax.swing.JTextField(); + examinerPanel = new javax.swing.JPanel(); + tfExaminerPhoneText = new javax.swing.JTextField(); + lbExaminerPhoneLabel = new javax.swing.JLabel(); + caseNotesScrollPane = new javax.swing.JScrollPane(); + taNotesText = new javax.swing.JTextArea(); + tfExaminerEmailText = new javax.swing.JTextField(); + examinerTextField = new javax.swing.JTextField(); + lbExaminerEmailLabel = new javax.swing.JLabel(); + examinerLabel = new javax.swing.JLabel(); + lbNotesLabel = new javax.swing.JLabel(); + orgainizationPanel = new javax.swing.JPanel(); + lbPointOfContactPhoneLabel = new javax.swing.JLabel(); + comboBoxOrgName = new javax.swing.JComboBox<>(); + lbPointOfContactNameLabel = new javax.swing.JLabel(); + bnNewOrganization = new javax.swing.JButton(); + lbPointOfContactEmailText = new javax.swing.JLabel(); + lbPointOfContactNameText = new javax.swing.JLabel(); + lbOrganizationNameLabel = new javax.swing.JLabel(); + lbPointOfContactEmailLabel = new javax.swing.JLabel(); + lbPointOfContactPhoneText = new javax.swing.JLabel(); + + casePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.casePanel.border.title"))); // NOI18N + + caseNumberLabel.setFont(caseNumberLabel.getFont().deriveFont(caseNumberLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(caseNumberLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.caseNumberLabel.text")); // NOI18N + caseNumberLabel.setMaximumSize(new java.awt.Dimension(41, 14)); + caseNumberLabel.setMinimumSize(new java.awt.Dimension(41, 14)); + caseNumberLabel.setPreferredSize(new java.awt.Dimension(41, 14)); + + caseNumberTextField.setFont(caseNumberTextField.getFont().deriveFont(caseNumberTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + + caseDisplayNameLabel.setFont(caseDisplayNameLabel.getFont().deriveFont(caseDisplayNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(caseDisplayNameLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.caseDisplayNameLabel.text")); // NOI18N + caseDisplayNameLabel.setMaximumSize(new java.awt.Dimension(41, 14)); + caseDisplayNameLabel.setMinimumSize(new java.awt.Dimension(41, 14)); + caseDisplayNameLabel.setPreferredSize(new java.awt.Dimension(41, 14)); + caseDisplayNameLabel.setVerifyInputWhenFocusTarget(false); + + caseDisplayNameTextField.setFont(caseDisplayNameTextField.getFont().deriveFont(caseDisplayNameTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + + javax.swing.GroupLayout casePanelLayout = new javax.swing.GroupLayout(casePanel); + casePanel.setLayout(casePanelLayout); + casePanelLayout.setHorizontalGroup( + casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(caseDisplayNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(caseNumberLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(caseDisplayNameTextField) + .addComponent(caseNumberTextField)) + .addContainerGap()) + ); + casePanelLayout.setVerticalGroup( + casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(casePanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(caseDisplayNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseDisplayNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(casePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(caseNumberLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseNumberTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6)) + ); + + examinerPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.examinerPanel.border.title"))); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(lbExaminerPhoneLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbExaminerPhoneLabel.text")); // NOI18N + lbExaminerPhoneLabel.setMaximumSize(new java.awt.Dimension(41, 14)); + lbExaminerPhoneLabel.setMinimumSize(new java.awt.Dimension(41, 14)); + lbExaminerPhoneLabel.setPreferredSize(new java.awt.Dimension(41, 14)); + + caseNotesScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + taNotesText.setColumns(20); + taNotesText.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + taNotesText.setLineWrap(true); + taNotesText.setRows(2); + taNotesText.setWrapStyleWord(true); + taNotesText.setBorder(null); + caseNotesScrollPane.setViewportView(taNotesText); + + examinerTextField.setFont(examinerTextField.getFont().deriveFont(examinerTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + + org.openide.awt.Mnemonics.setLocalizedText(lbExaminerEmailLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbExaminerEmailLabel.text")); // NOI18N + lbExaminerEmailLabel.setMaximumSize(new java.awt.Dimension(41, 14)); + lbExaminerEmailLabel.setMinimumSize(new java.awt.Dimension(41, 14)); + lbExaminerEmailLabel.setPreferredSize(new java.awt.Dimension(41, 14)); + + examinerLabel.setFont(examinerLabel.getFont().deriveFont(examinerLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(examinerLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.examinerLabel.text")); // NOI18N + examinerLabel.setMaximumSize(new java.awt.Dimension(41, 14)); + examinerLabel.setMinimumSize(new java.awt.Dimension(41, 14)); + examinerLabel.setPreferredSize(new java.awt.Dimension(41, 14)); + + org.openide.awt.Mnemonics.setLocalizedText(lbNotesLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbNotesLabel.text")); // NOI18N + lbNotesLabel.setMaximumSize(new java.awt.Dimension(41, 14)); + lbNotesLabel.setMinimumSize(new java.awt.Dimension(41, 14)); + lbNotesLabel.setPreferredSize(new java.awt.Dimension(41, 14)); + + javax.swing.GroupLayout examinerPanelLayout = new javax.swing.GroupLayout(examinerPanel); + examinerPanel.setLayout(examinerPanelLayout); + examinerPanelLayout.setHorizontalGroup( + examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbNotesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbExaminerPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(10, 10, 10) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(caseNotesScrollPane) + .addComponent(tfExaminerPhoneText))) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(lbExaminerEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(examinerLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(examinerTextField) + .addComponent(tfExaminerEmailText)))) + .addGap(11, 11, 11)) + ); + examinerPanelLayout.setVerticalGroup( + examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(examinerPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(examinerLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(examinerTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tfExaminerPhoneText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbExaminerPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tfExaminerEmailText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbExaminerEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(examinerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbNotesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseNotesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6)) + ); + + orgainizationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.orgainizationPanel.border.title"))); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactPhoneLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbPointOfContactPhoneLabel.text")); // NOI18N + lbPointOfContactPhoneLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactPhoneLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactPhoneLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + comboBoxOrgName.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + comboBoxOrgNameActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactNameLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbPointOfContactNameLabel.text")); // NOI18N + lbPointOfContactNameLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactNameLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactNameLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + org.openide.awt.Mnemonics.setLocalizedText(bnNewOrganization, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.bnNewOrganization.text")); // NOI18N + bnNewOrganization.setMargin(new java.awt.Insets(2, 6, 2, 6)); + bnNewOrganization.setMaximumSize(new java.awt.Dimension(123, 23)); + bnNewOrganization.setMinimumSize(new java.awt.Dimension(123, 23)); + bnNewOrganization.setPreferredSize(new java.awt.Dimension(123, 23)); + bnNewOrganization.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnNewOrganizationActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(lbOrganizationNameLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbOrganizationNameLabel.text")); // NOI18N + lbOrganizationNameLabel.setMaximumSize(new java.awt.Dimension(189, 14)); + lbOrganizationNameLabel.setMinimumSize(new java.awt.Dimension(189, 14)); + lbOrganizationNameLabel.setPreferredSize(new java.awt.Dimension(189, 14)); + + org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactEmailLabel, org.openide.util.NbBundle.getMessage(OptionalCasePropertiesPanel.class, "OptionalCasePropertiesPanel.lbPointOfContactEmailLabel.text")); // NOI18N + lbPointOfContactEmailLabel.setMaximumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactEmailLabel.setMinimumSize(new java.awt.Dimension(82, 14)); + lbPointOfContactEmailLabel.setPreferredSize(new java.awt.Dimension(82, 14)); + + javax.swing.GroupLayout orgainizationPanelLayout = new javax.swing.GroupLayout(orgainizationPanel); + orgainizationPanel.setLayout(orgainizationPanelLayout); + orgainizationPanelLayout.setHorizontalGroup( + orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(orgainizationPanelLayout.createSequentialGroup() + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(orgainizationPanelLayout.createSequentialGroup() + .addGap(106, 106, 106) + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbPointOfContactPhoneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(15, 15, 15) + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbPointOfContactPhoneText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactEmailText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(orgainizationPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lbOrganizationNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(comboBoxOrgName, 0, 161, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnNewOrganization, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + orgainizationPanelLayout.setVerticalGroup( + orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(orgainizationPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbOrganizationNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(comboBoxOrgName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnNewOrganization, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactPhoneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactPhoneText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(orgainizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lbPointOfContactEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lbPointOfContactEmailText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(6, 6, 6)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(6, 6, 6) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(casePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(examinerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(orgainizationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(6, 6, 6)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(casePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(examinerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(orgainizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + private void comboBoxOrgNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboBoxOrgNameActionPerformed + @SuppressWarnings("unchecked") + JComboBox cb = (JComboBox) evt.getSource(); + String orgName = (String) cb.getSelectedItem(); + if (null == orgName) { + return; + } + if ("".equals(orgName)) { + clearOrganization(); + return; + } + for (EamOrganization org : orgs) { + if (org.getName().equals(orgName)) { + selectedOrg = org; + lbPointOfContactNameText.setText(selectedOrg.getPocName()); + lbPointOfContactEmailText.setText(selectedOrg.getPocEmail()); + lbPointOfContactPhoneText.setText(selectedOrg.getPocPhone()); + return; + } + } + }//GEN-LAST:event_comboBoxOrgNameActionPerformed + + private void bnNewOrganizationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnNewOrganizationActionPerformed + ManageOrganizationsDialog dialog = new ManageOrganizationsDialog(); + // update the combobox options and org data fields + loadOrganizationData(); + if (dialog.isChanged()) { + selectedOrg = dialog.getNewOrg(); + setCurrentlySelectedOrganization(dialog.getNewOrg().getName()); + } + validate(); + repaint(); + }//GEN-LAST:event_bnNewOrganizationActionPerformed + + void setCurrentlySelectedOrganization(String orgName) { + comboBoxOrgName.setSelectedItem(orgName == null ? "" : orgName); + } + + @Messages({ + "OptionalCasePropertiesPanel.errorDialog.emptyCaseNameMessage=No case name entered.", + "OptionalCasePropertiesPanel.errorDialog.invalidCaseNameMessage=Case names cannot include the following symbols: \\, /, :, *, ?, \", <, >, |" + }) + void saveUpdatedCaseDetails() { + if (caseDisplayNameTextField.getText().trim().isEmpty()) { + MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_emptyCaseNameMessage()); + return; + } + if (!Case.isValidName(caseDisplayNameTextField.getText())) { + MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_invalidCaseNameMessage()); + return; + } + updateCaseDetails(); + updateCorrelationCase(); + } + + private void updateCaseDetails() { + if (caseDisplayNameTextField.isVisible()) { + try { + Case.getCurrentCase().updateCaseDetails(new CaseDetails( + caseDisplayNameTextField.getText(), caseNumberTextField.getText(), + examinerTextField.getText(), tfExaminerPhoneText.getText(), + tfExaminerEmailText.getText(), taNotesText.getText())); + } catch (CaseActionException ex) { + Exceptions.printStackTrace(ex); + } + } + } + + /** + * Save changed value from text fields and text areas into the EamCase + * object. + */ + private void updateCorrelationCase() { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + if (EamDb.isEnabled()) { + try { + EamDb dbManager = EamDb.getInstance(); + CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + if (caseDisplayNameTextField.isVisible()) { + correlationCase.setDisplayName(caseDisplayNameTextField.getText()); + } + correlationCase.setOrg(selectedOrg); + correlationCase.setCaseNumber(caseNumberTextField.getText()); + correlationCase.setExaminerName(examinerTextField.getText()); + correlationCase.setExaminerEmail(tfExaminerEmailText.getText()); + correlationCase.setExaminerPhone(tfExaminerPhoneText.getText()); + correlationCase.setNotes(taNotesText.getText()); + dbManager.updateCase(correlationCase); + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + } + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bnNewOrganization; + private javax.swing.JLabel caseDisplayNameLabel; + private javax.swing.JTextField caseDisplayNameTextField; + private javax.swing.JScrollPane caseNotesScrollPane; + private javax.swing.JLabel caseNumberLabel; + private javax.swing.JTextField caseNumberTextField; + private javax.swing.JPanel casePanel; + private javax.swing.JComboBox comboBoxOrgName; + private javax.swing.JLabel examinerLabel; + private javax.swing.JPanel examinerPanel; + private javax.swing.JTextField examinerTextField; + private javax.swing.JLabel lbExaminerEmailLabel; + private javax.swing.JLabel lbExaminerPhoneLabel; + private javax.swing.JLabel lbNotesLabel; + private javax.swing.JLabel lbOrganizationNameLabel; + private javax.swing.JLabel lbPointOfContactEmailLabel; + private javax.swing.JLabel lbPointOfContactEmailText; + private javax.swing.JLabel lbPointOfContactNameLabel; + private javax.swing.JLabel lbPointOfContactNameText; + private javax.swing.JLabel lbPointOfContactPhoneLabel; + private javax.swing.JLabel lbPointOfContactPhoneText; + private javax.swing.JPanel orgainizationPanel; + private javax.swing.JTextArea taNotesText; + private javax.swing.JTextField tfExaminerEmailText; + private javax.swing.JTextField tfExaminerPhoneText; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index 446c03b6c8..46727fc570 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -199,12 +199,15 @@ public class SingleUserCaseConverter { copyImages(icd); // Create new .aut file - CaseMetadata newCaseMetadata = new CaseMetadata(icd.getCaseOutputFolder().toString(), - CaseType.MULTI_USER_CASE, - icd.getNewCaseName(), + CaseMetadata newCaseMetadata = new CaseMetadata(CaseType.MULTI_USER_CASE, + icd.getCaseOutputFolder().toString(), icd.getNewCaseName(), + new CaseDetails(icd.getNewCaseName(), oldCaseMetadata.getCaseNumber(), - oldCaseMetadata.getExaminer()); + oldCaseMetadata.getExaminer(), + oldCaseMetadata.getExaminerPhone(), + oldCaseMetadata.getExaminerEmail(), + oldCaseMetadata.getCaseNotes())); newCaseMetadata.setCaseDatabaseName(dbName); // Set created date. This calls writefile, no need to call it again newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties deleted file mode 100755 index 6a2b388e78..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/Bundle.properties +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Enterprise Artifacts Manager - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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. - */ -EamCaseEditDetailsDialog.lbExaminerEmailLabel.text=Email: -EamCaseEditDetailsDialog.lbCaseNameLabel.text=Case Name: -EamCaseEditDetailsDialog.lbExaminerNameLabel.text=Name: -EamCaseEditDetailsDialog.bnOk.text=OK -EamCaseEditDetailsDialog.bnClose.text=Close -EamCaseEditDetailsDialog.bnNewOrganization.text=New Organization -EamCaseEditDetailsDialog.lbPointOfContactPhoneLabel.text=Phone: -EamCaseEditDetailsDialog.lbPointOfContactEmailLabel.text=Email: -EamCaseEditDetailsDialog.lbPointOfContactNameLabel.text=Name: -EamCaseEditDetailsDialog.lbPointOfContactGroupLabel.text=Point of Contact: -EamCaseEditDetailsDialog.lbOrganizationNameLabel.text=Organization Name: -EamCaseEditDetailsDialog.lbNotesLabel.text=Notes: -EamCaseEditDetailsDialog.lbCaseUUIDLabel.text=Case UUID: -EamCaseEditDetailsDialog.lbExaminerPhoneLabel.text=Phone: -EamCaseEditDetailsDialog.lbCaseNumberLabel.text=Case Number: -EamCaseEditDetailsDialog.lbCreationDateLabel.text=Creation Date: -EamCaseEditDetailsDialog.pnCaseMetadata.title=Case Metadata -EamCaseEditDetailsDialog.pnOrganization.title=Organization -EamCaseEditDetailsDialog.pnExaminer.title=Examiner diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form deleted file mode 100755 index 0ef78a860c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.form +++ /dev/null @@ -1,456 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java deleted file mode 100755 index 3e34bf9dd2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamCaseEditDetailsDialog.java +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Central Repository - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.centralrepository.actions; - -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Toolkit; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.logging.Level; -import javax.swing.JComboBox; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import org.openide.util.NbBundle.Messages; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; -import org.sleuthkit.autopsy.centralrepository.optionspanel.AddNewOrganizationDialog; - -/** - * Handle editing details of cases within the central repository - */ -public class EamCaseEditDetailsDialog extends JDialog { - - private final static Logger LOGGER = Logger.getLogger(EamCaseEditDetailsDialog.class.getName()); - private CorrelationCase eamCase; - private EamDb dbManager; - private Boolean contentChanged = false; - private final Collection textBoxes = new ArrayList<>(); - private final Collection textAreas = new ArrayList<>(); - private final TextBoxChangedListener textBoxChangedListener = new TextBoxChangedListener(); - private EamOrganization selectedOrg = null; - private List orgs = null; - private boolean comboboxOrganizationActionListenerActive; - - /** - * Creates new EamCaseEditDetailsDialog form - */ - @Messages({"EamCaseEditDetailsDialog.window.title=Central Repository Case Properties"}) - public EamCaseEditDetailsDialog() { - super((JFrame) WindowManager.getDefault().getMainWindow(), - Bundle.EamCaseEditDetailsDialog_window_title(), - true); // NON-NLS - - try { - this.dbManager = EamDb.getInstance(); - this.eamCase = this.dbManager.getCaseByUUID(Case.getCurrentCase().getName()); - if(this.eamCase == null){ - this.eamCase = dbManager.newCase(Case.getCurrentCase()); - } - initComponents(); - loadData(); - customizeComponents(); - display(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error getting current case.", ex); - } - } - - private void customizeComponents() { - setTextBoxListeners(); - setTextAreaListeners(); - } - - private void setTextBoxListeners() { - // Register for notifications when the text boxes get updated. - textBoxes.add(tfExaminerNameText); - textBoxes.add(tfExaminerEmailText); - textBoxes.add(tfExaminerPhoneText); - addTextFieldDocumentListeners(textBoxes, textBoxChangedListener); - } - - private void setTextAreaListeners() { - // Register for notifications when the text areas get updated. - textAreas.add(taNotesText); - addTextAreaDocumentListeners(textAreas, textBoxChangedListener); - } - - /** - * Adds a change listener to a collection of text fields. - * - * @param textFields The text fields. - * @param listener The change listener. - */ - private static void addTextFieldDocumentListeners(Collection textFields, TextBoxChangedListener listener) { - textFields.forEach((textField) -> { - textField.getDocument().addDocumentListener(listener); - }); - } - - /** - * Adds a change listener to a collection of text areas. - * - * @param textAreas The text areas. - * @param listener The change listener. - */ - private static void addTextAreaDocumentListeners(Collection textAreas, TextBoxChangedListener listener) { - textAreas.forEach((textArea) -> { - textArea.getDocument().addDocumentListener(listener); - }); - } - - private void display() { - pack(); - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); - setVisible(true); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - // //GEN-BEGIN:initComponents - private void initComponents() { - - bnClose = new javax.swing.JButton(); - bnOk = new javax.swing.JButton(); - pnCaseMetadata = new javax.swing.JPanel(); - lbCaseNameLabel = new javax.swing.JLabel(); - lbCreationDateLabel = new javax.swing.JLabel(); - lbCaseNumberLabel = new javax.swing.JLabel(); - lbCaseUUIDLabel = new javax.swing.JLabel(); - lbCaseUUIDText = new javax.swing.JLabel(); - lbCaseNameText = new javax.swing.JLabel(); - lbCeationDateText = new javax.swing.JLabel(); - lbCaseNumberText = new javax.swing.JLabel(); - pnOrganization = new javax.swing.JPanel(); - lbOrganizationNameLabel = new javax.swing.JLabel(); - comboBoxOrgName = new javax.swing.JComboBox<>(); - lbPointOfContactGroupLabel = new javax.swing.JLabel(); - lbPointOfContactNameLabel = new javax.swing.JLabel(); - lbPointOfContactEmailLabel = new javax.swing.JLabel(); - lbPointOfContactPhoneLabel = new javax.swing.JLabel(); - lbPointOfContactNameText = new javax.swing.JLabel(); - lbPointOfContactEmailText = new javax.swing.JLabel(); - lbPointOfContactPhoneText = new javax.swing.JLabel(); - bnNewOrganization = new javax.swing.JButton(); - pnExaminer = new javax.swing.JPanel(); - lbExaminerNameLabel = new javax.swing.JLabel(); - tfExaminerNameText = new javax.swing.JTextField(); - lbExaminerEmailLabel = new javax.swing.JLabel(); - tfExaminerEmailText = new javax.swing.JTextField(); - lbExaminerPhoneLabel = new javax.swing.JLabel(); - tfExaminerPhoneText = new javax.swing.JTextField(); - lbNotesLabel = new javax.swing.JLabel(); - jScrollPane2 = new javax.swing.JScrollPane(); - taNotesText = new javax.swing.JTextArea(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - - org.openide.awt.Mnemonics.setLocalizedText(bnClose, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.bnClose.text")); // NOI18N - bnClose.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnCloseActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(bnOk, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.bnOk.text")); // NOI18N - bnOk.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnOkActionPerformed(evt); - } - }); - - pnCaseMetadata.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.pnCaseMetadata.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbCaseNameLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbCaseNameLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbCreationDateLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbCreationDateLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbCaseNumberLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbCaseNumberLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbCaseUUIDLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbCaseUUIDLabel.text")); // NOI18N - - javax.swing.GroupLayout pnCaseMetadataLayout = new javax.swing.GroupLayout(pnCaseMetadata); - pnCaseMetadata.setLayout(pnCaseMetadataLayout); - pnCaseMetadataLayout.setHorizontalGroup( - pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnCaseMetadataLayout.createSequentialGroup() - .addGap(25, 25, 25) - .addGroup(pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(lbCaseNumberLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbCreationDateLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbCaseNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbCaseUUIDLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbCaseNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbCeationDateText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbCaseNumberText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbCaseUUIDText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - pnCaseMetadataLayout.setVerticalGroup( - pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnCaseMetadataLayout.createSequentialGroup() - .addContainerGap() - .addGroup(pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lbCaseUUIDLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbCaseUUIDText, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbCaseNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbCaseNameText, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbCreationDateLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbCeationDateText, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(pnCaseMetadataLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbCaseNumberLabel) - .addComponent(lbCaseNumberText, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(26, 26, 26)) - ); - - pnOrganization.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.pnOrganization.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbOrganizationNameLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbOrganizationNameLabel.text")); // NOI18N - - comboBoxOrgName.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - comboBoxOrgNameActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactGroupLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbPointOfContactGroupLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactNameLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbPointOfContactNameLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactEmailLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbPointOfContactEmailLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbPointOfContactPhoneLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbPointOfContactPhoneLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(bnNewOrganization, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.bnNewOrganization.text")); // NOI18N - bnNewOrganization.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnNewOrganizationActionPerformed(evt); - } - }); - - javax.swing.GroupLayout pnOrganizationLayout = new javax.swing.GroupLayout(pnOrganization); - pnOrganization.setLayout(pnOrganizationLayout); - pnOrganizationLayout.setHorizontalGroup( - pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnOrganizationLayout.createSequentialGroup() - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnOrganizationLayout.createSequentialGroup() - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, pnOrganizationLayout.createSequentialGroup() - .addGap(25, 25, 25) - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lbPointOfContactGroupLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbOrganizationNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addGroup(pnOrganizationLayout.createSequentialGroup() - .addContainerGap() - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lbPointOfContactPhoneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) - .addGap(18, 18, 18) - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbPointOfContactNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactEmailText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactPhoneText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(comboBoxOrgName, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnOrganizationLayout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(bnNewOrganization))) - .addContainerGap()) - ); - pnOrganizationLayout.setVerticalGroup( - pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnOrganizationLayout.createSequentialGroup() - .addContainerGap() - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbOrganizationNameLabel) - .addComponent(comboBoxOrgName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lbPointOfContactGroupLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lbPointOfContactNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactNameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lbPointOfContactEmailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactEmailText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnOrganizationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lbPointOfContactPhoneLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lbPointOfContactPhoneText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnNewOrganization) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - pnExaminer.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.pnExaminer.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbExaminerNameLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbExaminerNameLabel.text")); // NOI18N - - tfExaminerNameText.setEditable(false); - - org.openide.awt.Mnemonics.setLocalizedText(lbExaminerEmailLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbExaminerEmailLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbExaminerPhoneLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbExaminerPhoneLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbNotesLabel, org.openide.util.NbBundle.getMessage(EamCaseEditDetailsDialog.class, "EamCaseEditDetailsDialog.lbNotesLabel.text")); // NOI18N - - taNotesText.setColumns(20); - taNotesText.setRows(5); - jScrollPane2.setViewportView(taNotesText); - - javax.swing.GroupLayout pnExaminerLayout = new javax.swing.GroupLayout(pnExaminer); - pnExaminer.setLayout(pnExaminerLayout); - pnExaminerLayout.setHorizontalGroup( - pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnExaminerLayout.createSequentialGroup() - .addGap(28, 28, 28) - .addGroup(pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbExaminerEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 85, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbExaminerNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbExaminerPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbNotesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(25, 25, 25) - .addGroup(pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tfExaminerEmailText) - .addComponent(tfExaminerPhoneText) - .addComponent(tfExaminerNameText) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE)) - .addContainerGap()) - ); - pnExaminerLayout.setVerticalGroup( - pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnExaminerLayout.createSequentialGroup() - .addContainerGap() - .addGroup(pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbExaminerNameLabel) - .addComponent(tfExaminerNameText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(tfExaminerEmailText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbExaminerEmailLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(tfExaminerPhoneText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbExaminerPhoneLabel)) - .addGap(24, 24, 24) - .addGroup(pnExaminerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbNotesLabel) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(bnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 59, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnClose)) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnCaseMetadata, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pnOrganization, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pnExaminer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(23, 23, 23) - .addComponent(pnCaseMetadata, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnOrganization, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnExaminer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnOk) - .addComponent(bnClose)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - }// //GEN-END:initComponents - - private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed - if (contentChanged) { - updateEamCase(); - updateDb(); - } - dispose(); - }//GEN-LAST:event_bnOkActionPerformed - - private void bnNewOrganizationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnNewOrganizationActionPerformed - AddNewOrganizationDialog dialogO = new AddNewOrganizationDialog(); - // update the combobox options and org data fields - if (dialogO.isChanged()) { - loadOrganizationData(); - } - }//GEN-LAST:event_bnNewOrganizationActionPerformed - - @SuppressWarnings({"unchecked"}) - private void comboBoxOrgNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboBoxOrgNameActionPerformed - JComboBox cb = (JComboBox) evt.getSource(); - String orgName = (String) cb.getSelectedItem(); - if (null == orgName || false == comboboxOrganizationActionListenerActive) { - return; - } - - if ("".equals(orgName)) { - selectedOrg = null; - lbPointOfContactNameText.setText(""); - lbPointOfContactEmailText.setText(""); - lbPointOfContactPhoneText.setText(""); - contentChanged = true; - return; - } - - for (EamOrganization org : orgs) { - if (org.getName().equals(orgName)) { - selectedOrg = org; - lbPointOfContactNameText.setText(selectedOrg.getPocName()); - lbPointOfContactEmailText.setText(selectedOrg.getPocEmail()); - lbPointOfContactPhoneText.setText(selectedOrg.getPocPhone()); - contentChanged = true; - return; - } - } - }//GEN-LAST:event_comboBoxOrgNameActionPerformed - - private void bnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCloseActionPerformed - dispose(); - }//GEN-LAST:event_bnCloseActionPerformed - - private void loadCaseMetaData() { - lbCaseUUIDText.setText(eamCase.getCaseUUID()); - lbCaseNameText.setText(eamCase.getDisplayName()); - lbCeationDateText.setText(eamCase.getCreationDate()); - lbCaseNumberText.setText(eamCase.getCaseNumber()); - } - - private void loadExaminerData() { - tfExaminerNameText.setText(eamCase.getExaminerName()); - tfExaminerEmailText.setText(eamCase.getExaminerEmail()); - tfExaminerPhoneText.setText(eamCase.getExaminerPhone()); - taNotesText.setText(eamCase.getNotes()); - } - - private void loadOrganizationData() { - comboboxOrganizationActionListenerActive = false; // don't fire action listener while loading combobox content - comboBoxOrgName.removeAllItems(); - try { - orgs = dbManager.getOrganizations(); - comboBoxOrgName.addItem(""); // for when a case has a null Org - orgs.forEach((org) -> { - comboBoxOrgName.addItem(org.getName()); - }); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failure populating combobox with organizations.", ex); - } - comboboxOrganizationActionListenerActive = true; - - if (!orgs.isEmpty() && null != eamCase.getOrg()) { - selectedOrg = eamCase.getOrg(); - comboBoxOrgName.setSelectedItem(selectedOrg.getName()); - lbPointOfContactNameText.setText(selectedOrg.getPocName()); - lbPointOfContactEmailText.setText(selectedOrg.getPocEmail()); - lbPointOfContactPhoneText.setText(selectedOrg.getPocPhone()); - } else { - comboBoxOrgName.setSelectedItem(""); - lbPointOfContactNameText.setText(""); - lbPointOfContactEmailText.setText(""); - lbPointOfContactPhoneText.setText(""); - } - } - - private void loadData() { - loadCaseMetaData(); - loadExaminerData(); - loadOrganizationData(); - } - - /** - * Save changed value from text fields and text areas into the EamCase - * object. - */ - private void updateEamCase() { - eamCase.setOrg(selectedOrg); - eamCase.setExaminerName(tfExaminerNameText.getText()); - eamCase.setExaminerEmail(tfExaminerEmailText.getText()); - eamCase.setExaminerPhone(tfExaminerPhoneText.getText()); - eamCase.setNotes(taNotesText.getText()); - } - - private void updateDb() { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - if (!EamDb.isEnabled()) { - LOGGER.log(Level.SEVERE, "Central repository database not enabled"); // NON-NLS - return; - } - - try { - dbManager.updateCase(eamCase); - } catch (IllegalArgumentException | EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS - } finally { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - - /** - * Used to listen for changes in text areas/boxes. Let the panel know text - * content has changed. - */ - private class TextBoxChangedListener implements DocumentListener { - - @Override - public void changedUpdate(DocumentEvent e) { - setChanged(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - setChanged(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - setChanged(); - } - - private void setChanged() { - contentChanged = true; - } - } - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton bnClose; - private javax.swing.JButton bnNewOrganization; - private javax.swing.JButton bnOk; - private javax.swing.JComboBox comboBoxOrgName; - private javax.swing.JScrollPane jScrollPane2; - private javax.swing.JLabel lbCaseNameLabel; - private javax.swing.JLabel lbCaseNameText; - private javax.swing.JLabel lbCaseNumberLabel; - private javax.swing.JLabel lbCaseNumberText; - private javax.swing.JLabel lbCaseUUIDLabel; - private javax.swing.JLabel lbCaseUUIDText; - private javax.swing.JLabel lbCeationDateText; - private javax.swing.JLabel lbCreationDateLabel; - private javax.swing.JLabel lbExaminerEmailLabel; - private javax.swing.JLabel lbExaminerNameLabel; - private javax.swing.JLabel lbExaminerPhoneLabel; - private javax.swing.JLabel lbNotesLabel; - private javax.swing.JLabel lbOrganizationNameLabel; - private javax.swing.JLabel lbPointOfContactEmailLabel; - private javax.swing.JLabel lbPointOfContactEmailText; - private javax.swing.JLabel lbPointOfContactGroupLabel; - private javax.swing.JLabel lbPointOfContactNameLabel; - private javax.swing.JLabel lbPointOfContactNameText; - private javax.swing.JLabel lbPointOfContactPhoneLabel; - private javax.swing.JLabel lbPointOfContactPhoneText; - private javax.swing.JPanel pnCaseMetadata; - private javax.swing.JPanel pnExaminer; - private javax.swing.JPanel pnOrganization; - private javax.swing.JTextArea taNotesText; - private javax.swing.JTextField tfExaminerEmailText; - private javax.swing.JTextField tfExaminerNameText; - private javax.swing.JTextField tfExaminerPhoneText; - // End of variables declaration//GEN-END:variables -} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java deleted file mode 100755 index 4123e382ff..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Central Repository - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.centralrepository.actions; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.Action; -import org.openide.awt.ActionID; -import org.openide.awt.ActionReference; -import org.openide.awt.ActionRegistration; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle.Messages; -import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; - -/** - * Action to update case details in Central Repository database - */ -@ActionID( - category = "Case", - id = "org.sleuthkit.centralrepository.actions.CentralRepositoryCaseProperties" -) -@ActionRegistration( - displayName = "#CTL_CentralRepositoryCaseProperties", - lazy = false -) -@ActionReference(path = "Menu/Case", position = 650, separatorAfter = 824) -@Messages("CTL_CentralRepositoryCaseProperties=Central Repository Case Properties...") -public final class EamEditCaseInfoAction extends CallableSystemAction implements ActionListener { - - EamEditCaseInfoAction() { - putValue(Action.NAME, Bundle.CTL_CentralRepositoryCaseProperties()); // put the action Name - this.setEnabled(true); - } - - @Override - public boolean isEnabled() { - return EamDb.isEnabled() && Case.isCaseOpen(); - } - - @Override - public void actionPerformed(ActionEvent e) { - performAction(); - } - - @Override - public void performAction() { - - EamCaseEditDetailsDialog caseInformationDialog = new EamCaseEditDetailsDialog(); - } - - @Override - public String getName() { - return Bundle.CTL_CentralRepositoryCaseProperties(); - } - - @Override - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 689d5a22fb..b16589c3dd 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -28,11 +28,14 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.sql.Types; import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -272,9 +275,9 @@ public abstract class AbstractSqlEamDb implements EamDb { autopsyCase.getCreatedDate(), autopsyCase.getNumber(), autopsyCase.getExaminer(), - null, - null, - null); + autopsyCase.getExaminerEmail(), + autopsyCase.getExaminerPhone(), + autopsyCase.getCaseNotes()); newCase(curCeCase); return curCeCase; } @@ -451,7 +454,8 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Retrieves Data Source details based on data source device ID * - * @param correlationCase the current CorrelationCase used for ensuring uniqueness of DataSource + * @param correlationCase the current CorrelationCase used for ensuring + * uniqueness of DataSource * @param dataSourceDeviceId the data source device ID number * * @return The data source @@ -572,10 +576,11 @@ public abstract class AbstractSqlEamDb implements EamDb { * Retrieves eamArtifact instances from the database that are associated * with the eamArtifactType and eamArtifactValue of the given eamArtifact. * - * @param aType The type of the artifact - * @param value The correlation value + * @param aType The type of the artifact + * @param value The correlation value * * @return List of artifact instances for a given type/value + * * @throws EamDbException */ @Override @@ -675,8 +680,8 @@ public abstract class AbstractSqlEamDb implements EamDb { * Retrieves number of artifact instances in the database that are * associated with the ArtifactType and artifactValue of the given artifact. * - * @param aType The type of the artifact - * @param value The correlation value + * @param aType The type of the artifact + * @param value The correlation value * * @return Number of artifact instances having ArtifactType and * ArtifactValue. @@ -725,8 +730,8 @@ public abstract class AbstractSqlEamDb implements EamDb { * database that are associated with the artifactType and artifactValue of * the given artifact. * - * @param aType The type of the artifact - * @param value The correlation value + * @param aType The type of the artifact + * @param value The correlation value * * @return Number of unique tuples */ @@ -1019,7 +1024,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * given status. * * @param eamArtifact Artifact containing exactly one (1) ArtifactInstance. - * @param knownStatus The status to change the artifact to + * @param knownStatus The status to change the artifact to */ @Override public void setArtifactInstanceKnownStatus(CorrelationAttribute eamArtifact, TskData.FileKnown knownStatus) throws EamDbException { @@ -1290,29 +1295,38 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Add a new organization * + * @return the Organization ID of the newly created organization. + * * @param eamOrg The organization to add * * @throws EamDbException */ @Override - public void newOrganization(EamOrganization eamOrg) throws EamDbException { + public long newOrganization(EamOrganization eamOrg) throws EamDbException { Connection conn = connect(); - + ResultSet generatedKeys = null; PreparedStatement preparedStatement = null; String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?)"; try { - preparedStatement = conn.prepareStatement(sql); + preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); preparedStatement.setString(1, eamOrg.getName()); preparedStatement.setString(2, eamOrg.getPocName()); preparedStatement.setString(3, eamOrg.getPocEmail()); preparedStatement.setString(4, eamOrg.getPocPhone()); preparedStatement.executeUpdate(); + generatedKeys = preparedStatement.getGeneratedKeys(); + if (generatedKeys.next()) { + return generatedKeys.getLong(1); + } else { + throw new SQLException("Creating user failed, no ID obtained."); + } } catch (SQLException ex) { throw new EamDbException("Error inserting new organization.", ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeResultSet(generatedKeys); EamDbUtil.closeConnection(conn); } } @@ -1383,6 +1397,68 @@ public abstract class AbstractSqlEamDb implements EamDb { } } + /** + * Update an existing organization. + * + * @param updatedOrganization the values the Organization with the same ID + * will be updated to in the database. + * + * @throws EamDbException + */ + @Override + public void updateOrganization(EamOrganization updatedOrganization) throws EamDbException { + Connection conn = connect(); + PreparedStatement preparedStatement = null; + String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?"; + try { + preparedStatement = conn.prepareStatement(sql); + preparedStatement.setString(1, updatedOrganization.getName()); + preparedStatement.setString(2, updatedOrganization.getPocName()); + preparedStatement.setString(3, updatedOrganization.getPocEmail()); + preparedStatement.setString(4, updatedOrganization.getPocPhone()); + preparedStatement.setInt(5, updatedOrganization.getOrgID()); + preparedStatement.executeUpdate(); + } catch (SQLException ex) { + throw new EamDbException("Error updating organization.", ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeConnection(conn); + } + } + + @Messages({"AbstractSqlEamDb.deleteOrganization.inUseException.message=Can not delete organization " + + "which is currently in use by a case or reference set in the central repository.", + "AbstractSqlEamDb.deleteOrganization.errorDeleting.message=Error executing query when attempting to delete organization by id."}) + @Override + public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException { + Connection conn = connect(); + PreparedStatement checkIfUsedStatement = null; + ResultSet resultSet = null; + String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)"; + PreparedStatement deleteOrgStatement = null; + String deleteOrgSql = "DELETE FROM organizations WHERE id=?"; + try { + checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql); + checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID()); + checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID()); + resultSet = checkIfUsedStatement.executeQuery(); + resultSet.next(); + if (resultSet.getLong(1) > 0) { + throw new EamDbException(Bundle.AbstractSqlEamDb_deleteOrganization_inUseException_message()); + } + deleteOrgStatement = conn.prepareStatement(deleteOrgSql); + deleteOrgStatement.setInt(1, organizationToDelete.getOrgID()); + deleteOrgStatement.executeUpdate(); + } catch (SQLException ex) { + throw new EamDbException(Bundle.AbstractSqlEamDb_deleteOrganization_errorDeleting_message(), ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(checkIfUsedStatement); + EamDbUtil.closePreparedStatement(deleteOrgStatement); + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + } + /** * Add a new Global Set * @@ -1851,7 +1927,7 @@ public abstract class AbstractSqlEamDb implements EamDb { resultSet.getInt("id"), resultSet.getInt("case_id"), resultSet.getString("device_id"), - resultSet.getString("name") + resultSet.getString("name") ); return eamDataSource; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index c3f3c09730..70ab104fa4 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -314,7 +314,7 @@ public interface EamDb { * exists, it is updated. If eamArtifact does not exist nothing happens * * @param eamArtifact Artifact containing exactly one (1) ArtifactInstance. - * @param knownStatus The status to change the artifact to + * @param knownStatus The status to change the artifact to */ void setArtifactInstanceKnownStatus(CorrelationAttribute eamArtifact, TskData.FileKnown knownStatus) throws EamDbException; @@ -368,9 +368,11 @@ public interface EamDb { * * @param eamOrg The organization to add * + * @return the Organization ID of the newly created organization. + * * @throws EamDbException */ - void newOrganization(EamOrganization eamOrg) throws EamDbException; + long newOrganization(EamOrganization eamOrg) throws EamDbException; /** * Get all organizations @@ -392,6 +394,26 @@ public interface EamDb { */ EamOrganization getOrganizationByID(int orgID) throws EamDbException; + /** + * Update an existing organization. + * + * @param updatedOrganization the values the Organization with the same ID + * will be updated to in the database. + * + * @throws EamDbException + */ + void updateOrganization(EamOrganization updatedOrganization) throws EamDbException; + + /** + * Delete an organization if it is not being used by any case. + * + * @param organizationToDelete the organization to be deleted + * + * @throws EamDbException + */ + void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException; + + /** * Add a new Global Set * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index a048d95f9c..5890dd2a67 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -656,15 +656,17 @@ public class SqliteEamDb extends AbstractSqlEamDb { /** * Add a new organization * + * @return the Organization ID of the newly created organization. + * * @param eamOrg The organization to add * * @throws EamDbException */ @Override - public void newOrganization(EamOrganization eamOrg) throws EamDbException { + public long newOrganization(EamOrganization eamOrg) throws EamDbException { try{ acquireExclusiveLock(); - super.newOrganization(eamOrg); + return super.newOrganization(eamOrg); } finally { releaseExclusiveLock(); } @@ -704,8 +706,27 @@ public class SqliteEamDb extends AbstractSqlEamDb { } finally { releaseSharedLock(); } - } + } + @Override + public void updateOrganization(EamOrganization updatedOrganization) throws EamDbException { + try{ + acquireExclusiveLock(); + super.updateOrganization(updatedOrganization); + } finally { + releaseExclusiveLock(); + } + } + + @Override + public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException { + try{ + acquireExclusiveLock(); + super.deleteOrganization(organizationToDelete); + } finally { + releaseExclusiveLock(); + } + } /** * Add a new Global Set * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 7f4f97d08a..a68b0cba8d 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -18,9 +18,12 @@ */ package org.sleuthkit.autopsy.centralrepository.eventlisteners; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; import org.openide.util.NbBundle.Messages; @@ -39,6 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -53,9 +57,19 @@ import org.sleuthkit.datamodel.TskDataException; * accordingly */ @Messages({"caseeventlistener.evidencetag=Evidence"}) -public class CaseEventListener implements PropertyChangeListener { +final class CaseEventListener implements PropertyChangeListener { private static final Logger LOGGER = Logger.getLogger(CaseEventListener.class.getName()); + private final ExecutorService jobProcessingExecutor; + private static final String CASE_EVENT_THREAD_NAME = "Case-Event-Listener-%d"; + + CaseEventListener() { + jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build()); + } + + void shutdown() { + ThreadUtils.shutDownTaskExecutor(jobProcessingExecutor); + } @Override public void propertyChange(PropertyChangeEvent evt) { @@ -69,222 +83,290 @@ public class CaseEventListener implements PropertyChangeListener { switch (Case.Events.valueOf(evt.getPropertyName())) { case CONTENT_TAG_ADDED: case CONTENT_TAG_DELETED: { - if (!EamDb.isEnabled()) { + jobProcessingExecutor.submit(new ContentTagTask(dbManager, evt)); + } + break; + + case BLACKBOARD_ARTIFACT_TAG_DELETED: + case BLACKBOARD_ARTIFACT_TAG_ADDED: { + jobProcessingExecutor.submit(new BlackboardTagTask(dbManager, evt)); + } + break; + + case DATA_SOURCE_ADDED: { + jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt)); + } + break; + + case CURRENT_CASE: { + jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt)); + } + break; + } + } + + private final class ContentTagTask implements Runnable { + + private final EamDb dbManager; + private final PropertyChangeEvent event; + + private ContentTagTask(EamDb db, PropertyChangeEvent evt) { + dbManager = db; + event = evt; + } + + @Override + public void run() { + if (!EamDb.isEnabled()) { + return; + } + + AbstractFile af; + TskData.FileKnown knownStatus; + String comment; + if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.CONTENT_TAG_ADDED) { + // For added tags, we want to change the known status to BAD if the + // tag that was just added is in the list of central repo tags. + final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event; + final ContentTag tagAdded = tagAddedEvent.getAddedTag(); + + if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) { + if (tagAdded.getContent() instanceof AbstractFile) { + af = (AbstractFile) tagAdded.getContent(); + knownStatus = TskData.FileKnown.BAD; + comment = tagAdded.getComment(); + } else { + LOGGER.log(Level.WARNING, "Error updating non-file object"); + return; + } + } else { + // The added tag isn't flagged as bad in central repo, so do nothing + return; + } + } else { // CONTENT_TAG_DELETED + // For deleted tags, we want to set the file status to UNKNOWN if: + // - The tag that was just removed is notable in central repo + // - There are no remaining tags that are notable + final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) event; + long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID(); + + String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName(); + if (!dbManager.getBadTags().contains(tagName)) { + // If the tag that got removed isn't on the list of central repo tags, do nothing return; } - AbstractFile af; - TskData.FileKnown knownStatus; - String comment; - if (Case.Events.valueOf(evt.getPropertyName()) == Case.Events.CONTENT_TAG_ADDED) { - // For added tags, we want to change the known status to BAD if the - // tag that was just added is in the list of central repo tags. - final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - final ContentTag tagAdded = tagAddedEvent.getAddedTag(); + try { + // Get the remaining tags on the content object + Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tags = tagsManager.getContentTagsByContent(content); - if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) { - if (tagAdded.getContent() instanceof AbstractFile) { - af = (AbstractFile) tagAdded.getContent(); - knownStatus = TskData.FileKnown.BAD; - comment = tagAdded.getComment(); + if (tags.stream() + .map(tag -> tag.getName().getDisplayName()) + .filter(dbManager.getBadTags()::contains) + .collect(Collectors.toList()) + .isEmpty()) { + + // There are no more bad tags on the object + if (content instanceof AbstractFile) { + af = (AbstractFile) content; + knownStatus = TskData.FileKnown.UNKNOWN; + comment = ""; } else { LOGGER.log(Level.WARNING, "Error updating non-file object"); return; } } else { - // The added tag isn't flagged as bad in central repo, so do nothing + // There's still at least one bad tag, so leave the known status as is return; } - } else { // CONTENT_TAG_DELETED - // For deleted tags, we want to set the file status to UNKNOWN if: - // - The tag that was just removed is notable in central repo - // - There are no remaining tags that are notable - final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID(); - - String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName(); - if (!dbManager.getBadTags().contains(tagName)) { - // If the tag that got removed isn't on the list of central repo tags, do nothing - return; - } - - try { - // Get the remaining tags on the content object - Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List tags = tagsManager.getContentTagsByContent(content); - - if (tags.stream() - .map(tag -> tag.getName().getDisplayName()) - .filter(dbManager.getBadTags()::contains) - .collect(Collectors.toList()) - .isEmpty()) { - - // There are no more bad tags on the object - if (content instanceof AbstractFile) { - af = (AbstractFile) content; - knownStatus = TskData.FileKnown.UNKNOWN; - comment = ""; - } else { - LOGGER.log(Level.WARNING, "Error updating non-file object"); - return; - } - } else { - // There's still at least one bad tag, so leave the known status as is - return; - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to find content", ex); - return; - } - } - - final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af, - knownStatus, comment); - - if (eamArtifact != null) { - // send update to Central Repository db - Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus); - // TODO: send r into a thread pool instead - Thread t = new Thread(r); - t.start(); - } - } // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED - break; - - case BLACKBOARD_ARTIFACT_TAG_DELETED: - case BLACKBOARD_ARTIFACT_TAG_ADDED: { - if (!EamDb.isEnabled()) { + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to find content", ex); return; } + } - Content content; - BlackboardArtifact bbArtifact; - TskData.FileKnown knownStatus; - String comment; - if (Case.Events.valueOf(evt.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) { - // For added tags, we want to change the known status to BAD if the - // tag that was just added is in the list of central repo tags. - final BlackBoardArtifactTagAddedEvent tagAddedEvent = (BlackBoardArtifactTagAddedEvent) evt; - final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag(); + final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af, + knownStatus, comment); - if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) { - content = tagAdded.getContent(); - bbArtifact = tagAdded.getArtifact(); - knownStatus = TskData.FileKnown.BAD; - comment = tagAdded.getComment(); - } else { - // The added tag isn't flagged as bad in central repo, so do nothing - return; - } - } else { //BLACKBOARD_ARTIFACT_TAG_DELETED - // For deleted tags, we want to set the file status to UNKNOWN if: - // - The tag that was just removed is notable in central repo - // - There are no remaining tags that are notable - final BlackBoardArtifactTagDeletedEvent tagDeletedEvent = (BlackBoardArtifactTagDeletedEvent) evt; - long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID(); - long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID(); - - String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName(); - if (!dbManager.getBadTags().contains(tagName)) { - // If the tag that got removed isn't on the list of central repo tags, do nothing - return; - } - - try { - // Get the remaining tags on the artifact - content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); - bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); - - if (tags.stream() - .map(tag -> tag.getName().getDisplayName()) - .filter(dbManager.getBadTags()::contains) - .collect(Collectors.toList()) - .isEmpty()) { - - // There are no more bad tags on the object - knownStatus = TskData.FileKnown.UNKNOWN; - comment = ""; - - } else { - // There's still at least one bad tag, so leave the known status as is - return; - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to find content", ex); - return; - } + if (eamArtifact != null) { + // send update to Central Repository db + try { + dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus); + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS } + } + } // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED + } - if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { + private final class BlackboardTagTask implements Runnable { + + private final EamDb dbManager; + private final PropertyChangeEvent event; + + private BlackboardTagTask(EamDb db, PropertyChangeEvent evt) { + dbManager = db; + event = evt; + } + + @Override + public void run() { + if (!EamDb.isEnabled()) { + return; + } + + Content content; + BlackboardArtifact bbArtifact; + TskData.FileKnown knownStatus; + String comment; + if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) { + // For added tags, we want to change the known status to BAD if the + // tag that was just added is in the list of central repo tags. + final BlackBoardArtifactTagAddedEvent tagAddedEvent = (BlackBoardArtifactTagAddedEvent) event; + final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag(); + + if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) { + content = tagAdded.getContent(); + bbArtifact = tagAdded.getArtifact(); + knownStatus = TskData.FileKnown.BAD; + comment = tagAdded.getComment(); + } else { + // The added tag isn't flagged as bad in central repo, so do nothing return; } + } else { //BLACKBOARD_ARTIFACT_TAG_DELETED + // For deleted tags, we want to set the file status to UNKNOWN if: + // - The tag that was just removed is notable in central repo + // - There are no remaining tags that are notable + final BlackBoardArtifactTagDeletedEvent tagDeletedEvent = (BlackBoardArtifactTagDeletedEvent) event; + long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID(); + long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID(); - List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true); - for (CorrelationAttribute eamArtifact : convertedArtifacts) { - eamArtifact.getInstances().get(0).setComment(comment); - Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus); - // TODO: send r into a thread pool instead - Thread t = new Thread(r); - t.start(); + String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName(); + if (!dbManager.getBadTags().contains(tagName)) { + // If the tag that got removed isn't on the list of central repo tags, do nothing + return; } - } // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED - break; - - case DATA_SOURCE_ADDED: { - if (!EamDb.isEnabled()) { - break; - } - - final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) evt; - Content newDataSource = dataSourceAddedEvent.getDataSource(); - try { - String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId(); - CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); - if (null == correlationCase) { - dbManager.newCase(Case.getCurrentCase()); - correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + // Get the remaining tags on the artifact + content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); + bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID); + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); + + if (tags.stream() + .map(tag -> tag.getName().getDisplayName()) + .filter(dbManager.getBadTags()::contains) + .collect(Collectors.toList()) + .isEmpty()) { + + // There are no more bad tags on the object + knownStatus = TskData.FileKnown.UNKNOWN; + comment = ""; + + } else { + // There's still at least one bad tag, so leave the known status as is + return; } - if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) { - dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource)); - } - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS - } catch (TskCoreException | TskDataException ex) { - LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to find content", ex); + return; } - } // DATA_SOURCE_ADDED - break; + } - case CURRENT_CASE: { - /* - * A case has been opened if evt.getOldValue() is null and - * evt.getNewValue() is a valid Case. - */ - if ((null == evt.getOldValue()) && (evt.getNewValue() instanceof Case)) { - Case curCase = (Case) evt.getNewValue(); - IngestEventsListener.resetCeModuleInstanceCount(); - try { - // only add default evidence tag if case is open and it doesn't already exist in the tags list. - if (Case.isCaseOpen() - && Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() - .map(tag -> tag.getDisplayName()) - .filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName)) - .collect(Collectors.toList()) - .isEmpty()) { - curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag()); - } - } catch (TagsManager.TagNameAlreadyExistsException ex) { - LOGGER.info("Evidence tag already exists"); // NON-NLS - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS + if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { + return; + } + + List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true); + for (CorrelationAttribute eamArtifact : convertedArtifacts) { + eamArtifact.getInstances().get(0).setComment(comment); + try { + dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus); + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS + } + } + } // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED + + } + + private final class DataSourceAddedTask implements Runnable { + + private final EamDb dbManager; + private final PropertyChangeEvent event; + + private DataSourceAddedTask(EamDb db, PropertyChangeEvent evt) { + dbManager = db; + event = evt; + } + + @Override + public void run() { + if (!EamDb.isEnabled()) { + return; + } + + final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event; + Content newDataSource = dataSourceAddedEvent.getDataSource(); + + try { + String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId(); + CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + if (null == correlationCase) { + dbManager.newCase(Case.getCurrentCase()); + correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); + } + if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) { + dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource)); + } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS + } catch (TskCoreException | TskDataException ex) { + LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS + } + } // DATA_SOURCE_ADDED + } + + private final class CurrentCaseTask implements Runnable { + + private final EamDb dbManager; + private final PropertyChangeEvent event; + + private CurrentCaseTask(EamDb db, PropertyChangeEvent evt) { + dbManager = db; + event = evt; + } + + @Override + public void run() { + /* + * A case has been opened if evt.getOldValue() is null and + * evt.getNewValue() is a valid Case. + */ + if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) { + Case curCase = (Case) event.getNewValue(); + IngestEventsListener.resetCeModuleInstanceCount(); + try { + // only add default evidence tag if case is open and it doesn't already exist in the tags list. + if (Case.isCaseOpen() + && Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() + .map(tag -> tag.getDisplayName()) + .filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName)) + .collect(Collectors.toList()) + .isEmpty()) { + curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag()); } + } catch (TagsManager.TagNameAlreadyExistsException ex) { + LOGGER.info("Evidence tag already exists"); // NON-NLS + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS + } - CorrelationCase curCeCase = new CorrelationCase( + CorrelationCase curCeCase = new CorrelationCase( -1, curCase.getName(), // unique case ID EamOrganization.getDefault(), @@ -292,52 +374,26 @@ public class CaseEventListener implements PropertyChangeListener { curCase.getCreatedDate(), curCase.getNumber(), curCase.getExaminer(), - null, - null, - null); + curCase.getExaminerEmail(), + curCase.getExaminerPhone(), + curCase.getCaseNotes()); if (!EamDb.isEnabled()) { - break; + return; } - try { - // NOTE: Cannot determine if the opened case is a new case or a reopened case, - // so check for existing name in DB and insert if missing. - CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID()); + try { + // NOTE: Cannot determine if the opened case is a new case or a reopened case, + // so check for existing name in DB and insert if missing. + CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID()); - if (null == existingCase) { - dbManager.newCase(curCeCase); - } - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS + if (null == existingCase) { + dbManager.newCase(curCeCase); } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS } - } // CURRENT_CASE - break; - - case NAME: { - // The display name of the case has been changed - - if (!EamDb.isEnabled()) { - break; - } - - if (evt.getNewValue() instanceof String) { - String newName = (String) evt.getNewValue(); - try { - // See if the case is in the database. If it is, update the display name. - CorrelationCase existingCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName()); - - if (null != existingCase) { - existingCase.setDisplayName(newName); - dbManager.updateCase(existingCase); - } - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS - } - } - } // NAME - break; - } + } + } // CURRENT_CASE } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 496dbe2f33..02d64904a4 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.centralrepository.eventlisteners; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import static java.lang.Boolean.FALSE; @@ -25,6 +26,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; import org.openide.util.NbBundle; @@ -42,6 +45,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.coreutils.ThreadUtils; /** * Listen for ingest events and update entries in the Central Repository @@ -53,9 +57,19 @@ public class IngestEventsListener { final Collection recentlyAddedCeArtifacts = new LinkedHashSet<>(); private static int ceModuleInstanceCount = 0; + private final ExecutorService jobProcessingExecutor; + private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d"; private final PropertyChangeListener pcl1 = new IngestModuleEventListener(); private final PropertyChangeListener pcl2 = new IngestJobEventListener(); + IngestEventsListener() { + jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(INGEST_EVENT_THREAD_NAME).build()); + } + + void shutdown() { + ThreadUtils.shutDownTaskExecutor(jobProcessingExecutor); + } + /* * Add all of our Ingest Event Listeners to the IngestManager Instance. */ @@ -86,7 +100,7 @@ public class IngestEventsListener { * Engine. */ public synchronized static void decrementCorrelationEngineModuleCount() { - if (getCeModuleInstanceCount()>0) { //prevent it ingestJobCounter from going negative + if (getCeModuleInstanceCount() > 0) { //prevent it ingestJobCounter from going negative ceModuleInstanceCount--; //Should be called once in the Correlation Engine module's shutdown method. } } @@ -109,89 +123,10 @@ public class IngestEventsListener { return ceModuleInstanceCount; } - private class IngestModuleEventListener implements PropertyChangeListener { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (getCeModuleInstanceCount() > 0) { - EamDb dbManager; - try { - dbManager = EamDb.getInstance(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failed to connect to Central Repository database.", ex); - return; - } - switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) { - case DATA_ADDED: { - if (!EamDb.isEnabled()) { - return; - } - final ModuleDataEvent mde = (ModuleDataEvent) evt.getOldValue(); - Collection bbArtifacts = mde.getArtifacts(); - if (null == bbArtifacts) { //the ModuleDataEvents don't always have a collection of artifacts set - return; - } - List eamArtifacts = new ArrayList<>(); - - for (BlackboardArtifact bbArtifact : bbArtifacts) { - // eamArtifact will be null OR a EamArtifact containing one EamArtifactInstance. - List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true); - for (CorrelationAttribute eamArtifact : convertedArtifacts) { - try { - // Only do something with this artifact if it's unique within the job - if (recentlyAddedCeArtifacts.add(eamArtifact.toString())) { - // Was it previously marked as bad? - // query db for artifact instances having this TYPE/VALUE and knownStatus = "Bad". - // if gettKnownStatus() is "Unknown" and this artifact instance was marked bad in a previous case, - // create TSK_INTERESTING_ARTIFACT_HIT artifact on BB. - List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); - if (!caseDisplayNames.isEmpty()) { - postCorrelatedBadArtifactToBlackboard(bbArtifact, - caseDisplayNames); - } - eamArtifacts.add(eamArtifact); - } - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error counting notable artifacts.", ex); - } - } - } - - if (FALSE == eamArtifacts.isEmpty()) { - // send update to entperirse artifact manager db - Runnable r = new NewArtifactsRunner(eamArtifacts); - // TODO: send r into a thread pool instead - Thread t = new Thread(r); - t.start(); - } // DATA_ADDED - break; - } - } - } - } - } - - private class IngestJobEventListener implements PropertyChangeListener { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) { - case DATA_SOURCE_ANALYSIS_COMPLETED: { - // clear the tracker to reduce memory usage - if (getCeModuleInstanceCount() == 0) { - recentlyAddedCeArtifacts.clear(); - } - //else another instance of the Correlation Engine Module is still being run. - } // DATA_SOURCE_ANALYSIS_COMPLETED - break; - } - } - } - @NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", - "IngestEventsListener.prevCaseComment.text=Previous Case: ", + "IngestEventsListener.prevCaseComment.text=Previous Case: ", "IngestEventsListener.ingestmodule.name=Correlation Engine"}) - private void postCorrelatedBadArtifactToBlackboard(BlackboardArtifact bbArtifact, List caseDisplayNames) { + static private void postCorrelatedBadArtifactToBlackboard(BlackboardArtifact bbArtifact, List caseDisplayNames) { try { AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); @@ -222,4 +157,109 @@ public class IngestEventsListener { LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS } } + + private class IngestModuleEventListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (getCeModuleInstanceCount() > 0) { + EamDb dbManager; + try { + dbManager = EamDb.getInstance(); + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Failed to connect to Central Repository database.", ex); + return; + } + switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) { + case DATA_ADDED: { + jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt)); + break; + } + } + } + } + } + + private class IngestJobEventListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) { + case DATA_SOURCE_ANALYSIS_COMPLETED: { + jobProcessingExecutor.submit(new AnalysisCompleteTask()); + break; + } + } + } + + } + + private final class AnalysisCompleteTask implements Runnable { + + @Override + public void run() { + // clear the tracker to reduce memory usage + if (getCeModuleInstanceCount() == 0) { + recentlyAddedCeArtifacts.clear(); + } + //else another instance of the Correlation Engine Module is still being run. + } // DATA_SOURCE_ANALYSIS_COMPLETED + } + + private final class DataAddedTask implements Runnable { + + private final EamDb dbManager; + private final PropertyChangeEvent event; + + private DataAddedTask(EamDb db, PropertyChangeEvent evt) { + dbManager = db; + event = evt; + } + + @Override + public void run() { + if (!EamDb.isEnabled()) { + return; + } + final ModuleDataEvent mde = (ModuleDataEvent) event.getOldValue(); + Collection bbArtifacts = mde.getArtifacts(); + if (null == bbArtifacts) { //the ModuleDataEvents don't always have a collection of artifacts set + return; + } + List eamArtifacts = new ArrayList<>(); + + for (BlackboardArtifact bbArtifact : bbArtifacts) { + // eamArtifact will be null OR a EamArtifact containing one EamArtifactInstance. + List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true); + for (CorrelationAttribute eamArtifact : convertedArtifacts) { + try { + // Only do something with this artifact if it's unique within the job + if (recentlyAddedCeArtifacts.add(eamArtifact.toString())) { + // Was it previously marked as bad? + // query db for artifact instances having this TYPE/VALUE and knownStatus = "Bad". + // if gettKnownStatus() is "Unknown" and this artifact instance was marked bad in a previous case, + // create TSK_INTERESTING_ARTIFACT_HIT artifact on BB. + List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); + if (!caseDisplayNames.isEmpty()) { + postCorrelatedBadArtifactToBlackboard(bbArtifact, + caseDisplayNames); + } + eamArtifacts.add(eamArtifact); + } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error counting notable artifacts.", ex); + } + } + } + if (FALSE == eamArtifacts.isEmpty()) { + try { + for (CorrelationAttribute eamArtifact : eamArtifacts) { + dbManager.addArtifact(eamArtifact); + } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS + } + } // DATA_ADDED + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java index d2b1beebbb..8af34bc718 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.centralrepository.eventlisteners; -import java.beans.PropertyChangeListener; import org.openide.modules.ModuleInstall; -import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.centralrepository.actions.EamEditCaseInfoAction; /** * Install event listeners during module initialization @@ -32,7 +29,7 @@ public class Installer extends ModuleInstall { private static final Logger LOGGER = Logger.getLogger(Installer.class.getName()); private static final long serialVersionUID = 1L; - private final PropertyChangeListener pcl = new CaseEventListener(); + private final CaseEventListener pcl = new CaseEventListener(); private final IngestEventsListener ieListener = new IngestEventsListener(); private static Installer instance; @@ -54,8 +51,6 @@ public class Installer extends ModuleInstall { Case.addPropertyChangeListener(pcl); ieListener.installListeners(); - CallableSystemAction.get(EamEditCaseInfoAction.class).setEnabled(true); - // TODO: create a thread pool to process Runners. } @@ -71,6 +66,8 @@ public class Installer extends ModuleInstall { //module is being unloaded Case.removePropertyChangeListener(pcl); + pcl.shutdown(); + ieListener.shutdown(); ieListener.uninstallListeners(); // TODO: remove thread pool diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/KnownStatusChangeRunner.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/KnownStatusChangeRunner.java deleted file mode 100755 index 4761f77370..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/KnownStatusChangeRunner.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Central Repository - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.centralrepository.eventlisteners; - -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.datamodel.TskData.FileKnown; - -/** - * Thread to send info to remote DB that tags a file as known, unknown, or notable. - */ -public class KnownStatusChangeRunner implements Runnable { - - private static final Logger LOGGER = Logger.getLogger(KnownStatusChangeRunner.class.getName()); - private static final long serialVersionUID = 1L; - - private final CorrelationAttribute artifact; - private final FileKnown knownStatus; - - public KnownStatusChangeRunner(CorrelationAttribute artifact, FileKnown knownStatus) { - this.artifact = artifact; - this.knownStatus = knownStatus; - } - - @Override - public void run() { - if (!EamDb.isEnabled()) { - LOGGER.log(Level.WARNING, "Central Repository database not configured"); // NON-NLS - return; - } - - try { - EamDb dbManager = EamDb.getInstance(); - dbManager.setArtifactInstanceKnownStatus(this.artifact, this.knownStatus); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index fc8d100c37..31d989d74a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -241,9 +241,9 @@ class IngestModule implements FileIngestModule { curCase.getCreatedDate(), curCase.getNumber(), curCase.getExaminer(), - null, - null, - null); + curCase.getExaminerEmail(), + curCase.getExaminerPhone(), + curCase.getCaseNotes()); try { dbManager.newCase(curCeCase); eamCase = dbManager.getCaseByUUID(curCase.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java index 0721c92ca7..db26739a9c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/AddNewOrganizationDialog.java @@ -41,10 +41,13 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; public class AddNewOrganizationDialog extends javax.swing.JDialog { private static final Logger LOGGER = Logger.getLogger(AddNewOrganizationDialog.class.getName()); + private static final long serialVersionUID = 1L; private final Collection textBoxes; private final TextBoxChangedListener textBoxChangedListener; private boolean hasChanged; + private EamOrganization newOrg; + private final EamOrganization organizationToEdit; /** * Creates new form AddNewOrganizationDialog @@ -57,8 +60,28 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog { textBoxes = new ArrayList<>(); textBoxChangedListener = new TextBoxChangedListener(); hasChanged = false; + newOrg = null; initComponents(); customizeComponents(); + organizationToEdit = null; + display(); + } + + public AddNewOrganizationDialog(EamOrganization orgToEdit) { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.AddNewOrganizationDialog_addNewOrg_msg(), + true); // NON-NLS + organizationToEdit = orgToEdit; + textBoxes = new ArrayList<>(); + textBoxChangedListener = new TextBoxChangedListener(); + hasChanged = false; + newOrg = null; + initComponents(); + customizeComponents(); + tfOrganizationName.setText(orgToEdit.getName()); + tfPocName.setText(orgToEdit.getPocName()); + tfPocEmail.setText(orgToEdit.getPocEmail()); + tfPocPhone.setText(orgToEdit.getPocPhone()); display(); } @@ -177,6 +200,10 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog { return hasChanged; } + public EamOrganization getNewOrg() { + return newOrg; + } + /** * 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 @@ -304,14 +331,25 @@ public class AddNewOrganizationDialog extends javax.swing.JDialog { @Messages({"AddNewOrganizationDialog.bnOk.addFailed.text=Failed to add new organization."}) private void bnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOKActionPerformed - EamOrganization newOrg = new EamOrganization( - tfOrganizationName.getText(), - tfPocName.getText(), - tfPocEmail.getText(), - tfPocPhone.getText()); + try { EamDb dbManager = EamDb.getInstance(); - dbManager.newOrganization(newOrg); + if (organizationToEdit != null) { + //check if new name exists with ID other than the one in use here + newOrg = new EamOrganization(organizationToEdit.getOrgID(), + tfOrganizationName.getText(), + tfPocName.getText(), + tfPocEmail.getText(), + tfPocPhone.getText()); + dbManager.updateOrganization(newOrg); + } else { + newOrg = new EamOrganization( + tfOrganizationName.getText(), + tfPocName.getText(), + tfPocEmail.getText(), + tfPocPhone.getText()); + newOrg.setOrgID((int)dbManager.newOrganization(newOrg)); + } hasChanged = true; dispose(); } catch (EamDbException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties index 32a8938df1..7ab2c9b2e4 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties @@ -75,4 +75,4 @@ ImportHashDatabaseDialog.lbInstructions.text=Choose an .idx file to import into ImportHashDatabaseDialog.lbFilePath.text=File Path: ImportHashDatabaseDialog.tfFilePath.text= EamDbSettingsDialog.lbDatabaseDesc.text=Database File: -EamDbSettingsDialog.lbFullDbPath.text=jLabel2 +EamDbSettingsDialog.lbFullDbPath.text= diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form index c9c19a90ff..49d525511b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form @@ -25,17 +25,13 @@ + - - - - - - - + + @@ -56,9 +52,12 @@ + + +
@@ -312,9 +311,6 @@ - - -
@@ -415,5 +411,93 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java index 77b9a63288..58eb9fbe40 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java @@ -41,7 +41,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(GlobalSettingsPanel.class.getName()); - + private final IngestJobEventPropertyChangeListener ingestJobEventListener; /** @@ -61,12 +61,17 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i "GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties", "GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.", "GlobalSettingsPanel.manageTagsTextArea.text=Configure which tag names are associated with notable items. " - + "When these tags are used, the file or result will be recorded in the central repository. " - + "If that file or result is seen again in future cases, it will be flagged.", - "GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation."}) + + "When these tags are used, the file or result will be recorded in the central repository. " + + "If that file or result is seen again in future cases, it will be flagged.", + "GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.", + "GlobalSettingsPanel.organizationPanel.border.title=Organizations", + "GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations", + "GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository" + }) + private void customizeComponents() { setName(Bundle.GlobalSettingsPanel_title()); - + // The hash set functions of central repo are not being included in the current release. bnImportDatabase.setVisible(false); } @@ -105,6 +110,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i correlationPropertiesScrollPane = new javax.swing.JScrollPane(); correlationPropertiesTextArea = new javax.swing.JTextArea(); lbCentralRepository = new javax.swing.JLabel(); + organizationPanel = new javax.swing.JPanel(); + manageOrganizationButton = new javax.swing.JButton(); + organizationScrollPane = new javax.swing.JScrollPane(); + organizationTextArea = new javax.swing.JTextArea(); setName(""); // NOI18N @@ -234,11 +243,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N tbOops.setBorder(null); - tbOops.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - tbOopsActionPerformed(evt); - } - }); pnCorrelationProperties.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N pnCorrelationProperties.setPreferredSize(new java.awt.Dimension(674, 93)); @@ -289,6 +293,51 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i org.openide.awt.Mnemonics.setLocalizedText(lbCentralRepository, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.lbCentralRepository.text")); // NOI18N + organizationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.organizationPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(manageOrganizationButton, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.manageOrganizationButton.text")); // NOI18N + manageOrganizationButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + manageOrganizationButtonActionPerformed(evt); + } + }); + + organizationScrollPane.setBorder(null); + + organizationTextArea.setEditable(false); + organizationTextArea.setBackground(new java.awt.Color(240, 240, 240)); + organizationTextArea.setColumns(20); + organizationTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + organizationTextArea.setLineWrap(true); + organizationTextArea.setRows(2); + organizationTextArea.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.organizationTextArea.text")); // NOI18N + organizationTextArea.setWrapStyleWord(true); + organizationTextArea.setBorder(null); + organizationScrollPane.setViewportView(organizationTextArea); + + javax.swing.GroupLayout organizationPanelLayout = new javax.swing.GroupLayout(organizationPanel); + organizationPanel.setLayout(organizationPanelLayout); + organizationPanelLayout.setHorizontalGroup( + organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(organizationPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(organizationScrollPane) + .addGroup(organizationPanelLayout.createSequentialGroup() + .addComponent(manageOrganizationButton) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + organizationPanelLayout.setVerticalGroup( + organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, organizationPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(organizationScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(manageOrganizationButton) + .addGap(8, 8, 8)) + ); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -299,15 +348,13 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addComponent(tbOops, javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lbCentralRepository, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnTagManagement, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(bnImportDatabase, javax.swing.GroupLayout.Alignment.LEADING)) - .addGap(0, 0, Short.MAX_VALUE))) + .addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnImportDatabase, javax.swing.GroupLayout.Alignment.LEADING)) .addContainerGap()))) ); layout.setVerticalGroup( @@ -323,9 +370,12 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addGap(0, 0, 0) .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) + .addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) - .addComponent(bnImportDatabase)) + .addComponent(bnImportDatabase) + .addContainerGap()) ); pnTagManagement.getAccessibleContext().setAccessibleName(""); @@ -366,9 +416,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_cbUseCentralRepoActionPerformed - private void tbOopsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbOopsActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_tbOopsActionPerformed + private void manageOrganizationButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manageOrganizationButtonActionPerformed + store(); + ManageOrganizationsDialog dialog = new ManageOrganizationsDialog(); + }//GEN-LAST:event_manageOrganizationButtonActionPerformed @Override @Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."}) @@ -427,6 +478,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i protected void finalize() throws Throwable { IngestManager.getInstance().removeIngestJobEventListener(ingestJobEventListener); super.finalize(); + } /** @@ -511,7 +563,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i * @return True */ private boolean enableButtonSubComponents(Boolean enable) { - boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); + boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); pnCorrelationProperties.setEnabled(enable && !ingestRunning); pnTagManagement.setEnabled(enable && !ingestRunning); bnManageTypes.setEnabled(enable && !ingestRunning); @@ -519,6 +571,9 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i bnManageTags.setEnabled(enable && !ingestRunning); manageTagsTextArea.setEnabled(enable && !ingestRunning); correlationPropertiesTextArea.setEnabled(enable && !ingestRunning); + organizationPanel.setEnabled(enable && !ingestRunning); + organizationTextArea.setEnabled(enable && !ingestRunning); + manageOrganizationButton.setEnabled(enable && !ingestRunning); return true; } @@ -537,8 +592,12 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private javax.swing.JLabel lbDbNameValue; private javax.swing.JLabel lbDbPlatformTypeLabel; private javax.swing.JLabel lbDbPlatformValue; + private javax.swing.JButton manageOrganizationButton; private javax.swing.JScrollPane manageTagsScrollPane; private javax.swing.JTextArea manageTagsTextArea; + private javax.swing.JPanel organizationPanel; + private javax.swing.JScrollPane organizationScrollPane; + private javax.swing.JTextArea organizationTextArea; private javax.swing.JPanel pnCorrelationProperties; private javax.swing.JPanel pnDatabaseConfiguration; private javax.swing.JPanel pnTagManagement; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.form new file mode 100644 index 0000000000..0655ced314 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.form @@ -0,0 +1,356 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java new file mode 100644 index 0000000000..ad6c26e4d8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java @@ -0,0 +1,456 @@ +/* + * Central Repository + * + * Copyright 2015-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.centralrepository.optionspanel; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.util.List; +import java.util.logging.Level; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.coreutils.Logger; + +public final class ManageOrganizationsDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private EamDb dbManager; + private EamOrganization newOrg; + private final DefaultListModel rulesListModel = new DefaultListModel<>(); + private final static Logger LOGGER = Logger.getLogger(ManageOrganizationsDialog.class.getName()); + + @Messages({"ManageOrganizationsDialog.title.text=Manage Organizations"}) + /** + * Creates new form ManageOrganizationsPanel + */ + public ManageOrganizationsDialog() { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.ManageOrganizationsDialog_title_text(), + true); // NON-NLS + initComponents(); + try { + this.dbManager = EamDb.getInstance(); + organizationList.setCellRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1L; + + @SuppressWarnings("rawtypes") + @Override + public Component getListCellRendererComponent(javax.swing.JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setText(((EamOrganization) value).getName()); + return c; + } + }); + organizationList.setModel(rulesListModel); + organizationList.addListSelectionListener(new OrganizationListSelectionListener()); + populateList(); + setButtonsEnabled(organizationList.getSelectedValue() != null); + newOrg = null; + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + } + display(); + } + + private void display() { + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); + setVisible(true); + } + + private void populateListAndSelect(EamOrganization selected) throws EamDbException { + rulesListModel.clear(); + List orgs = dbManager.getOrganizations(); + if (orgs.size() > 0) { + for (EamOrganization org : orgs) { + rulesListModel.addElement(org); + if (selected != null && org.getOrgID() == selected.getOrgID()) { + selected = org; + } + } + if (orgs.contains(selected)) { + organizationList.setSelectedValue(selected, true); + } else { + organizationList.setSelectedIndex(0); + } + organizationList.validate(); + organizationList.repaint(); + } + } + + private void populateList() throws EamDbException { + EamOrganization selected = organizationList.getSelectedValue(); + populateListAndSelect(selected); + } + + @Messages({"ManageOrganizationsDialog.pocNameLabel.text=Point of Contact Name:", + "ManageOrganizationsDialog.deleteButton.text=Delete", + "ManageOrganizationsDialog.newButton.text=New", + "ManageOrganizationsDialog.closeButton.text=Close", + "ManageOrganizationsDialog.orgNameLabel.text=Organization Name:", + "ManageOrganizationsDialog.pocEmailLabel.text=Point of Contact Email:", + "ManageOrganizationsDialog.editButton.text=Edit", + "ManageOrganizationsDialog.pocPhoneLabel.text=Point of Contact Phone:", + "ManageOrganizationsDialog.orgDescriptionTextArea.text=Organizations are used to provide additional contact information for the content they are associated with.", + "ManageOrganizationsDialog.orgListLabel.text=Organizations", + "ManageOrganizationsDialog.orgDetailsLabel.text=Organization Details", + "ManageOrganizationsDialog.confirmDeletion.title=Confirm Deletion", + "ManageOrganizationsDialog.confirmDeletion.message=Are you sure you want to delete the selected organization from the central repo?", + "ManageOrganizationsDialog.unableToDeleteOrg.title=Unable to Delete", + "ManageOrganizationsDialog.unableToDeleteOrg.message=Unable to delete selected organizaiton."}) + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + manageOrganizationsScrollPane = new javax.swing.JScrollPane(); + manageOrganizationsPanel = new javax.swing.JPanel(); + orgListScrollPane = new javax.swing.JScrollPane(); + organizationList = new javax.swing.JList<>(); + orgDescriptionScrollPane = new javax.swing.JScrollPane(); + orgDescriptionTextArea = new javax.swing.JTextArea(); + newButton = new javax.swing.JButton(); + deleteButton = new javax.swing.JButton(); + closeButton = new javax.swing.JButton(); + orgListLabel = new javax.swing.JLabel(); + jSeparator1 = new javax.swing.JSeparator(); + pocNameLabel = new javax.swing.JLabel(); + pocPhoneLabel = new javax.swing.JLabel(); + pocEmailLabel = new javax.swing.JLabel(); + orgNameLabel = new javax.swing.JLabel(); + orgNameTextField = new javax.swing.JTextField(); + pocNameTextField = new javax.swing.JTextField(); + pocPhoneTextField = new javax.swing.JTextField(); + pocEmailTextField = new javax.swing.JTextField(); + editButton = new javax.swing.JButton(); + orgDetailsLabel = new javax.swing.JLabel(); + + setMinimumSize(new java.awt.Dimension(545, 450)); + + manageOrganizationsScrollPane.setMinimumSize(null); + manageOrganizationsScrollPane.setPreferredSize(new java.awt.Dimension(535, 415)); + + manageOrganizationsPanel.setPreferredSize(new java.awt.Dimension(527, 407)); + + organizationList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + orgListScrollPane.setViewportView(organizationList); + + orgDescriptionTextArea.setEditable(false); + orgDescriptionTextArea.setBackground(new java.awt.Color(240, 240, 240)); + orgDescriptionTextArea.setColumns(20); + orgDescriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + orgDescriptionTextArea.setLineWrap(true); + orgDescriptionTextArea.setRows(3); + orgDescriptionTextArea.setText(org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.orgDescriptionTextArea.text")); // NOI18N + orgDescriptionTextArea.setWrapStyleWord(true); + orgDescriptionScrollPane.setViewportView(orgDescriptionTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(newButton, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.newButton.text")); // NOI18N + newButton.setMargin(new java.awt.Insets(2, 6, 2, 6)); + newButton.setMaximumSize(new java.awt.Dimension(70, 23)); + newButton.setMinimumSize(new java.awt.Dimension(70, 23)); + newButton.setPreferredSize(new java.awt.Dimension(70, 23)); + newButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + newButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.deleteButton.text")); // NOI18N + deleteButton.setMargin(new java.awt.Insets(2, 6, 2, 6)); + deleteButton.setMaximumSize(new java.awt.Dimension(70, 23)); + deleteButton.setMinimumSize(new java.awt.Dimension(70, 23)); + deleteButton.setPreferredSize(new java.awt.Dimension(70, 23)); + deleteButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.closeButton.text")); // NOI18N + closeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(orgListLabel, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.orgListLabel.text")); // NOI18N + + jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + + org.openide.awt.Mnemonics.setLocalizedText(pocNameLabel, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.pocNameLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(pocPhoneLabel, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.pocPhoneLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(pocEmailLabel, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.pocEmailLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(orgNameLabel, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.orgNameLabel.text")); // NOI18N + + orgNameTextField.setEditable(false); + + pocNameTextField.setEditable(false); + + pocPhoneTextField.setEditable(false); + + pocEmailTextField.setEditable(false); + + org.openide.awt.Mnemonics.setLocalizedText(editButton, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.editButton.text")); // NOI18N + editButton.setMaximumSize(new java.awt.Dimension(70, 23)); + editButton.setMinimumSize(new java.awt.Dimension(70, 23)); + editButton.setPreferredSize(new java.awt.Dimension(70, 23)); + editButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + editButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(orgDetailsLabel, org.openide.util.NbBundle.getMessage(ManageOrganizationsDialog.class, "ManageOrganizationsDialog.orgDetailsLabel.text")); // NOI18N + + javax.swing.GroupLayout manageOrganizationsPanelLayout = new javax.swing.GroupLayout(manageOrganizationsPanel); + manageOrganizationsPanel.setLayout(manageOrganizationsPanelLayout); + manageOrganizationsPanelLayout.setHorizontalGroup( + manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(orgDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(orgListLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addComponent(newButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(orgListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(closeButton)) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addGap(29, 29, 29) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(pocNameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(orgNameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pocPhoneLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pocEmailLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pocNameTextField) + .addComponent(pocPhoneTextField) + .addComponent(pocEmailTextField, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(orgNameTextField)))) + .addContainerGap()) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(orgDetailsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + ); + manageOrganizationsPanelLayout.setVerticalGroup( + manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addComponent(orgDetailsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(orgNameLabel) + .addComponent(orgNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(pocNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pocNameLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(pocPhoneTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pocPhoneLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(pocEmailTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pocEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 235, Short.MAX_VALUE) + .addComponent(closeButton)) + .addComponent(jSeparator1) + .addGroup(manageOrganizationsPanelLayout.createSequentialGroup() + .addComponent(orgDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(orgListLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(orgListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(manageOrganizationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addContainerGap()) + ); + + manageOrganizationsScrollPane.setViewportView(manageOrganizationsPanel); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(manageOrganizationsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(manageOrganizationsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed + EamOrganization orgToDelete = organizationList.getSelectedValue(); + if (orgToDelete != null) { + if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), + Bundle.ManageOrganizationsDialog_confirmDeletion_message(), + Bundle.ManageOrganizationsDialog_confirmDeletion_title(), + JOptionPane.YES_NO_OPTION)) { + try { + EamDb.getInstance().deleteOrganization(orgToDelete); + populateList(); + } catch (EamDbException ex) { + JOptionPane.showMessageDialog(null, + ex.getMessage(), Bundle.ManageOrganizationsDialog_unableToDeleteOrg_title(), JOptionPane.WARNING_MESSAGE); + LOGGER.log(Level.INFO, "Was unable to delete organization from central repository", ex); + } + } + } + }//GEN-LAST:event_deleteButtonActionPerformed + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed + dispose(); + }//GEN-LAST:event_closeButtonActionPerformed + + private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed + AddNewOrganizationDialog dialogO = new AddNewOrganizationDialog(); + if (dialogO.isChanged()) { + try { + newOrg = dialogO.getNewOrg(); + populateListAndSelect(dialogO.getNewOrg()); + } catch (EamDbException ex) { + + } + } + }//GEN-LAST:event_newButtonActionPerformed + + private void editButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editButtonActionPerformed + EamOrganization orgToEdit = organizationList.getSelectedValue(); + if (orgToEdit != null) { + AddNewOrganizationDialog dialogO = new AddNewOrganizationDialog(orgToEdit); + if (dialogO.isChanged()) { + try { + newOrg = dialogO.getNewOrg(); + populateListAndSelect(dialogO.getNewOrg()); + } catch (EamDbException ex) { + + } + } + } + }//GEN-LAST:event_editButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private javax.swing.JButton deleteButton; + private javax.swing.JButton editButton; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JPanel manageOrganizationsPanel; + private javax.swing.JScrollPane manageOrganizationsScrollPane; + private javax.swing.JButton newButton; + private javax.swing.JScrollPane orgDescriptionScrollPane; + private javax.swing.JTextArea orgDescriptionTextArea; + private javax.swing.JLabel orgDetailsLabel; + private javax.swing.JLabel orgListLabel; + private javax.swing.JScrollPane orgListScrollPane; + private javax.swing.JLabel orgNameLabel; + private javax.swing.JTextField orgNameTextField; + private javax.swing.JList organizationList; + private javax.swing.JLabel pocEmailLabel; + private javax.swing.JTextField pocEmailTextField; + private javax.swing.JLabel pocNameLabel; + private javax.swing.JTextField pocNameTextField; + private javax.swing.JLabel pocPhoneLabel; + private javax.swing.JTextField pocPhoneTextField; + // End of variables declaration//GEN-END:variables + public boolean isChanged() { + return newOrg != null; + } + + public EamOrganization getNewOrg() { + return newOrg; + } + + private void setButtonsEnabled(boolean isSelected) { + editButton.setEnabled(isSelected); + deleteButton.setEnabled(isSelected); + } + + /** + * A list events listener for the interesting files sets list component. + */ + private final class OrganizationListSelectionListener implements ListSelectionListener { + + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + EamOrganization selected = organizationList.getSelectedValue(); + boolean isSelected = (selected != null); + setButtonsEnabled(isSelected); + if (selected != null) { + orgNameTextField.setText(selected.getName()); + pocNameTextField.setText(selected.getPocName()); + pocPhoneTextField.setText(selected.getPocPhone()); + pocEmailTextField.setText(selected.getPocEmail()); + } else { + orgNameTextField.setText(""); + pocNameTextField.setText(""); + pocPhoneTextField.setText(""); + pocEmailTextField.setText(""); + } + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 0b660acd2a..83250f719d 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -29,15 +29,15 @@ import java.util.logging.Handler; import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; -import javax.swing.SwingWorker; -import org.openide.LifecycleManager; import org.openide.modules.ModuleInstall; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.IngestRunningCheck; import org.sleuthkit.autopsy.casemodule.Case; +import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** @@ -206,6 +206,9 @@ public class Installer extends ModuleInstall { // Prevent the Autopsy UI from shrinking on high DPI displays System.setProperty("sun.java2d.dpiaware", "false"); System.setProperty("prism.allowhidpi", "false"); + + // Update existing configuration in case of unsupported settings + updateConfig(); packageInstallers = new ArrayList<>(); packageInstallers.add(org.sleuthkit.autopsy.coreutils.Installer.getDefault()); @@ -214,6 +217,21 @@ public class Installer extends ModuleInstall { packageInstallers.add(org.sleuthkit.autopsy.ingest.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.centralrepository.eventlisteners.Installer.getDefault()); } + + /** + * If the mode in the configuration file is 'REVIEW' (2, now invalid), this + * method will set it to 'STANDALONE' (0) and disable auto ingest. + */ + private void updateConfig() { + String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); + if(mode != null) { + int ordinal = Integer.parseInt(mode); + if(ordinal > 1) { + UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + } + } + } /** * Check if JavaFx initialized diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index df63b0fa1f..86f68e1df5 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import java.util.prefs.BackingStoreException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; -import org.openide.util.Exceptions; import org.openide.util.NbPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -76,8 +75,7 @@ public final class UserPreferences { public enum SelectedMode { STANDALONE, - AUTOINGEST, - REVIEW + AUTOINGEST }; /** diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 09514caddf..e06fc9ac45 100755 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -51,7 +51,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -165,11 +165,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java index 753ccd598a..4c7c022871 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ThreadUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ThreadUtils.java new file mode 100644 index 0000000000..80f0467781 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ThreadUtils.java @@ -0,0 +1,67 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.coreutils; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +/* + * General purpose actions which can be performed on Threads. + */ +final public class ThreadUtils { + + private static final long DEFAULT_TIMEOUT = 5; + private static final TimeUnit DEFAULT_TIMEOUT_UNITS = TimeUnit.SECONDS; + + /** + * Shuts down a task executor service, waiting until all tasks are + * terminated. + * + * @param executor The executor. + */ + public static void shutDownTaskExecutor(ExecutorService executor) { + executor.shutdown(); + boolean taskCompleted = false; + while (!taskCompleted) { + try { + taskCompleted = executor.awaitTermination(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNITS); + } catch (InterruptedException ignored) { + /* + * The current policy is to wait for the task to finish so that + * the case can be left in a consistent state. + * + * For a specific example of the motivation for this policy, + * note that a application service (Solr search service) + * experienced an error condition when opening case resources + * that left the service blocked uninterruptibly on a socket + * read. This eventually led to a mysterious "freeze" as the + * user-cancelled service task continued to run holdiong a lock + * that a UI thread soon tried to acquire. Thus it has been + * deemed better to make the "freeze" happen in a more + * informative way, i.e., with the progress indicator for the + * unfinished task on the screen, if a similar error condition + * arises again. + */ + } + } + } + + private ThreadUtils() { + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java similarity index 73% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java rename to Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java index fe53871dd5..e14b5c5897 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -24,32 +24,32 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Utility methods for working with strings with the time-stamp suffixes used by - * auto ingest. + * Utility methods for working with time stamps of the form + * 'yyyy_MM_dd_HH_mm_ss'. */ public final class TimeStampUtils { /* * Sample time stamp suffix: 2015_02_02_12_10_31 */ - private static final Pattern timeStampPattern = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$"); + private static final Pattern TIME_STAMP_PATTERN = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$"); private static final int LENGTH_OF_DATE_TIME_STAMP = 20; // length of the above time stamp - private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); /** - * Checks whether a string ends with an auto ingest time stamp. + * Checks whether a string ends with a time stamp. * * @param inputString The string to check. * * @return True or false. */ public static boolean endsWithTimeStamp(String inputString) { - Matcher m = timeStampPattern.matcher(inputString); + Matcher m = TIME_STAMP_PATTERN.matcher(inputString); return m.find(); } /** - * Gets the fixed length of the auto-ingest time stamp suffix. + * Gets the fixed length of the time stamp suffix. * * @return The length. */ @@ -58,16 +58,16 @@ public final class TimeStampUtils { } /** - * Creates an auto ingest time stamp suffix using the current time. + * Creates a time stamp suffix using the current time. * * @return The suffix. */ public static String createTimeStamp() { - return dateFormat.format(Calendar.getInstance().getTime()); + return DATE_FORMAT.format(Calendar.getInstance().getTime()); } /** - * Removes an auto ingest timestamp suffix, if it present. + * Removes the time stamp suffix from a string, if present. * * @param inputString The string to trim. * @@ -82,7 +82,7 @@ public final class TimeStampUtils { } /** - * Gets the auto ingest time stamp suffix from a string, if it is present. + * Gets the time stamp suffix from a string, if present. * * @param inputString the name to check for a timestamp * diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java index 67f65be80b..149e11afa5 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java @@ -31,9 +31,20 @@ import javax.swing.JComponent; abstract class AbstractFileSearchFilter implements FileSearchFilter { final private T component; - + private String lastErrorMessage; + AbstractFileSearchFilter(T component) { this.component = component; + this.lastErrorMessage = ""; + } + + void setLastError(String mes){ + lastErrorMessage = mes; + } + + @Override + public String getLastError(){ + return this.lastErrorMessage; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties index fff8007fd4..bb91c8e05c 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties @@ -57,4 +57,5 @@ MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected FileSearchPanel.searchButton.text=Search MimeTypePanel.mimeTypeCheckBox.text=MIME Type: HashSearchPanel.md5CheckBox.text=MD5: -HashSearchPanel.emptyHashMsg.text=Must enter something for hash search. \ No newline at end of file +HashSearchPanel.emptyHashMsg.text=Must enter something for hash search. +FileSearchPanel.errorLabel.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 205db56998..3291c5ae42 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -42,6 +42,7 @@ import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.openide.util.NbBundle.Messages; /** * Filters file date properties (modified/created/etc.. times) @@ -79,25 +80,10 @@ class DateSearchFilter extends AbstractFileSearchFilter { String query = "NULL"; DateSearchPanel panel = this.getComponent(); - // first, get the selected timeZone from the dropdown list - String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString(); - String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID - TimeZone selectedTZ = TimeZone.getTimeZone(tzID); // - // convert the date from the selected timezone to get the GMT long fromDate = 0; String startDateValue = panel.getDateFromTextField().getText(); - Calendar startDate = null; - try { - DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); - sdf.setTimeZone(selectedTZ); // get the time in the selected timezone - Date temp = sdf.parse(startDateValue); - - startDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS - startDate.setTime(temp); // convert to GMT - } catch (ParseException ex) { - // for now, no need to show the error message to the user here - } + Calendar startDate = getCalendarDate(startDateValue); if (!startDateValue.isEmpty()) { if (startDate != null) { fromDate = startDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds @@ -106,31 +92,13 @@ class DateSearchFilter extends AbstractFileSearchFilter { long toDate = 0; String endDateValue = panel.getDateToTextField().getText(); - Calendar endDate = null; - try { - DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); - sdf.setTimeZone(selectedTZ); // get the time in the selected timezone - Date temp2 = sdf.parse(endDateValue); - - endDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS - endDate.setTime(temp2); // convert to GMT - endDate.set(Calendar.HOUR, endDate.get(Calendar.HOUR) + 24); // get the next 24 hours - } catch (ParseException ex) { - // for now, no need to show the error message to the user here - } + Calendar endDate = getCalendarDate(endDateValue); if (!endDateValue.isEmpty()) { if (endDate != null) { toDate = endDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds } } - // If they put the dates in backwards, help them out. - if (fromDate > toDate) { - long temp = toDate; - toDate = fromDate; - fromDate = temp; - } - final boolean modifiedChecked = panel.getModifiedCheckBox().isSelected(); final boolean changedChecked = panel.getChangedCheckBox().isSelected(); final boolean accessedChecked = panel.getAccessedCheckBox().isSelected(); @@ -206,14 +174,56 @@ class DateSearchFilter extends AbstractFileSearchFilter { return timeZones; } + private TimeZone getSelectedTimeZone() { + String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString(); + String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID + TimeZone selectedTZ = TimeZone.getTimeZone(tzID); // + return selectedTZ; + } + + private Calendar getCalendarDate(String dateValue) { + TimeZone selectedTZ = getSelectedTimeZone(); + Calendar inputDate = null; + try { + DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); + sdf.setTimeZone(selectedTZ); // get the time in the selected timezone + Date temp = sdf.parse(dateValue); + + inputDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS + inputDate.setTime(temp); // convert to GMT + } catch (ParseException ex) { + // for now, no need to show the error message to the user here + } + return inputDate; + } + @Override public void addActionListener(ActionListener l) { getComponent().addActionListener(l); } @Override + @Messages ({ + "DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date.", + "DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected." + }) public boolean isValid() { - return this.getComponent().isValidSearch(); + + DateSearchPanel panel = this.getComponent(); + Calendar startDate = getCalendarDate(panel.getDateFromTextField().getText()); + Calendar endDate = getCalendarDate(panel.getDateToTextField().getText()); + + if ((startDate != null && startDate.after(endDate)) || (endDate != null && endDate.before(startDate))) { + setLastError(Bundle.DateSearchFilter_errorMessage_endDateBeforeStartDate()); + return false; + } + + if (!panel.isValidSearch()) { + setLastError(Bundle.DateSearchFilter_errorMessage_noCheckboxSelected()); + return false; + } + + return true; } /** diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form index e92d57fdd9..59082745da 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form @@ -149,6 +149,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index 7867a5ebd6..b9f490041b 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -29,6 +29,8 @@ import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; /** * Subpanel with controls for file data filtering. @@ -50,6 +52,7 @@ class DateSearchPanel extends javax.swing.JPanel { dateFromTextField.setComponentPopupMenu(rightClickMenu); dateToTextField.setComponentPopupMenu(rightClickMenu); + ActionListener actList = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -74,6 +77,41 @@ class DateSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); + this.dateFromTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); + + this.dateToTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); + + this.setComponentsEnabled(); } @@ -176,6 +214,7 @@ class DateSearchPanel extends javax.swing.JPanel { selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.selectAllMenuItem.text")); // NOI18N rightClickMenu.add(selectAllMenuItem); + dateToTextField.setEditable(false); dateToTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToTextField.text")); // NOI18N dateToTextField.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { @@ -197,6 +236,7 @@ class DateSearchPanel extends javax.swing.JPanel { jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N jLabel3.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel3.text")); // NOI18N + dateFromTextField.setEditable(false); dateFromTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromTextField.text")); // NOI18N dateFromTextField.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { @@ -365,6 +405,7 @@ class DateSearchPanel extends javax.swing.JPanel { if (evt.getNewValue() instanceof Date) { setToDate((Date) evt.getNewValue()); } + }//GEN-LAST:event_dateToPopupChanged private void dateCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateCheckBoxActionPerformed @@ -399,6 +440,7 @@ class DateSearchPanel extends javax.swing.JPanel { if (date != null) { dateStringResult = dateFormat.format(date); } + dateFromTextField.setText(dateStringResult); dateFromButtonCalendar.setTargetDate(date); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java index 457db56570..db16fdd1e0 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java @@ -47,6 +47,13 @@ interface FileSearchFilter { * @return Whether the panel has valid input for search. */ boolean isValid(); + + /** + * Get the last error recorded during the call to isValid + * + * @return Description of why the filter is invalid + */ + String getLastError(); /** * Gets predicate expression to include in the SQL filter expression diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form index dbb90bea12..a64489bb01 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form @@ -23,7 +23,9 @@ - + + + @@ -32,9 +34,14 @@ - - - + + + + + + + + @@ -63,6 +70,19 @@ + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index d7efb0b46f..f6c72df611 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -27,7 +27,6 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -111,13 +110,7 @@ class FileSearchPanel extends javax.swing.JPanel { } }); } - - addListenerToAll(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - search(); - } - }); + searchButton.setEnabled(isValidSearch()); } @@ -130,11 +123,13 @@ class FileSearchPanel extends javax.swing.JPanel { if (filter.isEnabled()) { enabled = true; if (!filter.isValid()) { + errorLabel.setText(filter.getLastError()); return false; } } } + errorLabel.setText(""); return enabled; } @@ -280,6 +275,7 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel = new javax.swing.JPanel(); searchButton = new javax.swing.JButton(); + errorLabel = new javax.swing.JLabel(); setPreferredSize(new java.awt.Dimension(300, 300)); @@ -288,6 +284,14 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS)); searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N + searchButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + searchButtonActionPerformed(evt); + } + }); + + errorLabel.setForeground(new java.awt.Color(255, 51, 51)); + errorLabel.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.errorLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -295,21 +299,31 @@ class FileSearchPanel extends javax.swing.JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap() + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(searchButton) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(0, 0, 0) - .addComponent(searchButton) + .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(searchButton) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel))) .addContainerGap()) ); }// //GEN-END:initComponents + private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed + search(); + }//GEN-LAST:event_searchButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel errorLabel; private javax.swing.JPanel filterPanel; private javax.swing.JButton searchButton; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index 951f4b206e..d77fe5826e 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -60,7 +61,25 @@ class HashSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages({ + "HashSearchFilter.errorMessage.emptyHash=Hash data is empty.", + "# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input length({0}), doesn''t match the MD5 length(32).", + "HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters." + }) public boolean isValid() { - return !this.getComponent().getSearchTextField().getText().isEmpty(); + String inputHashData = this.getComponent().getSearchTextField().getText(); + if (inputHashData.isEmpty()) { + setLastError(Bundle.HashSearchFilter_errorMessage_emptyHash()); + return false; + } + if (inputHashData.length() != 32) { + setLastError(Bundle.HashSearchFilter_errorMessage_wrongLength(inputHashData.length())); + return false; + } + if (!inputHashData.matches("[0-9a-fA-F]+")) { + setLastError(Bundle.HashSearchFilter_errorMessage_wrongCharacter()); + return false; + } + return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index 5f52afa035..677f0116e9 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.TskData.FileKnown; /** @@ -85,7 +86,14 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages ({ + "MimeTypeFilter.errorMessage.emptyMimeType=At least one MIME type must be selected." + }) public boolean isValid() { - return !this.getComponent().getMimeTypesSelected().isEmpty(); + if(this.getComponent().getMimeTypesSelected().isEmpty()){ + setLastError(Bundle.MimeTypeFilter_errorMessage_emptyMimeType()); + return false; + } + return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java index ee70ebd5e1..2b204c8ca8 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -64,7 +65,14 @@ class NameSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages ({ + "NameSearchFilter.errorMessage.emtpyName=Please input a name to search." + }) public boolean isValid() { - return !this.getComponent().getSearchTextField().getText().isEmpty(); + if(this.getComponent().getSearchTextField().getText().isEmpty()) { + setLastError(Bundle.NameSearchFilter_errorMessage_emtpyName()); + return false; + } + return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java index ca43dac7e0..cf5d4f9e73 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import javax.swing.JComboBox; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -74,7 +75,23 @@ class SizeSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages ({ + "SizeSearchFilter.errorMessage.nonNegativeNumber=Input size data is a negative number.", + "SizeSearchFilter.errorMessage.notANumber=Input size data is not a number." + }) public boolean isValid() { + String input = this.getComponent().getSizeTextField().getText(); + + try { + int inputInt = Integer.parseInt(input); + if (inputInt < 0) { + setLastError(Bundle.SizeSearchFilter_errorMessage_nonNegativeNumber()); + return false; + } + } catch (NumberFormatException | NullPointerException e) { + setLastError(Bundle.SizeSearchFilter_errorMessage_notANumber()); + return false; + } return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java index 3add979247..51aa688619 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java @@ -25,6 +25,8 @@ import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JMenuItem; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; /** * @@ -65,6 +67,24 @@ class SizeSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); + this.sizeTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); + + } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java index b9040b674b..af37f3f2e3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import static javax.swing.SwingConstants.CENTER; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java similarity index 71% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java index 6bac0a996b..970dafacfc 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; +import java.awt.Color; import java.awt.Component; import java.time.Duration; import javax.swing.JTable; @@ -28,11 +29,11 @@ import static javax.swing.SwingConstants.CENTER; * string with days, hours, minutes, and seconds components. It center-aligns * cell content and grays out the cell if the table is disabled. */ -class DurationCellRenderer extends GrayableCellRenderer { +public class DurationCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; - DurationCellRenderer() { + public DurationCellRenderer() { setHorizontalAlignment(CENTER); } @@ -71,4 +72,26 @@ class DurationCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java index 60d3b77ccd..53031faae3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import java.awt.Color; import java.awt.Component; @@ -28,11 +28,11 @@ import javax.swing.table.DefaultTableCellRenderer; * A JTable cell renderer that left-aligns cell content and grays out the cell * if the table is disabled. */ -class GrayableCellRenderer extends DefaultTableCellRenderer { +public class GrayableCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; - GrayableCellRenderer() { + public GrayableCellRenderer() { setHorizontalAlignment(LEFT); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java index cfa2cedb14..373e4e2501 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import java.awt.Component; import java.text.SimpleDateFormat; @@ -28,7 +28,7 @@ import static javax.swing.SwingConstants.CENTER; * center-aligned, long-format date string. It also grays out the cell if the * table is disabled. */ -class LongDateCellRenderer extends GrayableCellRenderer { +public class LongDateCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java similarity index 66% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java index 713d177c0a..299880f1c0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java @@ -16,8 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; +import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; import javax.swing.JTable; @@ -46,4 +47,26 @@ class ShortDateCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java new file mode 100755 index 0000000000..b7ee58e4d4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java @@ -0,0 +1,74 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.guiutils; + +import java.awt.Component; +import javax.swing.ImageIcon; +import javax.swing.JTable; +import static javax.swing.SwingConstants.CENTER; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; + +/** + * A JTable cell renderer that represents a status as a center-aligned icon, and + * grays out the cell if the table is disabled. The statuses represented are OK, + * WARNING, and ERROR. + */ +public class StatusIconCellRenderer extends GrayableCellRenderer { + + private static final long serialVersionUID = 1L; + static final ImageIcon OK_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/tick.png", false)); + static final ImageIcon WARNING_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/warning16.png", false)); + static final ImageIcon ERROR_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/cross-script.png", false)); + + @Messages({ + "StatusIconCellRenderer.tooltiptext.ok=OK", + "StatusIconCellRenderer.tooltiptext.warning=A warning occurred", + "StatusIconCellRenderer.tooltiptext.error=An error occurred" + }) + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + setHorizontalAlignment(CENTER); + if ((value instanceof Status)) { + switch((Status) value) { + case OK: + setIcon(OK_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.ok")); + break; + case WARNING: + setIcon(WARNING_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.warning")); + break; + case ERROR: + setIcon(ERROR_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.error")); + break; + } + } + grayCellIfTableNotEnabled(table, isSelected); + + return this; + } + + public enum Status { + OK, + WARNING, + ERROR + } +} diff --git a/Core/src/org/sleuthkit/autopsy/images/tick.png b/Core/src/org/sleuthkit/autopsy/images/tick.png new file mode 100755 index 0000000000..a7d7a96be3 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/tick.png differ diff --git a/Core/src/org/sleuthkit/autopsy/images/warning16.png b/Core/src/org/sleuthkit/autopsy/images/warning16.png new file mode 100755 index 0000000000..f5ba881738 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/warning16.png differ diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 3110947488..249ded2020 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -33,7 +33,8 @@ import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; */ class ProfilePanel extends IngestModuleGlobalSettingsPanel { - @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Description:", + @NbBundle.Messages({"ProfilePanel.title.text=Profile", + "ProfilePanel.profileDescLabel.text=Description:", "ProfilePanel.profileNameLabel.text=Profile Name:", "ProfilePanel.newProfileText=NewEmptyProfile", "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.", @@ -50,6 +51,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { */ ProfilePanel() { initComponents(); + setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text")); settings = new IngestJobSettings(NEW_PROFILE_NAME); ingestSettingsPanel = new IngestJobSettingsPanel(settings); ingestSettingsPanel.setPastJobsButtonVisible(false); @@ -59,6 +61,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { ProfilePanel(IngestProfile selectedProfile) { initComponents(); + setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text")); profile = selectedProfile; profileDescArea.setText(profile.getDescription()); profileNameField.setText(profile.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties index df63e98d2e..f38bcbc815 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties @@ -4,8 +4,6 @@ OpenIDE-Module-Short-Description=Interesting Files Identifier ingest module. OpenIDE-Module-Name=Interesting Files Identifier OptionsCategory_Name_InterestingItemDefinitions=Interesting Files OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions -OptionsCategory_Name_FileIngestFilterDefinitions=File Ingest Filter -OptionsCategory_Keywords_FileIngestFilterDefinitions=FileIngestFilterDefinitions InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets. FilesSetPanel.interesting.title=Interesting Files Set @@ -45,7 +43,7 @@ FilesSetRulePanel.fileSizeCheck.text=File Size: FilesSetRulePanel.filesRadioButton.text=Files FilesSetRulePanel.dirsRadioButton.text=Directories FilesSetDefsPanel.interesting.setsListLabel.text=Rule Sets: -FilesSetDefsPanel.ingest.setsListLabel.text=File Ingest Filters: +FilesSetDefsPanel.ingest.setsListLabel.text=File Filters: FilesSetDefsPanel.interesting.jTextArea1.text=This module allows you to find files that match specified criteria. Each set has a list of rules, which will match on their chosen file characteristics. A file need only match one rule to be found. FilesSetDefsPanel.ingest.jTextArea1.text=Add rules so that only a subset of the files in a data source are analyzed. Rules are organized into sets and only one set can be used at a time. A file need only match one rule to be analyzed. FilesSetDefsPanel.interesting.editSetButton.text=Edit Set diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index f989d24971..c67051be97 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -77,6 +77,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private final JButton okButton = new JButton("OK"); private final JButton cancelButton = new JButton("Cancel"); private final PANEL_TYPE panelType; + private final String filterDialogTitle; private final String ruleDialogTitle; private boolean canBeEnabled = true; @@ -109,7 +110,8 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp this.jLabel7.setVisible(false); this.fileSizeUnitComboBox.setVisible(false); this.fileSizeSpinner.setVisible(false); - this.ruleDialogTitle = "FilesSetPanel.ingest.title"; + this.filterDialogTitle = "FilesSetPanel.filter.title"; + this.ruleDialogTitle = "FilesSetPanel.rule.title"; this.jLabel8.setVisible(false); this.equalitySignComboBox.setVisible(false); this.ignoreKnownFilesCheckbox.setVisible(false); @@ -124,13 +126,14 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp org.openide.awt.Mnemonics.setLocalizedText(deleteSetButton, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.deleteSetButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.jLabel6.text")); // NOI18N } else { + this.filterDialogTitle = "FilesSetPanel.interesting.title"; this.ruleDialogTitle = "FilesSetPanel.interesting.title"; this.ingoreUnallocCheckbox.setVisible(false); } } @NbBundle.Messages({"FilesSetDefsPanel.Interesting.Title=Global Interesting Items Settings", - "FilesSetDefsPanel.Ingest.Title=File Ingest Filter Settings"}) + "FilesSetDefsPanel.Ingest.Title=File Filter Settings"}) private void customInit() { if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { setName(Bundle.FilesSetDefsPanel_Ingest_Title()); @@ -408,7 +411,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp // feedback when isValidDefinition() is called. int option = JOptionPane.OK_OPTION; do { - option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, ruleDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, filterDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); // While adding new ruleset(selectedSet == null), if rule set with same name already exists, do not add to the filesSets hashMap. diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java index 962c18c8e1..51539b5806 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2016 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY */ public class FilesSetPanel extends javax.swing.JPanel { - @NbBundle.Messages({"FilesSetPanel.ingest.title=File Ingest Filter", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."}) + @NbBundle.Messages({"FilesSetPanel.filter.title=File Filter", "FilesSetPanel.rule.title=File Filter Rule", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."}) private static final String CREATE_NEW_FILE_INGEST_FILTER = Bundle.FilesSetPanel_ingest_createNewFilter(); private final String mustBeNamedErrorText; diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index 234ed1509c..2a8235ee08 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -168,14 +169,27 @@ class TableReportGenerator { return "unknown"; } }); - for (String accountType : groupedArtifacts.keySet()) { + for (String accountTypeStr : groupedArtifacts.keySet()) { /* If the report is a ReportHTML, the data type name * eventualy makes it to useDataTypeIcon which expects but * does not require a artifact name, so we make a synthetic * compund name by appending a ":" and the account type. */ - final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountType; - writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment); + String accountDisplayname = accountTypeStr; + if (accountTypeStr != null) { + try { + Account.Type acctType = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().getAccountType(accountTypeStr); + if (acctType != null) { + accountDisplayname = acctType.getDisplayName(); + } + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Unable to get dusplay name for account type.", ex); + } + } + + final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname; + writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountTypeStr)), type, compundDataTypeName, comment); } } else { //all other artifact types are sent to writeTableForDataType directly diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index 93dad76f89..1066973f58 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; - /** * Instances of this class are used to configure the report module plug in that * provides a convenient way to add content hashes to hash set databases. @@ -94,9 +93,11 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { public void mousePressed(MouseEvent evt) { JList list = (JList) evt.getSource(); int index = list.locationToIndex(evt.getPoint()); - String value = tagsNamesListModel.getElementAt(index); - tagNameSelections.put(value, !tagNameSelections.get(value)); - list.repaint(); + if (index > -1) { + String value = tagsNamesListModel.getElementAt(index); + tagNameSelections.put(value, !tagNameSelections.get(value)); + list.repaint(); + } } }); } diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java new file mode 100755 index 0000000000..843e9e53fa --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -0,0 +1,71 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.ingest; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import junit.framework.TestCase; +import org.netbeans.junit.NbModuleSuite; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; +import junit.framework.Test; +import org.apache.commons.io.FileUtils; +import org.openide.util.Exceptions; + +public class IngestFileFiltersTest extends TestCase { + + private static final Path caseDirectoryPath = Paths.get(System.getProperty("java.io.tmpdir"), "IngestFileFiltersTest"); + private static final File CASE_DIR = new File(caseDirectoryPath.toString()); + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestFileFiltersTest.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + @Override + public void setUp() { + try { + Case.createAsCurrentCase(Case.CaseType.SINGLE_USER_CASE, caseDirectoryPath.toString(), new CaseDetails("IngestFiltersTest")); + } catch (CaseActionException ex) { + Exceptions.printStackTrace(ex); + } + assertTrue(CASE_DIR.exists()); + } + + @Override + public void tearDown() { + try { + Case.closeCurrentCase(); + FileUtils.deleteDirectory(CASE_DIR); + + } catch (CaseActionException | IOException ex) { + Exceptions.printStackTrace(ex); + } + assertFalse(CASE_DIR.exists()); + } + + public void testFilter() { + System.out.println("testFilter"); + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java new file mode 100755 index 0000000000..cfa9f3dc59 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java @@ -0,0 +1,109 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.testutils; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.datamodel.Content; + +/** + * A data source processor "callback" for unit testing that collects the results + * of running a data source processor on a data source and unblocks the job + * processing thread when the data source processor finishes running in its own + * thread. + */ +@Immutable +public class FunctionalTestDspCallback extends DataSourceProcessorCallback { + + private final Object monitor; + private final List errorMessages = new ArrayList<>(); + private final List dataSourceContent = new ArrayList<>(); + + /** + * Constructs a data source processor "callback" for unit testing that + * collects the results of running a data source processor on a data source + * and unblocks the job processing thread when the data source processor + * finishes running in its own thread. + * + * @param monitor A monitor for the callback to signal when the data source + * processor completes its processing. + */ + FunctionalTestDspCallback(Object monitor) { + this.monitor = monitor; + } + + /** + * Called by the data source processor when it finishes running in its own + * thread. + * + * @param result The result code for the processing of the data + * source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + this.errorMessages.addAll(errorMessages); + this.dataSourceContent.addAll(dataSourceContent); + synchronized (monitor) { + monitor.notify(); + } + } + + /** + * Called by the data source processor when it finishes running in its own + * thread, if that thread is the AWT (Abstract Window Toolkit) event + * dispatch thread (EDT). + * + * @param result The result code for the processing of the data + * source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + done(result, errorMessages, dataSourceContent); + } + + /** + * Gets any error messages emitted by the data source processor. + * + * @return A list of error messages, possibly empty. + */ + public List getDspErrorMessages() { + return new ArrayList<>(this.errorMessages); + } + + /** + * Gets any data source content objects produced by the data source + * processor. + * + * @return A list of content objects, possibly empty. + */ + public List getDataSourceContent() { + return new ArrayList<>(this.dataSourceContent); + } + +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java new file mode 100755 index 0000000000..03d26eb9b2 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.testutils; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; + +/** + * A data source processor progress monitor for unit testing. + */ +@Immutable +public class FunctionalTestDspProgressMonitor implements DataSourceProcessorProgressMonitor { + + /** + * Switches the progress indicator to indeterminate mode (the total number + * of work units to be completed is unknown) or determinate mode (the total + * number of work units to be completed is unknown). + * + * @param indeterminate True for indeterminate mode, false for determinate + * mode. + */ + @Override + public void setIndeterminate(final boolean indeterminate) { + } + + /** + * Updates the progress indicator with the number of work units completed so + * far when in determinate mode (the total number of work units to be + * completed is known). + * + * @param workUnitsCompleted Number of work units completed so far. + */ + @Override + public void setProgress(final int workUnitsCompleted) { + } + + /** + * Updates the progress indicator with a progress message. + * + * @param message The progress message. + */ + @Override + public void setProgressText(final String message) { + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java similarity index 54% rename from Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java rename to Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index 795b636b35..29618e30ec 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -15,15 +15,37 @@ * 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; + */package org.sleuthkit.autopsy.ingest; -import javax.swing.JDialog; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; -/** - * Interface for startup window implementations - */ -public interface AutoIngestCasePanelInterface { +public class IngestFileFiltersTest { - public void addWindowStateListener(JDialog parent); + public IngestFileFiltersTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void testFilters() { + System.out.println("Test filter"); + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 3bc76e61fd..b2204f1b2c 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; import org.sleuthkit.datamodel.Content; /* diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java deleted file mode 100755 index ff47423030..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.experimental.autoingest; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * A representation of a case created by automated ingest. - */ -class AutoIngestCase implements Comparable { - - private static final Logger logger = Logger.getLogger(AutoIngestCase.class.getName()); - private final Path caseDirectoryPath; - private final String caseName; - private final Path metadataFilePath; - private final Date createDate; - private final Date lastAccessedDate; - - /** - * Constructs a representation of case created by automated ingest. - * - * @param caseDirectoryPath The case directory path. - */ - AutoIngestCase(Path caseDirectoryPath) { - this.caseDirectoryPath = caseDirectoryPath; - caseName = PathUtils.caseNameFromCaseDirectoryPath(caseDirectoryPath); - metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); - BasicFileAttributes fileAttrs = null; - try { - fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); - } - if (null != fileAttrs) { - createDate = new Date(fileAttrs.creationTime().toMillis()); - lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); - } else { - createDate = new Date(); - lastAccessedDate = new Date(); - } - } - - /** - * Gets the case directory path. - * - * @return The case directory path. - */ - Path getCaseDirectoryPath() { - return this.caseDirectoryPath; - } - - /** - * Gets the case name. - * - * @return The case name. - */ - String getCaseName() { - return this.caseName; - } - - /** - * Gets the creation date for the case, defined as the create time of the - * case metadata file. - * - * @return The case creation date. - */ - Date getCreationDate() { - return this.createDate; - } - - /** - * Gets the last accessed date for the case, defined as the last accessed - * time of the case metadata file. - * - * @return The last accessed date. - */ - Date getLastAccessedDate() { - return this.lastAccessedDate; - } - - /** - * Gets the status of this case based on the auto ingest result file in the - * case directory. - * - * @return See CaseStatus enum definition. - */ - CaseStatus getStatus() { - if (AutoIngestAlertFile.exists(caseDirectoryPath)) { - return CaseStatus.ALERT; - } else { - return CaseStatus.OK; - } - } - - /** - * Indicates whether or not some other object is "equal to" this - * AutoIngestCase object. - * - * @param other The other object. - * - * @return True or false. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof AutoIngestCase)) { - return false; - } - if (other == this) { - return true; - } - return this.caseDirectoryPath.toString().equals(((AutoIngestCase) other).caseDirectoryPath.toString()); - } - - /** - * Returns a hash code value for this AutoIngestCase object. - * - * @return The has code. - */ - @Override - public int hashCode() { - int hash = 7; - hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); - hash = 71 * hash + Objects.hashCode(this.createDate); - hash = 71 * hash + Objects.hashCode(this.caseName); - return hash; - } - - /** - * Compares this AutopIngestCase object with abnother AutoIngestCase object - * for order. - */ - @Override - public int compareTo(AutoIngestCase other) { - return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); - } - - /** - * Comparator for a descending order sort on date created. - */ - static class LastAccessedDateDescendingComparator implements Comparator { - - /** - * Compares two AutoIngestCase objects for order based on last accessed - * date (descending). - * - * @param object The first AutoIngestCase object - * @param otherObject The second AuotIngestCase object. - * - * @return A negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - @Override - public int compare(AutoIngestCase object, AutoIngestCase otherObject) { - return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); - } - } - - enum CaseStatus { - - OK, - ALERT - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java deleted file mode 100755 index 8469ff2315..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.experimental.autoingest; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CaseActionException; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; - -/** - * Handles locating and opening cases created by auto ingest. - */ -final class AutoIngestCaseManager { - - private static AutoIngestCaseManager instance; - - private CoordinationService coordinationService; - - /** - * Gets the auto ingest case manager. - * - * @return The auto ingest case manager singleton. - * - * @throws AutoIngestCaseManagerException - */ - synchronized static AutoIngestCaseManager getInstance() throws AutoIngestCaseManager.AutoIngestCaseManagerException { - if (null == instance) { - instance = new AutoIngestCaseManager(); - } - return instance; - } - - /** - * Constructs an object that handles locating and opening cases created by - * auto ingest. - * - * @throws AutoIngestCaseManagerException - */ - private AutoIngestCaseManager() throws AutoIngestCaseManagerException { - try { - coordinationService = CoordinationService.getInstance(); - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get the coordination service.", ex); - } - } - - /** - * Gets a list of the cases in the top level case folder used by auto - * ingest. - * - * @return List of cases. - * - * @throws AutoIngestCaseManagerException - */ - List getCases() throws AutoIngestCaseManagerException { - List cases = new ArrayList<>(); - List casePathList = getCasePaths(); - for (Path casePath : casePathList) { - cases.add(new AutoIngestCase(casePath)); - } - return cases; - } - - /** - * Retrieve all of the case nodes and filter for only those that represent - * case paths. - * - * @return List of case paths. - * - * @throws AutoIngestCaseManagerException - */ - private List getCasePaths() throws AutoIngestCaseManagerException { - try { - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - List casePathList = new ArrayList(0); - for (String node : nodeList) { - if(node.indexOf('\\') >= 0 || node.indexOf('/') >= 0) { - /* - * This is not a case name lock (name specifies a path). - */ - String nodeUpperCase = node.toUpperCase(); - if(!nodeUpperCase.endsWith("_RESOURCES") && !nodeUpperCase.endsWith("AUTO_INGEST_LOG.TXT")) { - /* - * This is not a case resource lock, nor a case auto - * ingest log lock. Collect the path. - */ - casePathList.add(Paths.get(node)); - } - } - } - return casePathList; - - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get node list from coordination service.", ex); - } - } - - /** - * Opens an auto ingest case case. - * - * @param caseMetadataFilePath Path to the case metadata file. - * - * @throws CaseActionException - */ - synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { - /* - * Open the case. - */ - Case.openAsCurrentCase(caseMetadataFilePath.toString()); - } - - /** - * Exception type thrown when there is an error completing an auto ingest - * case manager operation. - */ - static final class AutoIngestCaseManagerException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - */ - private AutoIngestCaseManagerException(String message) { - super(message); - } - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. - */ - private AutoIngestCaseManagerException(String message, Throwable cause) { - super(message, cause); - } - - } -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java deleted file mode 100755 index e86a7bcf8a..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit 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.experimental.autoingest; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.logging.Level; -import org.openide.util.HelpCtx; -import org.openide.util.Lookup; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.SystemAction; -import org.sleuthkit.autopsy.casemodule.CaseCloseAction; -import org.sleuthkit.autopsy.casemodule.CaseOpenAction; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; -import org.sleuthkit.autopsy.core.UserPreferences; - -final class AutoIngestCaseOpenAction extends CallableSystemAction implements ActionListener { - - private static final Logger logger = Logger.getLogger(AutoIngestCaseOpenAction.class.getName()); - private static final long serialVersionUID = 1L; - - public AutoIngestCaseOpenAction() { - } - - @Override - public void actionPerformed(ActionEvent e) { - - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - switch (mode) { - case REVIEW: - - if (Case.isCaseOpen()) { - /* - * In review mode, close the currently open case, if any, and - * then display the review mode cases panel. This can be - * accomplished by invoking CaseCloseAction because it calls - * StartupWindowProvider.getInstance().open() after it closes - * the current case. - */ - SystemAction.get(CaseCloseAction.class).actionPerformed(e); - } else { - // no case is open, so show the startup window - StartupWindowProvider.getInstance().open(); - } - break; - - case AUTOINGEST: - /* - * New case action is disabled in auto ingest mode. - */ - break; - - case STANDALONE: - /** - * In standalone mode, invoke default Autopsy version of CaseOpenAction. - */ - Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(e); - break; - - - default: - logger.log(Level.SEVERE, "Attempting to open case in unsupported mode {0}", mode.toString()); - } - } - - @Override - public void performAction() { - } - - @Override - public String getName() { - return NbBundle.getMessage(AutoIngestCaseOpenAction.class, "CTL_OpenAction"); - } - - @Override - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 891975223a..fa4476d6f5 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -60,10 +60,13 @@ import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.CaseDeletionResult; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.JobsSnapshot; +import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; /** * A panel for monitoring automated ingest by a cluster, and for controlling @@ -596,7 +599,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * renderer that will choose an icon to represent the job status. */ column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); - column.setCellRenderer(new CaseStatusIconCellRenderer()); + column.setCellRenderer(new StatusIconCellRenderer()); column.setMinWidth(STATUS_COL_MIN_WIDTH); column.setMaxWidth(STATUS_COL_MAX_WIDTH); column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); @@ -1152,7 +1155,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { job.getProcessingStageStartDate(), // STARTED_TIME job.getCompletedDate(), // COMPLETED_TIME status.getDescription(), // ACTIVITY - job.getErrorsOccurred(), // STATUS + job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getProcessingHostName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 4a943b4924..9a599877f8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -29,8 +29,19 @@ + + - + + + + + + + + + + @@ -39,18 +50,9 @@ - - - - - - - - - @@ -81,6 +83,7 @@ + @@ -255,5 +258,15 @@ + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 2d10dff258..feafba3f4f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -44,6 +44,9 @@ import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; +import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A dashboard for monitoring an automated ingest cluster. @@ -400,7 +403,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * renderer that will choose an icon to represent the job status. */ column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); - column.setCellRenderer(new CaseStatusIconCellRenderer()); + column.setCellRenderer(new StatusIconCellRenderer()); column.setMinWidth(STATUS_COL_MIN_WIDTH); column.setMaxWidth(STATUS_COL_MAX_WIDTH); column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); @@ -472,7 +475,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { job.getProcessingStageStartDate(), // STARTED_TIME job.getCompletedDate(), // COMPLETED_TIME status.getDescription(), // STAGE - job.getErrorsOccurred(), // STATUS + job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // STAGE_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getManifest().getFilePath(), // MANIFEST_FILE_PATH @@ -662,6 +665,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { tbServicesStatusMessage = new javax.swing.JTextField(); prioritizeJobButton = new javax.swing.JButton(); prioritizeCaseButton = new javax.swing.JButton(); + clusterMetricsButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N @@ -762,6 +766,13 @@ public final class AutoIngestDashboard extends JPanel implements Observer { } }); + org.openide.awt.Mnemonics.setLocalizedText(clusterMetricsButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.clusterMetricsButton.text")); // NOI18N + clusterMetricsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + clusterMetricsButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -770,24 +781,26 @@ public final class AutoIngestDashboard extends JPanel implements Observer { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(pendingScrollPane) + .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbPending) - .addComponent(lbCompleted) - .addComponent(lbRunning) - .addGroup(layout.createSequentialGroup() - .addComponent(lbServicesStatus) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(prioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING)) + .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(clusterMetricsButton)) + .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(lbServicesStatus) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( @@ -813,7 +826,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(refreshButton) .addComponent(prioritizeJobButton) - .addComponent(prioritizeCaseButton)) + .addComponent(prioritizeCaseButton) + .addComponent(clusterMetricsButton)) .addContainerGap()) ); }// //GEN-END:initComponents @@ -872,7 +886,12 @@ public final class AutoIngestDashboard extends JPanel implements Observer { } }//GEN-LAST:event_prioritizeCaseButtonActionPerformed + private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed + new AutoIngestMetricsDialog(this.getTopLevelAncestor(), autoIngestMonitor); + }//GEN-LAST:event_clusterMetricsButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton clusterMetricsButton; private javax.swing.JScrollPane completedScrollPane; private javax.swing.JTable completedTable; private javax.swing.JButton jButton1; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 7e1b1907af..45563a4f4b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -25,7 +25,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") @@ -39,8 +38,7 @@ public final class AutoIngestDashboardOpenAction extends CallableSystemAction { @Override public boolean isEnabled() { - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - return (mode == REVIEW); + return (UserPreferences.getIsMultiUserModeEnabled()); } @Override diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2f2f22fb0d..b621cb514f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -62,6 +62,7 @@ import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -117,7 +118,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang private static final int NUM_INPUT_SCAN_SCHEDULING_THREADS = 1; private static final String INPUT_SCAN_SCHEDULER_THREAD_NAME = "AIM-input-scan-scheduler-%d"; private static final String INPUT_SCAN_THREAD_NAME = "AIM-input-scan-%d"; - private static int DEFAULT_JOB_PRIORITY = 0; private static final String AUTO_INGEST_THREAD_NAME = "AIM-job-processing-%d"; private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String EVENT_CHANNEL_NAME = "Auto-Ingest-Manager-Events"; @@ -2115,7 +2115,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang Case.openAsCurrentCase(metadataFilePath.toString()); } else { caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); + CaseDetails caseDetails = new CaseDetails(caseName); + Case.createAsCurrentCase(CaseType.MULTI_USER_CASE, caseDirectoryPath.toString(), caseDetails); /* * Sleep a bit before releasing the lock to ensure * that the new case folder is visible on the @@ -2932,4 +2933,4 @@ public final class AutoIngestManager extends Observable implements PropertyChang } -} +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form new file mode 100755 index 0000000000..49e700ca21 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form @@ -0,0 +1,113 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java new file mode 100755 index 0000000000..66c6d28581 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -0,0 +1,178 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.experimental.autoingest; + +import com.github.lgooddatepicker.datepicker.DatePicker; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Window; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; + +/** + * Display basic metrics for a cluster. + */ +final class AutoIngestMetricsDialog extends javax.swing.JDialog { + + private final AutoIngestMonitor autoIngestMonitor; + + /** + * Creates new form AutoIngestMetricsDialog + * + * @param parent The parent container. + * @param autoIngestMonitor The auto ingest monitor. + */ + @Messages({ + "AutoIngestMetricsDialog.title.text=Auto Ingest Cluster Metrics", + "AutoIngestMetricsDialog.initReportText=Select a date below and click the 'Get Metrics Since...' button to generate\na metrics report." + }) + AutoIngestMetricsDialog(Container parent, AutoIngestMonitor autoIngestMonitor) { + super((Window) parent, NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.title.text"), ModalityType.MODELESS); + initComponents(); + reportTextArea.setText(NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.initReportText")); + this.autoIngestMonitor = autoIngestMonitor; + setModal(true); + setSize(getPreferredSize()); + setLocationRelativeTo(parent); + setVisible(true); + } + + /** + * Update the metrics shown in the report text area. + */ + private void updateMetrics() { + if(datePicker.getDate() == null) { + return; + } + + AutoIngestMonitor.MetricsSnapshot metricsSnapshot = autoIngestMonitor.getMetricsSnapshot(); + Object[] completedJobDates = metricsSnapshot.getCompletedJobDates().toArray(); + int count = 0; + long pickedDate = datePicker.getDate().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000; + for(int i = completedJobDates.length - 1; i >= 0; i--) { + if((Long)completedJobDates[i] >= pickedDate) { + count++; + } + } + + SimpleDateFormat dateFormatter = new SimpleDateFormat("MMM d, yyyy"); + reportTextArea.setText(String.format( + "Since %s:\n" + + "\tNumber of Jobs Completed: %d\n", + dateFormatter.format(Date.valueOf(datePicker.getDate())), + count + )); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + closeButton = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + reportTextArea = new javax.swing.JTextArea(); + metricsButton = new javax.swing.JButton(); + datePicker = new DatePicker(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + setResizable(false); + + org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.closeButton.text")); // NOI18N + closeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + reportTextArea.setEditable(false); + reportTextArea.setColumns(20); + reportTextArea.setRows(5); + reportTextArea.setText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.reportTextArea.text")); // NOI18N + jScrollPane1.setViewportView(reportTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(metricsButton, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.metricsButton.text")); // NOI18N + metricsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + metricsButtonActionPerformed(evt); + } + }); + + datePicker.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.datePicker.toolTipText")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addComponent(metricsButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 33, Short.MAX_VALUE) + .addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(metricsButton)) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed + setVisible(false); + dispose(); + }//GEN-LAST:event_closeButtonActionPerformed + + private void metricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_metricsButtonActionPerformed + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + updateMetrics(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + }//GEN-LAST:event_metricsButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private com.github.lgooddatepicker.datepicker.DatePicker datePicker; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton metricsButton; + private javax.swing.JTextArea reportTextArea; + // End of variables declaration//GEN-END:variables +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 9a262bb6d3..37c635b9f0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -23,10 +23,12 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Observable; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -43,7 +45,7 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingSta * An auto ingest monitor responsible for monitoring and reporting the * processing of auto ingest jobs. */ -public final class AutoIngestMonitor extends Observable implements PropertyChangeListener { +final class AutoIngestMonitor extends Observable implements PropertyChangeListener { private static final Logger LOGGER = Logger.getLogger(AutoIngestMonitor.class.getName()); private static final int NUM_COORD_SVC_QUERY_THREADS = 1; @@ -265,17 +267,86 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang } } catch (InterruptedException ex) { LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); - } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJob.AutoIngestJobException ex) { + } catch (AutoIngestJobNodeData.InvalidDataException ex) { LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); } } + return newJobsSnapshot; + } catch (CoordinationServiceException ex) { LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); return new JobsSnapshot(); } } + /** + * Gets a new metrics snapshot from the coordination service for an auto + * ingest cluster. + * + * @return The metrics snapshot. + */ + private MetricsSnapshot queryCoordinationServiceForMetrics() { + try { + MetricsSnapshot newMetricsSnapshot = new MetricsSnapshot(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS); + for (String node : nodeList) { + try { + AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node)); + if (nodeData.getVersion() < 1) { + /* + * Ignore version '0' nodes that have not been + * "upgraded" since they don't carry enough data. + */ + continue; + } + AutoIngestJob job = new AutoIngestJob(nodeData); + ProcessingStatus processingStatus = nodeData.getProcessingStatus(); + switch (processingStatus) { + case PENDING: + case PROCESSING: + case DELETED: + /* + * These are not jobs we care about for metrics, so + * we will ignore them. + */ + break; + case COMPLETED: + newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate()); + break; + default: + LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus"); + break; + } + } catch (InterruptedException ex) { + LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); + } catch (AutoIngestJobNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); + } + } + + return newMetricsSnapshot; + + } catch (CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); + return new MetricsSnapshot(); + } + } + + /** + * Gets a new metrics snapshot. The jobs snapshot will also be updated in + * effect. + * + * @return The metrics snapshot. + */ + public MetricsSnapshot getMetricsSnapshot() { + return queryCoordinationServiceForMetrics(); + } + /** * Bumps the priority of all pending ingest jobs for a specified case. * @@ -522,6 +593,32 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang } + /** + * A snapshot of metrics for an auto ingest cluster. + */ + public static final class MetricsSnapshot { + + private final List completedJobDates = new ArrayList<>(); + + /** + * Gets a list of completed job dates, formatted in milliseconds. + * + * @return The completed job dates, formatted in milliseconds. + */ + List getCompletedJobDates() { + return new ArrayList<>(completedJobDates); + } + + /** + * Adds a new date to the list of completed job dates. + * + * @param date The date to be added. + */ + void addCompletedJobDate(Date date) { + completedJobDates.add(date.getTime()); + } + } + /** * Exception type thrown when there is an error completing an auto ingest * monitor operation. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index edac418672..5f335b1ba4 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -1,4 +1,3 @@ -CTL_OpenAction=Open Case... AutoIngestDashboard.lbCompleted.text=Completed Jobs AutoIngestDashboard.lbRunning.text=Running Jobs AutoIngestDashboard.lbPending.text=Pending Jobs @@ -47,14 +46,10 @@ OpenIDE-Module-Long-Description=\ We make no guarantee that the API of this module will not change, so developers should be careful when relying on it. OpenIDE-Module-Name=Experimental OpenIDE-Module-Short-Description=This module contains features that are being developed by Basis Technology and are not part of the default Autopsy distribution. -ReviewModeCasePanel.cannotOpenCase=Cannot Open Case -ReviewModeCasePanel.casePathNotFound=Case path not found -ReviewModeCasePanel.caseIsLocked=Single-user case is locked. DisplayLogDialog.cannotOpenLog=Unable to open the selected case log file DisplayLogDialog.cannotFindLog=Unable to find the selected case log file DisplayLogDialog.unableToShowLogFile=Unable to show log file DisplayLogDialog.okay=Okay -ReviewModeCasePanel.bnShowLog.text=&Show Log CopyFilesPanel.lbFrom.text=From Source CopyFilesPanel.lbTo.text=Destination Case CopyFilesPanel.bnCopy.text=&Copy @@ -128,8 +123,6 @@ CopyFilesPanel.cbThrottleNetwork.toolTipText=Select this box if a low-band CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.lbCaseName.text=Case Name -CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully -CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log OptionsCategory_Name_Case_Import=Case Import OptionsCategory_Keywords_Case_Import=Case Import Settings CaseImportPanel.validationErrMsg.MUdisabled=Multi user settings must be enabled and saved @@ -165,11 +158,6 @@ SingleUserCaseImporter.FailedToComplete=Failed to complete processing of SingleUserCaseImporter.CompletedBatch=Completed batch processing of SingleUserCaseImporter.AbortingBatch=Aborting batch processing of SingleUserCaseImporter.SourceImageMissing=. Source image missing for -ReviewModeCasePanel.CaseHeaderText=Case -ReviewModeCasePanel.CreatedTimeHeaderText=Created Time -ReviewModeCasePanel.StatusIconHeaderText=Status -ReviewModeCasePanel.OutputFolderHeaderText=Output Folder -ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time CopyFilesPanel.bnOptions.text=&Options AutoIngestDashboard.lbServicesStatus.text=Services Status: AutoIngestDashboard.tbServicesStatusMessage.text=Connecting... @@ -231,15 +219,6 @@ FileExporterSettingsPanel.BrowseReportTooltip_1=Browse for the Reports Folder FileExporterSettingsPanel.NewRuleTooltip_1=Clear the rule editor to begin a new rule FileExporterSettingsPanel.DeleteTooltip_1=Delete the selected rule FileExporterSettingsPanel.SaveTooltip_1=Save the current rule -AutoIngestCasePanel.rbDays.text=Days -AutoIngestCasePanel.rbWeeks.text=Weeks -AutoIngestCasePanel.rbMonths.text=Months -AutoIngestCasePanel.rbAllCases.text=Everything -AutoIngestCasePanel.bnRefresh.text=&Refresh -AutoIngestCasePanel.bnOpen.text=&Open -AutoIngestCasePanel.bnShowLog.toolTipText=Display case log file for selected case -AutoIngestCasePanel.bnShowLog.text=&Show Log -AutoIngestCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables AutoIngestDashboard.refreshButton.text=&Refresh AutoIngestDashboard.jButton1.text=jButton1 @@ -247,6 +226,11 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case +AutoIngestMetricsDialog.reportTextArea.text= +AutoIngestDashboard.clusterMetricsButton.text=Cluster Metrics +AutoIngestMetricsDialog.metricsButton.text=Get Metrics Since... +AutoIngestMetricsDialog.closeButton.text=Close +AutoIngestMetricsDialog.datePicker.toolTipText=Choose a date ArchiveFilePanel.pathLabel.text=Browse for an archive file: ArchiveFilePanel.browseButton.text=Browse ArchiveFilePanel.pathTextField.text= diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java index a7cd13af72..2e4866b010 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java @@ -672,7 +672,6 @@ public class CaseImportPanel extends javax.swing.JPanel implements ImportDoneCal */ private void enableStartButton() { if (UserPreferences.getIsMultiUserModeEnabled() - && AutoIngestUserPreferences.getJoinAutoModeCluster() && (! RuntimeProperties.runningWithGUI()) && !tbCaseSource.getText().isEmpty() && !tbCaseDestination.getText().isEmpty() diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java deleted file mode 100755 index 0010cc90ee..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit 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.experimental.autoingest; - -import java.awt.Component; -import javax.swing.ImageIcon; -import javax.swing.JTable; -import static javax.swing.SwingConstants.CENTER; -import org.openide.util.ImageUtilities; - -/** - * A JTable cell renderer that represents an auto ingest alert file exists flag - * as a center-aligned icon, and grays out the cell if the table is disabled. - */ -class CaseStatusIconCellRenderer extends GrayableCellRenderer { - - private static final long serialVersionUID = 1L; - static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false)); - static final ImageIcon warningIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/warning16.png", false)); - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - setHorizontalAlignment(CENTER); - if ((value instanceof Boolean)) { - if (true == (Boolean) value) { - setIcon(warningIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "CaseStatusIconCellRenderer.tooltiptext.warning")); - } else { - setIcon(checkedIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "CaseStatusIconCellRenderer.tooltiptext.ok")); - } - } - grayCellIfTableNotEnabled(table, isSelected); - - return this; - } -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java index 18ce9709d5..a7d5675883 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; final class PathUtils { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java index e04399d321..3a5c45632f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java @@ -47,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter; import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter.ImportCaseData; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.NetworkUtils; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; public class SingleUserCaseImporter implements Runnable { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml index 56ad444eb0..ced44d8569 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml @@ -2,20 +2,6 @@ - - - - - - - - - - - - @@ -23,19 +9,12 @@ - - - - - - - - + - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form index 20c8c7a981..68002e8055 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form @@ -1,10 +1,6 @@
- - - - @@ -56,18 +52,71 @@ - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -79,542 +128,65 @@ - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -649,6 +221,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 4877ce9d60..0d449fdb02 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -56,7 +56,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { enum OptionsUiMode { - STANDALONE, AIM, REVIEW, DOWNLOADING_CONFIGURATION + STANDALONE, AIM, DOWNLOADING_CONFIGURATION }; /** @@ -127,21 +127,10 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { if (inStartup) { UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); inputPathTextField.requestFocusInWindow(); - if (null != storedMode) { - switch (storedMode) { - case REVIEW: - jRadioButtonReview.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - break; - case AUTOINGEST: - jRadioButtonAutomated.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.AIM); - break; - default: - cbJoinAutoIngestCluster.setSelected(false); - enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); - break; - } + if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { + enableOptionsBasedOnMode(OptionsUiMode.AIM); + } else if (storedMode != null) { + enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); } } @@ -207,22 +196,12 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { * Save mode to persistent storage. */ void store() { - boolean needsRestart = false; - UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); - + boolean needsRestart = (cbJoinAutoIngestCluster.isSelected() != AutoIngestUserPreferences.getJoinAutoModeCluster()); + AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected()); if (!cbJoinAutoIngestCluster.isSelected()) { - if(storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); - } - else if (jRadioButtonAutomated.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.REVIEW) { - needsRestart = true; - } - + } else { UserPreferences.setMode(UserPreferences.SelectedMode.AUTOINGEST); String imageFolderPath = getNormalizedFolderPath(inputPathTextField.getText().trim()); AutoIngestUserPreferences.setAutoModeImageFolder(imageFolderPath); @@ -234,15 +213,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { AutoIngestUserPreferences.setSharedConfigFolder(globalSettingsPath); AutoIngestUserPreferences.setSharedConfigMaster(masterNodeCheckBox.isSelected()); } - } else if (jRadioButtonReview.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - - UserPreferences.setMode(UserPreferences.SelectedMode.REVIEW); - String resultsFolderPath = getNormalizedFolderPath(outputPathTextField.getText().trim()); - AutoIngestUserPreferences.setAutoModeResultsFolder(resultsFolderPath); } + if (needsRestart) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, @@ -306,23 +278,14 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { configButtonErrorTextField.setText("Shared configuration folder is invalid"); } break; - case REVIEW: - jLabelInvalidImageFolder.setVisible(false); - if (!validateResultsPath()) { - isValidNodePanel = false; - } - break; - case STANDALONE: break; default: break; } - if (jRadioButtonAutomated.isSelected()) { - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { - isValidNodePanel = false; - } + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { + isValidNodePanel = false; } return isValidNodePanel; } @@ -579,24 +542,17 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void enableOptionsBasedOnMode(OptionsUiMode mode) { if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected(); - jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); + jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + outputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); - - jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM); masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected()); bnFileExport.setEnabled(mode == OptionsUiMode.AIM); @@ -613,14 +569,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private OptionsUiMode getModeFromRadioButtons() { if (!cbJoinAutoIngestCluster.isSelected()) { return OptionsUiMode.STANDALONE; - } - - if (jRadioButtonAutomated.isSelected()) { - return OptionsUiMode.AIM; - } else if (jRadioButtonReview.isSelected()) { - return OptionsUiMode.REVIEW; } else { - return OptionsUiMode.STANDALONE; + return OptionsUiMode.AIM; } } @@ -633,292 +583,51 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - modeRadioButtons = new javax.swing.ButtonGroup(); nodeScrollPane = new javax.swing.JScrollPane(); nodePanel = new javax.swing.JPanel(); - jPanelNodeType = new javax.swing.JPanel(); - jLabelSelectMode = new javax.swing.JLabel(); - jRadioButtonAutomated = new javax.swing.JRadioButton(); - jRadioButtonReview = new javax.swing.JRadioButton(); - jLabelSelectInputFolder = new javax.swing.JLabel(); - inputPathTextField = new javax.swing.JTextField(); - browseInputFolderButton = new javax.swing.JButton(); - jLabelSelectOutputFolder = new javax.swing.JLabel(); - outputPathTextField = new javax.swing.JTextField(); - browseOutputFolderButton = new javax.swing.JButton(); - jLabelInvalidImageFolder = new javax.swing.JLabel(); - jLabelInvalidResultsFolder = new javax.swing.JLabel(); - jLabel1 = new javax.swing.JLabel(); - jPanelSharedConfig = new javax.swing.JPanel(); - sharedConfigCheckbox = new javax.swing.JCheckBox(); - sharedSettingsTextField = new javax.swing.JTextField(); - browseSharedSettingsButton = new javax.swing.JButton(); - sharedSettingsErrorTextField = new javax.swing.JTextField(); - masterNodeCheckBox = new javax.swing.JCheckBox(); - uploadButton = new javax.swing.JButton(); - downloadButton = new javax.swing.JButton(); - jLabelCurrentTask = new javax.swing.JLabel(); - pbTaskInProgress = new javax.swing.JProgressBar(); - jLabelTaskDescription = new javax.swing.JLabel(); - configButtonErrorTextField = new javax.swing.JTextField(); - jSeparator1 = new javax.swing.JSeparator(); - jPanelIngestSettings = new javax.swing.JPanel(); + cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); + tbOops = new javax.swing.JTextField(); bnEditIngestSettings = new javax.swing.JButton(); bnAdvancedSettings = new javax.swing.JButton(); bnFileExport = new javax.swing.JButton(); bnLogging = new javax.swing.JButton(); - cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); - tbOops = new javax.swing.JTextField(); + browseOutputFolderButton = new javax.swing.JButton(); + browseInputFolderButton = new javax.swing.JButton(); + inputPathTextField = new javax.swing.JTextField(); + outputPathTextField = new javax.swing.JTextField(); + jLabelInvalidResultsFolder = new javax.swing.JLabel(); + jLabelInvalidImageFolder = new javax.swing.JLabel(); + jLabelSelectInputFolder = new javax.swing.JLabel(); + jLabelSelectOutputFolder = new javax.swing.JLabel(); + sharedConfigCheckbox = new javax.swing.JCheckBox(); + sharedSettingsErrorTextField = new javax.swing.JTextField(); + sharedSettingsTextField = new javax.swing.JTextField(); + browseSharedSettingsButton = new javax.swing.JButton(); + downloadButton = new javax.swing.JButton(); + configButtonErrorTextField = new javax.swing.JTextField(); + pbTaskInProgress = new javax.swing.JProgressBar(); + jLabelTaskDescription = new javax.swing.JLabel(); + jLabelCurrentTask = new javax.swing.JLabel(); + uploadButton = new javax.swing.JButton(); + masterNodeCheckBox = new javax.swing.JCheckBox(); nodeScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); nodePanel.setMinimumSize(new java.awt.Dimension(100, 100)); - jPanelNodeType.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelNodeType.border.title"))); // NOI18N - jPanelNodeType.setMinimumSize(new java.awt.Dimension(50, 50)); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectMode, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectMode.text")); // NOI18N - - modeRadioButtons.add(jRadioButtonAutomated); - jRadioButtonAutomated.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonAutomated, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.text")); // NOI18N - jRadioButtonAutomated.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText")); // NOI18N - jRadioButtonAutomated.addActionListener(new java.awt.event.ActionListener() { + cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N + cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonAutomatedActionPerformed(evt); + cbJoinAutoIngestClusterActionPerformed(evt); } }); - modeRadioButtons.add(jRadioButtonReview); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonReview, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.text")); // NOI18N - jRadioButtonReview.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.toolTipText")); // NOI18N - jRadioButtonReview.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonReviewActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N - jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N - inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N - browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseInputFolderButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N - jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N - outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N - browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseOutputFolderButtonActionPerformed(evt); - } - }); - - jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N - - jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N - - jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/AIM.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabel1.text")); // NOI18N - - javax.swing.GroupLayout jPanelNodeTypeLayout = new javax.swing.GroupLayout(jPanelNodeType); - jPanelNodeType.setLayout(jPanelNodeTypeLayout); - jPanelNodeTypeLayout.setHorizontalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) - .addGap(10, 10, 10) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelSelectMode) - .addComponent(jRadioButtonReview) - .addComponent(jRadioButtonAutomated)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel1)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectInputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectOutputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - ); - jPanelNodeTypeLayout.setVerticalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabelSelectMode) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jRadioButtonAutomated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jRadioButtonReview)) - .addComponent(jLabel1)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectInputFolder) - .addComponent(jLabelInvalidImageFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseInputFolderButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabelInvalidResultsFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(browseOutputFolderButton) - .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 0, Short.MAX_VALUE)) - ); - - jPanelSharedConfig.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelSharedConfig.border.title"))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N - sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - sharedConfigCheckboxItemStateChanged(evt); - } - }); - - sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N - sharedSettingsTextField.setEnabled(false); - - org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N - browseSharedSettingsButton.setEnabled(false); - browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseSharedSettingsButtonActionPerformed(evt); - } - }); - - sharedSettingsErrorTextField.setEditable(false); - sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N - sharedSettingsErrorTextField.setBorder(null); - - org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N - masterNodeCheckBox.setEnabled(false); - masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - masterNodeCheckBoxItemStateChanged(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N - uploadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - uploadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N - downloadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - downloadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N - - configButtonErrorTextField.setEditable(false); - configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N - configButtonErrorTextField.setBorder(null); - - javax.swing.GroupLayout jPanelSharedConfigLayout = new javax.swing.GroupLayout(jPanelSharedConfig); - jPanelSharedConfig.setLayout(jPanelSharedConfigLayout); - jPanelSharedConfigLayout.setHorizontalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(jLabelCurrentTask) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(configButtonErrorTextField)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sharedSettingsErrorTextField)) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 692, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(masterNodeCheckBox)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelSharedConfigLayout.setVerticalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseSharedSettingsButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(downloadButton) - .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(1, 1, 1) - .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(uploadButton) - .addGap(8, 8, 8) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelCurrentTask) - .addComponent(jLabelTaskDescription)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanelIngestSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelIngestSettings.border.title"))); // NOI18N + tbOops.setEditable(false); + tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); + tbOops.setForeground(new java.awt.Color(255, 0, 0)); + tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N + tbOops.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnEditIngestSettings, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.text")); // NOI18N bnEditIngestSettings.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.toolTipText")); // NOI18N @@ -949,46 +658,94 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }); - javax.swing.GroupLayout jPanelIngestSettingsLayout = new javax.swing.GroupLayout(jPanelIngestSettings); - jPanelIngestSettings.setLayout(jPanelIngestSettingsLayout); - jPanelIngestSettingsLayout.setHorizontalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelIngestSettingsLayout.setVerticalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnEditIngestSettings) - .addComponent(bnFileExport) - .addComponent(bnAdvancedSettings) - .addComponent(bnLogging)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N - cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N + browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - cbJoinAutoIngestClusterActionPerformed(evt); + browseOutputFolderButtonActionPerformed(evt); } }); - tbOops.setEditable(false); - tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); - tbOops.setForeground(new java.awt.Color(255, 0, 0)); - tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N - tbOops.setBorder(null); + org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N + browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseInputFolderButtonActionPerformed(evt); + } + }); + + inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N + inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N + + outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N + outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N + + jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N + + jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N + jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N + jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N + sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + sharedConfigCheckboxItemStateChanged(evt); + } + }); + + sharedSettingsErrorTextField.setEditable(false); + sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N + sharedSettingsErrorTextField.setBorder(null); + + sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N + sharedSettingsTextField.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N + browseSharedSettingsButton.setEnabled(false); + browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseSharedSettingsButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N + downloadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadButtonActionPerformed(evt); + } + }); + + configButtonErrorTextField.setEditable(false); + configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N + configButtonErrorTextField.setBorder(null); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N + uploadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + uploadButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N + masterNodeCheckBox.setEnabled(false); + masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + masterNodeCheckBoxItemStateChanged(evt); + } + }); javax.swing.GroupLayout nodePanelLayout = new javax.swing.GroupLayout(nodePanel); nodePanel.setLayout(nodePanelLayout); @@ -998,14 +755,56 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(nodePanelLayout.createSequentialGroup() - .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelCurrentTask) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(10, 10, 10) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectInputFolder) .addGap(18, 18, 18) - .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(masterNodeCheckBox) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectOutputFolder) + .addGap(18, 18, 18) + .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 396, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 32, Short.MAX_VALUE))) + .addContainerGap()) ); nodePanelLayout.setVerticalGroup( nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1014,12 +813,51 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbJoinAutoIngestCluster) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectInputFolder) + .addComponent(jLabelInvalidImageFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseInputFolderButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelInvalidResultsFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(browseOutputFolderButton) + .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(25, 25, 25) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnEditIngestSettings) + .addComponent(bnFileExport) + .addComponent(bnAdvancedSettings) + .addComponent(bnLogging)) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseSharedSettingsButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(downloadButton) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(uploadButton) + .addGap(8, 8, 8) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelCurrentTask) + .addComponent(jLabelTaskDescription)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(161, Short.MAX_VALUE)) ); nodeScrollPane.setViewportView(nodePanel); @@ -1039,31 +877,35 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents - private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed - - String oldText = sharedSettingsTextField.getText().trim(); - // set the current directory of the FileChooser if the oldText is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } - - fc.setDialogTitle("Select shared configuration folder:"); - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - - int retval = fc.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - String path = fc.getSelectedFile().getPath(); - sharedSettingsTextField.setText(path); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed - boolean permissionsAppropriate(String path) { return FileUtil.hasReadWriteAccess(Paths.get(path)); } + private void setSharedConfigEnable() { + setEnabledStateForSharedConfiguration(); + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) { + sharedSettingsTextField.setEnabled(true); + browseSharedSettingsButton.setEnabled(true); + masterNodeCheckBox.setEnabled(true); + downloadButton.setEnabled(true); + validateSettings(); + controller.changed(); + } else { + sharedSettingsTextField.setEnabled(false); + browseSharedSettingsButton.setEnabled(false); + masterNodeCheckBox.setEnabled(false); + downloadButton.setEnabled(false); + sharedSettingsErrorTextField.setText(""); + validateSettings(); + controller.changed(); + } + } + + private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed + enableOptionsBasedOnMode(getModeFromRadioButtons()); + controller.changed(); + }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed // First save the shared config folder and solr settings to the properties String globalSettingsPath = getNormalizedFolderPath(sharedSettingsTextField.getText().trim()); @@ -1100,31 +942,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_uploadButtonActionPerformed - private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged - // Enable the global settings text box and browse button iff the checkbox is checked and enabled - setSharedConfigEnable(); - }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged - - private void setSharedConfigEnable() { - setEnabledStateForSharedConfiguration(); - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()) { - sharedSettingsTextField.setEnabled(true); - browseSharedSettingsButton.setEnabled(true); - masterNodeCheckBox.setEnabled(true); - downloadButton.setEnabled(true); - validateSettings(); - controller.changed(); - } else { - sharedSettingsTextField.setEnabled(false); - browseSharedSettingsButton.setEnabled(false); - masterNodeCheckBox.setEnabled(false); - downloadButton.setEnabled(false); - sharedSettingsErrorTextField.setText(""); - validateSettings(); - controller.changed(); - } - } - private void masterNodeCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_masterNodeCheckBoxItemStateChanged // Enable the global settings text box and browse button iff the checkbox is checked and enabled setEnabledStateForSharedConfiguration(); @@ -1137,10 +954,31 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_masterNodeCheckBoxItemStateChanged - private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed - enableOptionsBasedOnMode(getModeFromRadioButtons()); - controller.changed(); - }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed + + String oldText = sharedSettingsTextField.getText().trim(); + // set the current directory of the FileChooser if the oldText is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + + fc.setDialogTitle("Select shared configuration folder:"); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int retval = fc.showOpenDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + sharedSettingsTextField.setText(path); + validateSettings(); + controller.changed(); + } + }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed + + private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged + // Enable the global settings text box and browse button iff the checkbox is checked and enabled + setSharedConfigEnable(); + }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged private void browseOutputFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseOutputFolderButtonActionPerformed String oldText = outputPathTextField.getText().trim(); @@ -1182,24 +1020,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_browseInputFolderButtonActionPerformed - private void jRadioButtonReviewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonReviewActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonReviewActionPerformed - - private void jRadioButtonAutomatedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonAutomatedActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.AIM); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonAutomatedActionPerformed - private void bnLoggingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnLoggingActionPerformed JDialog jDialog = new JDialog(); NodeStatusLogPanel loggingPanel = new NodeStatusLogPanel(jDialog); @@ -1242,9 +1062,9 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void bnAdvancedSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnAdvancedSettingsActionPerformed AdvancedAutoIngestSettingsPanel advancedAutoIngestSettingsPanel = new AdvancedAutoIngestSettingsPanel(getModeFromRadioButtons()); if (JOptionPane.showConfirmDialog(null, advancedAutoIngestSettingsPanel, - NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { - advancedAutoIngestSettingsPanel.store(); + NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { + advancedAutoIngestSettingsPanel.store(); } }//GEN-LAST:event_bnAdvancedSettingsActionPerformed @@ -1349,7 +1169,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } void setEnabledStateForSharedConfiguration() { - if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) { + if (cbJoinAutoIngestCluster.isSelected()) { enableOptionsBasedOnMode(OptionsUiMode.AIM); } } @@ -1361,19 +1181,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { bnLogging.setEnabled(enabled); browseInputFolderButton.setEnabled(enabled); browseOutputFolderButton.setEnabled(enabled); - browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()); + browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && cbJoinAutoIngestCluster.isSelected()); configButtonErrorTextField.setEnabled(enabled); inputPathTextField.setEnabled(enabled); jLabelInvalidImageFolder.setEnabled(enabled); jLabelInvalidResultsFolder.setEnabled(enabled); jLabelSelectInputFolder.setEnabled(enabled); - jLabelSelectMode.setEnabled(enabled); jLabelSelectOutputFolder.setEnabled(enabled); - jPanelIngestSettings.setEnabled(enabled); - jPanelNodeType.setEnabled(enabled); - jPanelSharedConfig.setEnabled(enabled); - jRadioButtonAutomated.setEnabled(enabled); - jRadioButtonReview.setEnabled(enabled); outputPathTextField.setEnabled(enabled); } @@ -1389,22 +1203,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private javax.swing.JTextField configButtonErrorTextField; private javax.swing.JButton downloadButton; private javax.swing.JTextField inputPathTextField; - private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabelCurrentTask; private javax.swing.JLabel jLabelInvalidImageFolder; private javax.swing.JLabel jLabelInvalidResultsFolder; private javax.swing.JLabel jLabelSelectInputFolder; - private javax.swing.JLabel jLabelSelectMode; private javax.swing.JLabel jLabelSelectOutputFolder; private javax.swing.JLabel jLabelTaskDescription; - private javax.swing.JPanel jPanelIngestSettings; - private javax.swing.JPanel jPanelNodeType; - private javax.swing.JPanel jPanelSharedConfig; - private javax.swing.JRadioButton jRadioButtonAutomated; - private javax.swing.JRadioButton jRadioButtonReview; - private javax.swing.JSeparator jSeparator1; private javax.swing.JCheckBox masterNodeCheckBox; - private javax.swing.ButtonGroup modeRadioButtons; private javax.swing.JPanel nodePanel; private javax.swing.JScrollPane nodeScrollPane; private javax.swing.JTextField outputPathTextField; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties index 66ed50dd20..a12453e3c1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties @@ -23,12 +23,9 @@ AIMIngestSettingsPanel.lbSecondsBetweenJobs.toolTipText=Increase this value if d AIMIngestSettingsPanel.spSecondsBetweenJobs.toolTipText=Increase this value if database locks cause problems. It gives a little more time for finalizing. AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title=Advanced Settings AutoIngestSettingsPanel.browseGlobalSettingsButton.text=Browse -AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.CannotAccess=Cannot access AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text=Join auto ingest cluster AutoIngestSettingsPanel.CheckPermissions=Check permissions. -AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField -AutoIngestSettingsPanel.downloadButton.text=Download Config AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder AutoIngestSettingsPanel.FileExportRules.text=File Export Rules @@ -36,12 +33,8 @@ AutoIngestSettingsPanel.globalSettingsErrorTextField.text= AutoIngestSettingsPanel.globalSettingsTextField.text= AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set AutoIngestSettingsPanel.InvalidPortNumber=Invalid port number. -AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: -AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 -AutoIngestSettingsPanel.jPanelSharedConfig.border.title=Shared Configuration AutoIngestSettingsPanel.jRadioButtonCopyFiles.text=File Copy mode AutoIngestSettingsPanel.KeywordSearchNull=Cannot find Keyword Search service -AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings AutoIngestSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect AutoIngestSettingsPanel.nodePanel.TabConstraints.tabTitle=Node Configuration AutoIngestSettingsPanel.NodeStatusLogging.text=Node Status Logging Settings @@ -49,11 +42,7 @@ AutoIngestSettingsPanel.PathInvalid=Path is not valid AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required to take effect. AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required AutoIngestSettingsPanel.ResultsDirectoryUnspecified=Shared cases folder must be set -AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: -AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField -AutoIngestSettingsPanel.sharedSettingsTextField.text= AutoIngestSettingsPanel.tbOops.text= -AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config AutoIngestSettingsPanel.validationErrMsg.incomplete=Fill in all values AutoIngestSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number AutoIngestSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number @@ -119,8 +108,16 @@ AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1=A soft lim AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.toolTipText_1=The number of threads running file level ingest modules. AdvancedAutoIngestSettingsPanel.numberOfFileIngestThreadsComboBox.toolTipText=The number of threads running file level ingest modules. NodeStatusLogPanel.tbDbName.toolTipText_1=Database name -AutoIngestSettingsPanel.jPanelNodeType.border.title=Node Type Setup -AutoIngestSettingsPanel.jLabel1.text= +AutoIngestSettingsPanel.sharedSettingsTextField.text= +AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: +AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField +AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 +AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: +AutoIngestSettingsPanel.downloadButton.text=Download Config +AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config +AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings +AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField +AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text=jLabelInvalidResultsFolder AutoIngestSettingsPanel.jLabelInvalidImageFolder.text=jLabelInvalidImageFolder AutoIngestSettingsPanel.browseOutputFolderButton.text=Browse @@ -131,12 +128,6 @@ AutoIngestSettingsPanel.browseInputFolderButton.text=Browse AutoIngestSettingsPanel.inputPathTextField.toolTipText=Input folder for automated processing, i.e., the location where input case folders will be created for ingest by automated processing mode AutoIngestSettingsPanel.inputPathTextField.text= AutoIngestSettingsPanel.jLabelSelectInputFolder.text=Select shared images folder: -AutoIngestSettingsPanel.jRadioButtonReview.toolTipText=Review cases created in automated processing mode -AutoIngestSettingsPanel.jRadioButtonReview.text=Examiner node -AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText=Automatically detect new data sources and create cases. -AutoIngestSettingsPanel.jRadioButtonAutomated.text=Auto ingest node (application restart required) -AutoIngestSettingsPanel.jLabelSelectMode.text=Select mode: -AutoIngestSettingsPanel.jPanelIngestSettings.border.title=Automated Ingest Settings AutoIngestSettingsPanel.bnLogging.text=Node Status Logging AutoIngestSettingsPanel.bnFileExport.text=File Export Settings AutoIngestSettingsPanel.bnAdvancedSettings.text=Advanced Settings diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ba2de01a6c..74c28d55b8 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -236,9 +236,7 @@ public final class ImageGalleryController { undoManager.clear(); }); - regroupDisabled.addListener((Observable observable) -> { - checkForGroups(); - }); + regroupDisabled.addListener(observable -> checkForGroups()); IngestManager ingestManager = IngestManager.getInstance(); PropertyChangeListener ingestEventHandler = diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 1e914522ac..3ef949c9c9 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -128,9 +128,7 @@ public class DrawableGroup implements Comparable { LOGGER.log(Level.WARNING, "could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS } } - return hashSetHitsCount.get(); - } public ReadOnlyLongProperty hashSetHitsCountProperty() { @@ -226,7 +224,6 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override public int compareTo(DrawableGroup other) { - return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); + return getGroupByValueDislpayName().compareTo(other.getGroupByValueDislpayName()); } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ae9e17bb4a..5c02f5abd1 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -122,7 +122,7 @@ public class GroupManager { /* * --- current grouping/sorting attributes --- */ - private volatile GroupSortBy sortBy = GroupSortBy.NONE; + private volatile GroupSortBy sortBy = GroupSortBy.PRIORITY; private volatile DrawableAttribute groupBy = DrawableAttribute.PATH; private volatile SortOrder sortOrder = SortOrder.ASCENDING; @@ -156,7 +156,6 @@ public class GroupManager { */ public GroupManager(ImageGalleryController controller) { this.controller = controller; - } /** @@ -188,7 +187,7 @@ public class GroupManager { * the groups the given file is a part of * * @return a a set of {@link GroupKey}s representing the group(s) the given - * file is a part of + * file is a part of */ synchronized public Set> getGroupKeysForFileID(Long fileID) { try { @@ -208,7 +207,7 @@ public class GroupManager { * @param groupKey * * @return return the DrawableGroup (if it exists) for the given GroupKey, - * or null if no group exists for that key. + * or null if no group exists for that key. */ @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { @@ -284,7 +283,7 @@ public class GroupManager { * no-op * * @param groupKey the value of groupKey - * @param fileID the value of file + * @param fileID the value of file */ public synchronized DrawableGroup removeFromGroup(GroupKey groupKey, final Long fileID) { //get grouping this file would be in @@ -466,7 +465,7 @@ public class GroupManager { } } - public Comparator getSortBy() { + public GroupSortBy getSortBy() { return sortBy; } @@ -512,7 +511,7 @@ public class GroupManager { * @param groupBy * @param sortBy * @param sortOrder - * @param force true to force a full db query regroup + * @param force true to force a full db query regroup */ public synchronized > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { @@ -530,9 +529,7 @@ public class GroupManager { } groupByTask = new ReGroupTask<>(groupBy, sortBy, sortOrder); - Platform.runLater(() -> { - regroupProgress.bind(groupByTask.progressProperty()); - }); + Platform.runLater(() -> regroupProgress.bind(groupByTask.progressProperty())); regroupExecutor.submit(groupByTask); } else { // resort the list of groups @@ -583,10 +580,7 @@ public class GroupManager { DrawableGroup group = g; if (group != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - Platform.runLater(() -> { - group.addFile(fileID); - }); - + Platform.runLater(() -> group.addFile(fileID)); } } @@ -682,9 +676,9 @@ public class GroupManager { } else { group = new DrawableGroup(groupKey, fileIDs, groupSeen); controller.getCategoryManager().registerListener(group); - group.seenProperty().addListener((o, oldSeen, newSeen) -> { - Platform.runLater(() -> markGroupSeen(group, newSeen)); - }); + group.seenProperty().addListener((o, oldSeen, newSeen) -> + Platform.runLater(() -> markGroupSeen(group, newSeen)) + ); groupMap.put(groupKey, group); } } @@ -693,7 +687,7 @@ public class GroupManager { analyzedGroups.add(group); if (Objects.isNull(task)) { FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy)); - } + } } markGroupSeen(group, groupSeen); }); @@ -743,17 +737,17 @@ public class GroupManager { "# {0} - groupBy attribute Name", "# {1} - atribute value", "ReGroupTask.progressUpdate=regrouping files by {0} : {1}"}) - private class ReGroupTask> extends LoggedTask { + private class ReGroupTask> extends LoggedTask { private ProgressHandle groupProgress; - private final DrawableAttribute groupBy; + private final DrawableAttribute groupBy; private final GroupSortBy sortBy; private final SortOrder sortOrder; - ReGroupTask(DrawableAttribute groupBy, GroupSortBy sortBy, SortOrder sortOrder) { + ReGroupTask(DrawableAttribute groupBy, GroupSortBy sortBy, SortOrder sortOrder) { super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true); this.groupBy = groupBy; @@ -780,13 +774,13 @@ public class GroupManager { }); // Get the list of group keys - final List vals = findValuesForAttribute(groupBy); + final List vals = findValuesForAttribute(groupBy); groupProgress.start(vals.size()); int p = 0; // For each key value, partially create the group and add it to the list. - for (final A val : vals) { + for (final AttrType val : vals) { if (isCancelled()) { return null;//abort } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java index 20d47e2952..65e1870de8 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java @@ -37,24 +37,34 @@ public class GroupSortBy implements Comparator { /** * sort the groups by the number of files in each */ - public final static GroupSortBy FILE_COUNT = new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", Comparator.comparing(DrawableGroup::getSize)); + public final static GroupSortBy FILE_COUNT = + new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", + Comparator.comparing(DrawableGroup::getSize)); /** * sort the groups by the natural order of the grouping value ( eg group * them by path alphabetically ) */ - public final static GroupSortBy GROUP_BY_VALUE = new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", Comparator.comparing(DrawableGroup::getGroupByValueDislpayName)); + public final static GroupSortBy GROUP_BY_VALUE = + new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", + Comparator.comparing(DrawableGroup::getGroupByValueDislpayName)); /** * don't sort the groups just use what ever order they come in (ingest * order) */ - public final static GroupSortBy NONE = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", new AllEqualComparator<>()); + public final static GroupSortBy NONE = + new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", + new AllEqualComparator<>()); /** * sort the groups by some priority metric to be determined and implemented */ - public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)).reversed()); + public final static GroupSortBy PRIORITY = + new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", + Comparator.comparing(DrawableGroup::getHashHitDensity) + .thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)) + .reversed()); @Override public int compare(DrawableGroup o1, DrawableGroup o2) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 2dc85cbfd9..bdc43c1c06 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -180,8 +180,8 @@ public class Toolbar extends ToolBar { sortChooser = new SortChooser<>(GroupSortBy.getValues()); sortChooser.comparatorProperty().addListener((observable, oldComparator, newComparator) -> { - final boolean orderEnabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY; - sortChooser.setSortOrderDisabled(orderEnabled); + final boolean orderDisabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY; + sortChooser.setSortOrderDisabled(orderDisabled); final SortChooser.ValueType valueType = newComparator == GroupSortBy.GROUP_BY_VALUE ? SortChooser.ValueType.LEXICOGRAPHIC : SortChooser.ValueType.NUMERIC; sortChooser.setValueType(valueType); @@ -189,7 +189,7 @@ public class Toolbar extends ToolBar { }); sortChooser.sortOrderProperty().addListener(queryInvalidationListener); - sortChooser.setComparator(GroupSortBy.PRIORITY); + sortChooser.setComparator(controller.getGroupManager().getSortBy()); getItems().add(1, sortChooser); sortHelpImageView.setCursor(Cursor.HAND); diff --git a/KeywordSearch/build.xml b/KeywordSearch/build.xml index d02cb92727..5fe021fff8 100755 --- a/KeywordSearch/build.xml +++ b/KeywordSearch/build.xml @@ -6,8 +6,21 @@ Builds, tests, and runs the project org.sleuthkit.autopsy.keywordsearch. + + + + - + + + + + + + + + + @@ -39,5 +52,12 @@ - + + + + + + + + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java index 93fa053dd4..8e820b4c74 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java @@ -29,9 +29,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { private static final long serialVersionUID = 1L; - private GlobalListSettingsPanel listsPanel; - private KeywordSearchGlobalLanguageSettingsPanel languagesPanel; - private KeywordSearchGlobalSearchSettingsPanel generalPanel; + private final GlobalListSettingsPanel listsPanel = new GlobalListSettingsPanel(); + private final KeywordSearchGlobalLanguageSettingsPanel languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel(); + private final KeywordSearchGlobalSearchSettingsPanel generalPanel = new KeywordSearchGlobalSearchSettingsPanel(); KeywordSearchGlobalSettingsPanel() { initComponents(); @@ -41,9 +41,6 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP @NbBundle.Messages({"KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings"}) private void customizeComponents() { setName(Bundle.KeywordSearchGlobalSettingsPanel_Title()); - listsPanel = new GlobalListSettingsPanel(); - languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel(); - generalPanel = new KeywordSearchGlobalSearchSettingsPanel(); tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listTabTitle"), null, listsPanel, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listLabToolTip"), 0); tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.stringExtTitle"), null, diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java new file mode 100755 index 0000000000..373a2eedd1 --- /dev/null +++ b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java @@ -0,0 +1,54 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.keywordsearch; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({CreditCardValidatorTest.class}) +public class KeywordSearchTestSuite { + public KeywordSearchTestSuite() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Ignore + public static void main(String[] args) { + } +} diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index c23539d88b..f487637e9c 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Mon, 02 Oct 2017 14:46:21 -0400 +#Wed, 08 Nov 2017 10:44:01 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 4.4.2 +currentVersion=Autopsy 4.5.0 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 41fbe57fe3..4e4f5ebfe9 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Mon, 02 Oct 2017 14:46:21 -0400 -CTL_MainWindow_Title=Autopsy 4.4.2 -CTL_MainWindow_Title_No_Project=Autopsy 4.4.2 +#Wed, 08 Nov 2017 10:44:01 -0500 +CTL_MainWindow_Title=Autopsy 4.5.0 +CTL_MainWindow_Title_No_Project=Autopsy 4.5.0