mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-20 03:24:55 +00:00
Merge remote-tracking branch 'upstream/develop' into ig-deadlock-fix
This commit is contained in:
commit
0ddd529e4c
@ -45,6 +45,9 @@
|
|||||||
|
|
||||||
<dependency conf="core->default" org="commons-validator" name="commons-validator" rev="1.6"/>
|
<dependency conf="core->default" org="commons-validator" name="commons-validator" rev="1.6"/>
|
||||||
<dependency conf="core->default" org="net.htmlparser.jericho" name="jericho-html" rev="3.3"/>
|
<dependency conf="core->default" org="net.htmlparser.jericho" name="jericho-html" rev="3.3"/>
|
||||||
|
<dependency org="com.squareup.okhttp" name="okhttp" rev="2.7.5"/>
|
||||||
|
<!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
|
||||||
|
<dependency org="javax.ws.rs" name="javax.ws.rs-api" rev="2.0"/>
|
||||||
<override org="jakarta.ws.rs" module="jakarta.ws.rs-api" rev="2.1.5"/>
|
<override org="jakarta.ws.rs" module="jakarta.ws.rs-api" rev="2.1.5"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</ivy-module>
|
</ivy-module>
|
||||||
|
@ -111,6 +111,10 @@ file.reference.grpc-context-1.19.0.jar=release/modules/ext/grpc-context-1.19.0.j
|
|||||||
file.reference.opencensus-api-0.19.2.jar=release/modules/ext/opencensus-api-0.19.2.jar
|
file.reference.opencensus-api-0.19.2.jar=release/modules/ext/opencensus-api-0.19.2.jar
|
||||||
file.reference.opencensus-contrib-http-util-0.19.2.jar=release/modules/ext/opencensus-contrib-http-util-0.19.2.jar
|
file.reference.opencensus-contrib-http-util-0.19.2.jar=release/modules/ext/opencensus-contrib-http-util-0.19.2.jar
|
||||||
file.reference.threetenbp-1.3.3.jar=release/modules/ext/threetenbp-1.3.3.jar
|
file.reference.threetenbp-1.3.3.jar=release/modules/ext/threetenbp-1.3.3.jar
|
||||||
|
file.reference.okhttp-2.7.5-javadoc.jar=release/modules/ext/okhttp-2.7.5-javadoc.jar
|
||||||
|
file.reference.okhttp-2.7.5-sources.jar=release/modules/ext/okhttp-2.7.5-sources.jar
|
||||||
|
file.reference.okhttp-2.7.5.jar=release/modules/ext/okhttp-2.7.5.jar
|
||||||
|
file.reference.okio-1.6.0.jar=release/modules/ext/okio-1.6.0.jar
|
||||||
javac.source=1.8
|
javac.source=1.8
|
||||||
javac.compilerargs=-Xlint -Xlint:-serial
|
javac.compilerargs=-Xlint -Xlint:-serial
|
||||||
license.file=../LICENSE-2.0.txt
|
license.file=../LICENSE-2.0.txt
|
||||||
|
@ -773,6 +773,14 @@
|
|||||||
<runtime-relative-path>ext/google-api-services-translate-v2-rev20170525-1.27.0.jar</runtime-relative-path>
|
<runtime-relative-path>ext/google-api-services-translate-v2-rev20170525-1.27.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar</binary-origin>
|
<binary-origin>release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/okhttp-2.7.5.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/okhttp-2.7.5.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/okio-1.6.0.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/okio-1.6.0.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
</data>
|
</data>
|
||||||
</configuration>
|
</configuration>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,35 +1,25 @@
|
|||||||
AddBlackboardArtifactTagAction.pluralTagResult=Add Result Tags
|
AddBlackboardArtifactTagAction.pluralTagResult=Add Result Tags
|
||||||
AddBlackboardArtifactTagAction.singularTagResult=Add Result Tag
|
AddBlackboardArtifactTagAction.singularTagResult=Add Result Tag
|
||||||
AddBlackboardArtifactTagAction.taggingErr=Tagging Error
|
AddBlackboardArtifactTagAction.taggingErr=Tagging Error
|
||||||
# {0} - artifactName
|
|
||||||
AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.
|
AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.
|
||||||
AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag
|
AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag
|
||||||
AddContentTagAction.pluralTagFile=Add File Tags
|
AddContentTagAction.pluralTagFile=Add File Tags
|
||||||
AddContentTagAction.singularTagFile=Add File Tag
|
AddContentTagAction.singularTagFile=Add File Tag
|
||||||
# {0} - fileName
|
|
||||||
# {1} - tagName
|
|
||||||
AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag.
|
AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag.
|
||||||
AddContentTagAction.taggingErr=Tagging Error
|
AddContentTagAction.taggingErr=Tagging Error
|
||||||
# {0} - fileName
|
|
||||||
AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.
|
AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.
|
||||||
# {0} - fileName
|
|
||||||
AddContentTagAction.unableToTag.msg2=Unable to tag {0}.
|
AddContentTagAction.unableToTag.msg2=Unable to tag {0}.
|
||||||
CTL_ShowIngestProgressSnapshotAction=Ingest Status Details
|
CTL_ShowIngestProgressSnapshotAction=Ingest Status Details
|
||||||
DeleteBlackboardArtifactTagAction.deleteTag=Remove Selected Tag(s)
|
DeleteBlackboardArtifactTagAction.deleteTag=Remove Selected Tag(s)
|
||||||
DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error
|
DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error
|
||||||
# {0} - tagName
|
|
||||||
DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.
|
DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.
|
||||||
DeleteContentTagAction.deleteTag=Remove Selected Tag(s)
|
DeleteContentTagAction.deleteTag=Remove Selected Tag(s)
|
||||||
DeleteContentTagAction.tagDelErr=Tag Deletion Error
|
DeleteContentTagAction.tagDelErr=Tag Deletion Error
|
||||||
# {0} - tagName
|
|
||||||
DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.
|
DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.
|
||||||
DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag
|
DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag
|
||||||
# {0} - artifactID
|
|
||||||
DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}.
|
DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}.
|
||||||
# {0} - artifactID
|
|
||||||
DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}.
|
DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}.
|
||||||
DeleteFileContentTagAction.deleteTag=Remove File Tag
|
DeleteFileContentTagAction.deleteTag=Remove File Tag
|
||||||
# {0} - fileID
|
|
||||||
DeleteFileContentTagAction.deleteTag.alert=Unable to untag file {0}.
|
DeleteFileContentTagAction.deleteTag.alert=Unable to untag file {0}.
|
||||||
ExitAction.confirmationDialog.message=Ingest is running, are you sure you want to exit?
|
ExitAction.confirmationDialog.message=Ingest is running, are you sure you want to exit?
|
||||||
ExitAction.confirmationDialog.title=Ingest is Running
|
ExitAction.confirmationDialog.title=Ingest is Running
|
||||||
@ -83,11 +73,7 @@ CTL_OpenOutputFolder=Open Output Folder
|
|||||||
OpenOutputFolder.error1=Output Folder Not Found: {0}
|
OpenOutputFolder.error1=Output Folder Not Found: {0}
|
||||||
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
|
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
|
||||||
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
|
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
|
||||||
# {0} - old tag name
|
|
||||||
# {1} - artifactID
|
|
||||||
ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}.
|
ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}.
|
||||||
# {0} - old tag name
|
|
||||||
# {1} - content obj id
|
|
||||||
ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}.
|
ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}.
|
||||||
ReplaceTagAction.replaceTag=Replace Selected Tag(s) With
|
ReplaceTagAction.replaceTag=Replace Selected Tag(s) With
|
||||||
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
|
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules
|
AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules
|
||||||
AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode
|
AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode
|
||||||
# {0} - file
|
|
||||||
AddLogicalImageTask.addingToReport=Adding {0} to report
|
AddLogicalImageTask.addingToReport=Adding {0} to report
|
||||||
# {0} - src
|
|
||||||
# {1} - dest
|
|
||||||
AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1}
|
AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1}
|
||||||
# {0} - file
|
|
||||||
AddLogicalImageTask.doneAddingToReport=Done adding {0} to report
|
AddLogicalImageTask.doneAddingToReport=Done adding {0} to report
|
||||||
AddLogicalImageTask.doneCopying=Done copying
|
AddLogicalImageTask.doneCopying=Done copying
|
||||||
# {0} - file
|
|
||||||
# {1} - exception message
|
|
||||||
AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
|
AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
|
||||||
# {0} - src
|
|
||||||
# {1} - dest
|
|
||||||
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
|
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
|
||||||
# {0} - exception message
|
# {0} - exception message
|
||||||
Case.closeException.couldNotCloseCase=Error closing case: {0}
|
Case.closeException.couldNotCloseCase=Error closing case: {0}
|
||||||
@ -20,7 +12,6 @@ Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directo
|
|||||||
Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources
|
Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources
|
||||||
Case.deleteCaseConfirmationDialog.message=Are you sure you want to close and delete the current case?
|
Case.deleteCaseConfirmationDialog.message=Are you sure you want to close and delete the current case?
|
||||||
Case.deleteCaseConfirmationDialog.title=Delete Current Case?
|
Case.deleteCaseConfirmationDialog.title=Delete Current Case?
|
||||||
# {0} - exception message
|
|
||||||
Case.deleteCaseFailureMessageBox.message=Error deleting case: {0}
|
Case.deleteCaseFailureMessageBox.message=Error deleting case: {0}
|
||||||
Case.deleteCaseFailureMessageBox.title=Failed to Delete Case
|
Case.deleteCaseFailureMessageBox.title=Failed to Delete Case
|
||||||
Case.exceptionMessage.cancelledByUser=Cancelled by user.
|
Case.exceptionMessage.cancelledByUser=Cancelled by user.
|
||||||
@ -183,19 +174,13 @@ LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01
|
|||||||
LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)
|
LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)
|
||||||
LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders
|
LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders
|
||||||
LogicalImagerDSProcessor.dataSourceType=Autopsy Imager
|
LogicalImagerDSProcessor.dataSourceType=Autopsy Imager
|
||||||
# {0} - directory
|
|
||||||
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
|
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
|
||||||
# {0} - directory
|
|
||||||
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
|
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
|
||||||
# {0} - imageDirPath
|
|
||||||
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
|
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
|
||||||
LogicalImagerPanel.imageTable.columnModel.title0=Hostname
|
LogicalImagerPanel.imageTable.columnModel.title0=Hostname
|
||||||
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
|
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
|
||||||
LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images
|
LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images
|
||||||
# {0} - sparseImageDirectory
|
|
||||||
# {1} - image
|
|
||||||
LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}
|
LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}
|
||||||
# {0} - invalidFormatDirectory
|
|
||||||
LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
||||||
LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images
|
LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images
|
||||||
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
|
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
|
||||||
@ -266,15 +251,10 @@ AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in addi
|
|||||||
AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules
|
AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules
|
||||||
AddImageWizardIterator.stepXofN=Step {0} of {1}
|
AddImageWizardIterator.stepXofN=Step {0} of {1}
|
||||||
AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1}
|
AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1}
|
||||||
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\!
|
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open!
|
||||||
Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0}
|
Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0}
|
||||||
Case.open.msgDlg.updated.title=Case Database Schema Update
|
Case.open.msgDlg.updated.title=Case Database Schema Update
|
||||||
Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\
|
Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \nthis case are missing. Would you like to search for them now?\nPreviously, the image was located at:\n{0}\nPlease note that you will still be able to browse directories and generate reports\nif you choose No, but you will not be able to view file content or run the ingest process.
|
||||||
this case are missing. Would you like to search for them now?\n\
|
|
||||||
Previously, the image was located at:\n\
|
|
||||||
{0}\n\
|
|
||||||
Please note that you will still be able to browse directories and generate reports\n\
|
|
||||||
if you choose No, but you will not be able to view file content or run the ingest process.
|
|
||||||
Case.checkImgExist.confDlg.doesntExist.title=Missing Image
|
Case.checkImgExist.confDlg.doesntExist.title=Missing Image
|
||||||
Case.addImg.exception.msg=Error adding image to the case
|
Case.addImg.exception.msg=Error adding image to the case
|
||||||
Case.updateCaseName.exception.msg=Error while trying to update the case name.
|
Case.updateCaseName.exception.msg=Error while trying to update the case name.
|
||||||
@ -293,12 +273,9 @@ Case.GetCaseTypeGivenPath.Failure=Unable to get case type
|
|||||||
Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted.
|
Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted.
|
||||||
Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk.
|
Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk.
|
||||||
Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1}
|
Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1}
|
||||||
CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\
|
CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \nCase Name: {0}\nCase Directory: {1}
|
||||||
Case Name: {0}\n\
|
|
||||||
Case Directory: {1}
|
|
||||||
CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case
|
CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case
|
||||||
CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\n\
|
CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\nClose the folder and file and try again or you can delete the case manually.
|
||||||
Close the folder and file and try again or you can delete the case manually.
|
|
||||||
CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use
|
CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use
|
||||||
CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted.
|
CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted.
|
||||||
CaseOpenAction.autFilter.title={0} Case File ( {1})
|
CaseOpenAction.autFilter.title={0} Case File ( {1})
|
||||||
@ -330,8 +307,7 @@ NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case
|
|||||||
NewCaseWizardAction.databaseProblem2.text=Error
|
NewCaseWizardAction.databaseProblem2.text=Error
|
||||||
NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > |
|
NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > |
|
||||||
NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists.
|
NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists.
|
||||||
NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\
|
NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\nDo you want to create that directory?
|
||||||
Do you want to create that directory?
|
|
||||||
NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory
|
NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory
|
||||||
NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0}
|
NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0}
|
||||||
NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0}
|
NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0}
|
||||||
@ -360,14 +336,12 @@ OptionalCasePropertiesPanel.lbPointOfContactPhoneLabel.text=Phone:
|
|||||||
OptionalCasePropertiesPanel.orgainizationPanel.border.title=Organization
|
OptionalCasePropertiesPanel.orgainizationPanel.border.title=Organization
|
||||||
RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range.
|
RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range.
|
||||||
RecentCases.getName.text=Clear Recent Cases
|
RecentCases.getName.text=Clear Recent Cases
|
||||||
# {0} - case name
|
|
||||||
RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists.
|
RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists.
|
||||||
SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add
|
SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add
|
||||||
StartupWindow.title.text=Welcome
|
StartupWindow.title.text=Welcome
|
||||||
UnpackagePortableCaseDialog.title.text=Unpackage Portable Case
|
UnpackagePortableCaseDialog.title.text=Unpackage Portable Case
|
||||||
UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001)
|
UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001)
|
||||||
UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001
|
UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001
|
||||||
# {0} - case folder
|
|
||||||
UnpackagePortableCaseDialog.validatePaths.caseFolderExists=Folder {0} already exists
|
UnpackagePortableCaseDialog.validatePaths.caseFolderExists=Folder {0} already exists
|
||||||
UnpackagePortableCaseDialog.validatePaths.caseIsNotFile=Selected path is not a file
|
UnpackagePortableCaseDialog.validatePaths.caseIsNotFile=Selected path is not a file
|
||||||
UnpackagePortableCaseDialog.validatePaths.caseNotFound=File does not exist
|
UnpackagePortableCaseDialog.validatePaths.caseNotFound=File does not exist
|
||||||
@ -381,15 +355,15 @@ UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executabl
|
|||||||
UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases
|
UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases
|
||||||
UpdateRecentCases.menuItem.empty=-Empty-
|
UpdateRecentCases.menuItem.empty=-Empty-
|
||||||
AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel
|
AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel
|
||||||
NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive
|
NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on "C:" drive
|
||||||
NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on \"C:\" drive. Case folder is created on the target system
|
NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on "C:" drive. Case folder is created on the target system
|
||||||
NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive.
|
NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive.
|
||||||
CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
|
CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
|
||||||
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
|
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
|
||||||
MissingImageDialog.lbWarning.text=
|
MissingImageDialog.lbWarning.text=
|
||||||
MissingImageDialog.lbWarning.toolTipText=
|
MissingImageDialog.lbWarning.toolTipText=
|
||||||
NewCaseVisualPanel1.caseParentDirWarningLabel.text=
|
NewCaseVisualPanel1.caseParentDirWarningLabel.text=
|
||||||
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user
|
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user\t\t
|
||||||
NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user
|
NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user
|
||||||
NewCaseVisualPanel1.caseTypeLabel.text=Case Type:
|
NewCaseVisualPanel1.caseTypeLabel.text=Case Type:
|
||||||
SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist!
|
SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist!
|
||||||
|
@ -66,6 +66,7 @@ DataSourceSummaryDialog.window.title=Data Sources Summary
|
|||||||
DataSourceSummaryNode.column.dataSourceName.header=Data Source Name
|
DataSourceSummaryNode.column.dataSourceName.header=Data Source Name
|
||||||
DataSourceSummaryNode.column.files.header=Files
|
DataSourceSummaryNode.column.files.header=Files
|
||||||
DataSourceSummaryNode.column.results.header=Results
|
DataSourceSummaryNode.column.results.header=Results
|
||||||
|
DataSourceSummaryNode.column.status.header=Ingest Status
|
||||||
DataSourceSummaryNode.column.tags.header=Tags
|
DataSourceSummaryNode.column.tags.header=Tags
|
||||||
DataSourceSummaryNode.column.type.header=Type
|
DataSourceSummaryNode.column.type.header=Type
|
||||||
DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
|
DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
|
||||||
|
@ -37,8 +37,10 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
|||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryNode.DataSourceSummaryEntryNode;
|
import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryNode.DataSourceSummaryEntryNode;
|
||||||
import static javax.swing.SwingConstants.RIGHT;
|
import static javax.swing.SwingConstants.RIGHT;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.table.TableColumn;
|
import javax.swing.table.TableColumn;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
|
import org.sleuthkit.datamodel.IngestJobInfo;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
@ -50,9 +52,10 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(DataSourceBrowser.class.getName());
|
private static final Logger logger = Logger.getLogger(DataSourceBrowser.class.getName());
|
||||||
private static final int COUNT_COLUMN_WIDTH = 25;
|
private static final int COUNT_COLUMN_WIDTH = 20;
|
||||||
private static final int USAGE_COLUMN_WIDTH = 120;
|
private static final int INGEST_STATUS_WIDTH = 50;
|
||||||
private static final int DATA_SOURCE_COLUMN_WIDTH = 325;
|
private static final int USAGE_COLUMN_WIDTH = 110;
|
||||||
|
private static final int DATA_SOURCE_COLUMN_WIDTH = 280;
|
||||||
private final Outline outline;
|
private final Outline outline;
|
||||||
private final org.openide.explorer.view.OutlineView outlineView;
|
private final org.openide.explorer.view.OutlineView outlineView;
|
||||||
private final ExplorerManager explorerManager;
|
private final ExplorerManager explorerManager;
|
||||||
@ -69,6 +72,7 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana
|
|||||||
outlineView = new org.openide.explorer.view.OutlineView();
|
outlineView = new org.openide.explorer.view.OutlineView();
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
outlineView.setPropertyColumns(
|
outlineView.setPropertyColumns(
|
||||||
|
Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(),
|
||||||
Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(),
|
Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(),
|
||||||
Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(),
|
Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(),
|
||||||
Bundle.DataSourceSummaryNode_column_results_header(), Bundle.DataSourceSummaryNode_column_results_header(),
|
Bundle.DataSourceSummaryNode_column_results_header(), Bundle.DataSourceSummaryNode_column_results_header(),
|
||||||
@ -90,6 +94,8 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana
|
|||||||
column.setPreferredWidth(COUNT_COLUMN_WIDTH);
|
column.setPreferredWidth(COUNT_COLUMN_WIDTH);
|
||||||
} else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_type_header())) {
|
} else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_type_header())) {
|
||||||
column.setPreferredWidth(USAGE_COLUMN_WIDTH);
|
column.setPreferredWidth(USAGE_COLUMN_WIDTH);
|
||||||
|
} else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_status_header())) {
|
||||||
|
column.setPreferredWidth(INGEST_STATUS_WIDTH);
|
||||||
} else {
|
} else {
|
||||||
column.setPreferredWidth(DATA_SOURCE_COLUMN_WIDTH);
|
column.setPreferredWidth(DATA_SOURCE_COLUMN_WIDTH);
|
||||||
}
|
}
|
||||||
@ -182,6 +188,47 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the DataSourceBrowser to display up to date status information for
|
||||||
|
* the data sources.
|
||||||
|
*
|
||||||
|
* @param dataSourceId the ID of the data source which should be updated
|
||||||
|
* @param newStatus the new status which the data source should have
|
||||||
|
*/
|
||||||
|
void refresh(long dataSourceId, IngestJobInfo.IngestJobStatusType newStatus) {
|
||||||
|
|
||||||
|
//attempt to update the status of any datasources that had status which was STARTED
|
||||||
|
for (DataSourceSummary summary : dataSourceSummaryList) {
|
||||||
|
if (summary.getDataSource().getId() == dataSourceId) {
|
||||||
|
summary.setIngestStatus(newStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//figure out which nodes were previously selected
|
||||||
|
Node[] selectedNodes = explorerManager.getSelectedNodes();
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
explorerManager.setRootContext(new DataSourceSummaryNode(dataSourceSummaryList));
|
||||||
|
List<Node> nodesToSelect = new ArrayList<>();
|
||||||
|
for (Node node : explorerManager.getRootContext().getChildren().getNodes()) {
|
||||||
|
if (node instanceof DataSourceSummaryEntryNode) {
|
||||||
|
//there should only be one selected node as multi-select is disabled
|
||||||
|
for (Node selectedNode : selectedNodes) {
|
||||||
|
if (((DataSourceSummaryEntryNode) node).getDataSource().equals(((DataSourceSummaryEntryNode) selectedNode).getDataSource())) {
|
||||||
|
nodesToSelect.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//reselect the previously selected Nodes
|
||||||
|
try {
|
||||||
|
explorerManager.setSelectedNodes(nodesToSelect.toArray(new Node[nodesToSelect.size()]));
|
||||||
|
} catch (PropertyVetoException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error selecting previously selected nodes", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* 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
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
@ -18,7 +18,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
|
import org.sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper object for a DataSource and the information associated with it.
|
* Wrapper object for a DataSource and the information associated with it.
|
||||||
@ -26,7 +35,10 @@ import org.sleuthkit.datamodel.DataSource;
|
|||||||
*/
|
*/
|
||||||
class DataSourceSummary {
|
class DataSourceSummary {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(DataSourceSummary.class.getName());
|
||||||
|
private static final String INGEST_JOB_STATUS_QUERY = "status_id FROM ingest_jobs WHERE obj_id=";
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
private IngestJobStatusType status = null;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final long filesCount;
|
private final long filesCount;
|
||||||
private final long resultsCount;
|
private final long resultsCount;
|
||||||
@ -45,12 +57,26 @@ class DataSourceSummary {
|
|||||||
*/
|
*/
|
||||||
DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) {
|
DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) {
|
||||||
dataSource = dSource;
|
dataSource = dSource;
|
||||||
|
getStatusFromDatabase();
|
||||||
type = typeValue == null ? "" : typeValue;
|
type = typeValue == null ? "" : typeValue;
|
||||||
filesCount = numberOfFiles == null ? 0 : numberOfFiles;
|
filesCount = numberOfFiles == null ? 0 : numberOfFiles;
|
||||||
resultsCount = numberOfResults == null ? 0 : numberOfResults;
|
resultsCount = numberOfResults == null ? 0 : numberOfResults;
|
||||||
tagsCount = numberOfTags == null ? 0 : numberOfTags;
|
tagsCount = numberOfTags == null ? 0 : numberOfTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the status of the ingest job from the case database
|
||||||
|
*/
|
||||||
|
private void getStatusFromDatabase() {
|
||||||
|
try {
|
||||||
|
IngestJobQueryCallback callback = new IngestJobQueryCallback();
|
||||||
|
Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select(INGEST_JOB_STATUS_QUERY + dataSource.getId(), callback);
|
||||||
|
status = callback.getStatus();
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error getting status for data source from case database", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the DataSource
|
* Get the DataSource
|
||||||
*
|
*
|
||||||
@ -60,6 +86,16 @@ class DataSourceSummary {
|
|||||||
return dataSource;
|
return dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually set the ingest job status
|
||||||
|
*
|
||||||
|
* @param ingestStatus the status which the ingest job should have
|
||||||
|
* currently, null to display empty string
|
||||||
|
*/
|
||||||
|
void setIngestStatus(IngestJobStatusType ingestStatus) {
|
||||||
|
status = ingestStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of this DataSource
|
* Get the type of this DataSource
|
||||||
*
|
*
|
||||||
@ -87,6 +123,16 @@ class DataSourceSummary {
|
|||||||
return resultsCount;
|
return resultsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the IngestJobStatusType associated with this data source.
|
||||||
|
*
|
||||||
|
* @return the IngestJobStatusType associated with this data source. Can be
|
||||||
|
* null if the IngestJobStatusType is not STARTED or COMPLETED.
|
||||||
|
*/
|
||||||
|
IngestJobStatusType getIngestStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of tagged content objects in this DataSource
|
* Get the number of tagged content objects in this DataSource
|
||||||
*
|
*
|
||||||
@ -95,4 +141,40 @@ class DataSourceSummary {
|
|||||||
long getTagsCount() {
|
long getTagsCount() {
|
||||||
return tagsCount;
|
return tagsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to parse result set, getting the status to be associated with
|
||||||
|
* this data source
|
||||||
|
*/
|
||||||
|
class IngestJobQueryCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
|
||||||
|
|
||||||
|
private IngestJobStatusType jobStatus = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ResultSet rs) {
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
IngestJobStatusType currentStatus = IngestJobStatusType.fromID(rs.getInt("status_id"));
|
||||||
|
if (currentStatus == IngestJobStatusType.COMPLETED) {
|
||||||
|
jobStatus = currentStatus;
|
||||||
|
} else if (currentStatus == IngestJobStatusType.STARTED) {
|
||||||
|
jobStatus = currentStatus;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error getting status for ingest job", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the status which was determined for this callback
|
||||||
|
*
|
||||||
|
* @return the status of the data source which was queried for
|
||||||
|
*/
|
||||||
|
IngestJobStatusType getStatus() {
|
||||||
|
return jobStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,18 @@
|
|||||||
package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
package org.sleuthkit.autopsy.casemodule.datasourcesummary;
|
||||||
|
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
|
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
|
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent;
|
||||||
|
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent.Reason;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
|
import org.sleuthkit.datamodel.IngestJobInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog for displaying the Data Sources Summary information
|
* Dialog for displaying the Data Sources Summary information
|
||||||
@ -38,7 +42,6 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser
|
|||||||
private final DataSourceSummaryDetailsPanel detailsPanel;
|
private final DataSourceSummaryDetailsPanel detailsPanel;
|
||||||
private final DataSourceBrowser dataSourcesPanel;
|
private final DataSourceBrowser dataSourcesPanel;
|
||||||
private final IngestJobInfoPanel ingestHistoryPanel;
|
private final IngestJobInfoPanel ingestHistoryPanel;
|
||||||
private static final Logger logger = Logger.getLogger(DataSourceSummaryDialog.class.getName());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form DataSourceSummaryDialog for displaying a summary of the
|
* Creates new form DataSourceSummaryDialog for displaying a summary of the
|
||||||
@ -73,6 +76,17 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser
|
|||||||
this.repaint();
|
this.repaint();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
//add listener to refresh jobs with Started status when they complete
|
||||||
|
IngestManager.getInstance().addIngestJobEventListener((PropertyChangeEvent evt) -> {
|
||||||
|
if (evt instanceof DataSourceAnalysisCompletedEvent) {
|
||||||
|
DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt;
|
||||||
|
if (dsEvent.getResult() == Reason.ANALYSIS_COMPLETED) {
|
||||||
|
dataSourcesPanel.refresh(dsEvent.getDataSource().getId(), IngestJobInfo.IngestJobStatusType.COMPLETED);
|
||||||
|
} else if (dsEvent.getResult() == Reason.ANALYSIS_CANCELLED) {
|
||||||
|
dataSourcesPanel.refresh(dsEvent.getDataSource().getId(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
this.pack();
|
this.pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,7 @@ final class DataSourceSummaryNode extends AbstractNode {
|
|||||||
static final class DataSourceSummaryEntryNode extends AbstractNode {
|
static final class DataSourceSummaryEntryNode extends AbstractNode {
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
private final String status;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final long filesCount;
|
private final long filesCount;
|
||||||
private final long resultsCount;
|
private final long resultsCount;
|
||||||
@ -124,6 +125,7 @@ final class DataSourceSummaryNode extends AbstractNode {
|
|||||||
DataSourceSummaryEntryNode(DataSourceSummary dataSourceSummary) {
|
DataSourceSummaryEntryNode(DataSourceSummary dataSourceSummary) {
|
||||||
super(Children.LEAF);
|
super(Children.LEAF);
|
||||||
dataSource = dataSourceSummary.getDataSource();
|
dataSource = dataSourceSummary.getDataSource();
|
||||||
|
status = dataSourceSummary.getIngestStatus() == null ? "" : dataSourceSummary.getIngestStatus().getDisplayName();
|
||||||
type = dataSourceSummary.getType();
|
type = dataSourceSummary.getType();
|
||||||
filesCount = dataSourceSummary.getFilesCount();
|
filesCount = dataSourceSummary.getFilesCount();
|
||||||
resultsCount = dataSourceSummary.getResultsCount();
|
resultsCount = dataSourceSummary.getResultsCount();
|
||||||
@ -143,6 +145,7 @@ final class DataSourceSummaryNode extends AbstractNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Messages({"DataSourceSummaryNode.column.dataSourceName.header=Data Source Name",
|
@Messages({"DataSourceSummaryNode.column.dataSourceName.header=Data Source Name",
|
||||||
|
"DataSourceSummaryNode.column.status.header=Ingest Status",
|
||||||
"DataSourceSummaryNode.column.type.header=Type",
|
"DataSourceSummaryNode.column.type.header=Type",
|
||||||
"DataSourceSummaryNode.column.files.header=Files",
|
"DataSourceSummaryNode.column.files.header=Files",
|
||||||
"DataSourceSummaryNode.column.results.header=Results",
|
"DataSourceSummaryNode.column.results.header=Results",
|
||||||
@ -157,6 +160,7 @@ final class DataSourceSummaryNode extends AbstractNode {
|
|||||||
}
|
}
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_dataSourceName_header(), Bundle.DataSourceSummaryNode_column_dataSourceName_header(), Bundle.DataSourceSummaryNode_column_dataSourceName_header(),
|
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_dataSourceName_header(), Bundle.DataSourceSummaryNode_column_dataSourceName_header(), Bundle.DataSourceSummaryNode_column_dataSourceName_header(),
|
||||||
dataSource));
|
dataSource));
|
||||||
|
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(), status));
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(),
|
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(),
|
||||||
type));
|
type));
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(),
|
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(),
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.services;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -30,15 +31,18 @@ import java.util.logging.Level;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.CaseDbAccessManager;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TagName;
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
import org.sleuthkit.datamodel.TskData.DbType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A per case Autopsy service that manages the addition of content and artifact
|
* A per case Autopsy service that manages the addition of content and artifact
|
||||||
@ -49,6 +53,32 @@ public class TagsManager implements Closeable {
|
|||||||
private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName());
|
||||||
private final SleuthkitCase caseDb;
|
private final SleuthkitCase caseDb;
|
||||||
|
|
||||||
|
static {
|
||||||
|
//Create the contentviewer tags table (beta) if the current case does not
|
||||||
|
//have the table present
|
||||||
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), evt -> {
|
||||||
|
if (evt.getNewValue() != null) {
|
||||||
|
Case currentCase = (Case) evt.getNewValue();
|
||||||
|
try {
|
||||||
|
CaseDbAccessManager caseDb = currentCase.getSleuthkitCase().getCaseDbAccessManager();
|
||||||
|
if (caseDb.tableExists(ContentViewerTagManager.TABLE_NAME)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.SQLITE)) {
|
||||||
|
caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_SQLITE);
|
||||||
|
} else if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.POSTGRESQL)) {
|
||||||
|
caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_POSTGRESQL);
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE,
|
||||||
|
String.format("Unable to create the %s table for image tag storage.",
|
||||||
|
ContentViewerTagManager.TABLE_NAME), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether or not a given tag display name contains an illegal
|
* Tests whether or not a given tag display name contains an illegal
|
||||||
* character.
|
* character.
|
||||||
|
@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.casemodule.services.contentviewertags;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A per case Autopsy service that manages the addition of content viewer tags
|
||||||
|
* to the case database. This manager is also responsible for serializing and
|
||||||
|
* deserializing instances of your tag data objects for persistence and
|
||||||
|
* retrieval.
|
||||||
|
*/
|
||||||
|
public class ContentViewerTagManager {
|
||||||
|
|
||||||
|
//Used to convert Java beans into the physical representation that will be stored
|
||||||
|
//in the database.
|
||||||
|
private static final ObjectMapper SERIALIZER = new ObjectMapper();
|
||||||
|
|
||||||
|
public static final String TABLE_NAME = "beta_tag_app_data";
|
||||||
|
public static final String TABLE_SCHEMA_SQLITE = "(app_data_id INTEGER PRIMARY KEY, "
|
||||||
|
+ "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, "
|
||||||
|
+ "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))";
|
||||||
|
public static final String TABLE_SCHEMA_POSTGRESQL = "(app_data_id BIGSERIAL PRIMARY KEY, "
|
||||||
|
+ "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, "
|
||||||
|
+ "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))";
|
||||||
|
|
||||||
|
private static final String INSERT_TAG_DATA = "(content_tag_id, app_data) VALUES (%d, '%s')";
|
||||||
|
private static final String UPDATE_TAG_DATA = "SET content_tag_id = %d, app_data = '%s' WHERE app_data_id = %d";
|
||||||
|
private static final String SELECT_TAG_DATA = "* FROM " + TABLE_NAME + " WHERE content_tag_id = %d";
|
||||||
|
private static final String DELETE_TAG_DATA = "WHERE app_data_id = %d";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and saves a new ContentViewerTag in the case database. The
|
||||||
|
* generic tag data instance T will be automatically serialized into a
|
||||||
|
* storable format.
|
||||||
|
*
|
||||||
|
* @param <T> Generic class type that will be serialized into a storable
|
||||||
|
* format for persistence.
|
||||||
|
* @param contentTag ContentTag that this ContentViewerTag is associated
|
||||||
|
* with (1:1).
|
||||||
|
* @param tagDataBean Data instance that contains the tag information to be
|
||||||
|
* persisted.
|
||||||
|
* @return An instance of a ContentViewerTag of type T, which contains all
|
||||||
|
* the stored information.
|
||||||
|
*
|
||||||
|
* @throws SerializationException Thrown if the tag data instance T could
|
||||||
|
* not be serialized into a storable format.
|
||||||
|
* @throws TskCoreException Thrown if this operation did not successfully
|
||||||
|
* persist in the case database.
|
||||||
|
* @throws NoCurrentCaseException Thrown if invocation of this method occurs
|
||||||
|
* when no case is open.
|
||||||
|
*/
|
||||||
|
public static <T> ContentViewerTag<T> saveTag(ContentTag contentTag, T tagDataBean)
|
||||||
|
throws SerializationException, TskCoreException, NoCurrentCaseException {
|
||||||
|
try {
|
||||||
|
long contentTagId = contentTag.getId();
|
||||||
|
String serialAppData = SERIALIZER.writeValueAsString(tagDataBean);
|
||||||
|
String insertTemplateInstance = String.format(INSERT_TAG_DATA,
|
||||||
|
contentTagId, serialAppData);
|
||||||
|
long insertId = Case.getCurrentCaseThrows()
|
||||||
|
.getSleuthkitCase()
|
||||||
|
.getCaseDbAccessManager()
|
||||||
|
.insert(TABLE_NAME, insertTemplateInstance);
|
||||||
|
return new ContentViewerTag<>(insertId, contentTag, tagDataBean);
|
||||||
|
} catch (JsonProcessingException ex) {
|
||||||
|
throw new SerializationException("Unable to convert object instance into a storable format", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the ContentViewerTag instance with the new tag data T and
|
||||||
|
* persists the changes to the case database.
|
||||||
|
*
|
||||||
|
* @param <T> Generic class type that will be serialized into a storable
|
||||||
|
* format.
|
||||||
|
* @param oldTag ContentViewerTag instance to be updated
|
||||||
|
* @param tagDataBean Data instance that contains the updated information to
|
||||||
|
* be persisted.
|
||||||
|
*
|
||||||
|
* @throws SerializationException Thrown if the tag data instance T could
|
||||||
|
* not be serialized into a storable format.
|
||||||
|
* @throws TskCoreException Thrown if this operation did not successfully
|
||||||
|
* persist in the case database.
|
||||||
|
* @throws NoCurrentCaseException Thrown if invocation of this method occurs
|
||||||
|
* when no case is open.
|
||||||
|
*/
|
||||||
|
public static <T> ContentViewerTag<T> updateTag(ContentViewerTag<T> oldTag, T tagDataBean)
|
||||||
|
throws SerializationException, TskCoreException, NoCurrentCaseException {
|
||||||
|
try {
|
||||||
|
String serialAppData = SERIALIZER.writeValueAsString(tagDataBean);
|
||||||
|
String updateTemplateInstance = String.format(UPDATE_TAG_DATA,
|
||||||
|
oldTag.getContentTag().getId(), serialAppData, oldTag.getId());
|
||||||
|
Case.getCurrentCaseThrows()
|
||||||
|
.getSleuthkitCase()
|
||||||
|
.getCaseDbAccessManager()
|
||||||
|
.update(TABLE_NAME, updateTemplateInstance);
|
||||||
|
return new ContentViewerTag<>(oldTag.getId(), oldTag.getContentTag(), tagDataBean);
|
||||||
|
} catch (JsonProcessingException ex) {
|
||||||
|
throw new SerializationException("Unable to convert object instance into a storable format", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a ContentViewerTag instance that is associated with the
|
||||||
|
* specified ContentTag. The Java class T that represents the technical
|
||||||
|
* details of the tag should be passed so that automatic binding can take
|
||||||
|
* place.
|
||||||
|
*
|
||||||
|
* @param <T> Generic class type that will be instantiated and filled in
|
||||||
|
* with data.
|
||||||
|
* @param contentTag ContentTag that this ContentViewerTag is associated
|
||||||
|
* with (1:1)
|
||||||
|
* @param clazz Generic class that will be instantiated and filled in with
|
||||||
|
* data.
|
||||||
|
* @return ContentViewerTag with an instance of T as a member variable or
|
||||||
|
* null if the content tag does not have an associated ContentViewerTag of
|
||||||
|
* type T.
|
||||||
|
*
|
||||||
|
* @throws TskCoreException Thrown if this operation did not successfully
|
||||||
|
* persist in the case database.
|
||||||
|
* @throws NoCurrentCaseException Thrown if invocation of this method occurs
|
||||||
|
* when no case is open.
|
||||||
|
*/
|
||||||
|
public static <T> ContentViewerTag<T> getTag(ContentTag contentTag, Class<T> clazz) throws TskCoreException, NoCurrentCaseException {
|
||||||
|
String selectTemplateInstance = String.format(SELECT_TAG_DATA, contentTag.getId());
|
||||||
|
final ResultWrapper<ContentViewerTag<T>> result = new ResultWrapper<>();
|
||||||
|
Case.getCurrentCaseThrows()
|
||||||
|
.getSleuthkitCase()
|
||||||
|
.getCaseDbAccessManager()
|
||||||
|
.select(selectTemplateInstance, (ResultSet rs) -> {
|
||||||
|
try {
|
||||||
|
if (rs.next()) {
|
||||||
|
long tagId = rs.getLong(1);
|
||||||
|
String appDetails = rs.getString(3);
|
||||||
|
try {
|
||||||
|
T instance = SERIALIZER.readValue(appDetails, clazz);
|
||||||
|
result.setResult(new ContentViewerTag<>(tagId, contentTag, instance));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
//Databind for type T failed. Not a system error
|
||||||
|
//but rather a logic error on the part of the caller.
|
||||||
|
result.setResult(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
result.setException(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.hasException()) {
|
||||||
|
throw new TskCoreException("Unable to select tag from case db", result.getException());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for holding state in the CaseDbAccessQueryCallback.
|
||||||
|
* CaseDbAccessQueryCallback has no support for exception handling.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
private static class ResultWrapper<T> {
|
||||||
|
|
||||||
|
private T result;
|
||||||
|
private SQLException ex = null;
|
||||||
|
|
||||||
|
public void setResult(T result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setException(SQLException ex) {
|
||||||
|
this.ex = ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasException() {
|
||||||
|
return this.ex != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SQLException getException() {
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the content viewer tag with the specified id.
|
||||||
|
*
|
||||||
|
* @param contentViewerTag ContentViewerTag to delete
|
||||||
|
* @throws TskCoreException Thrown if this operation did not successfully
|
||||||
|
* persist in the case database.
|
||||||
|
* @throws NoCurrentCaseException Thrown if invocation of this method occurs
|
||||||
|
* when no case is open.
|
||||||
|
*/
|
||||||
|
public static <T> void deleteTag(ContentViewerTag<T> contentViewerTag) throws TskCoreException, NoCurrentCaseException {
|
||||||
|
String deleteTemplateInstance = String.format(DELETE_TAG_DATA, contentViewerTag.getId());
|
||||||
|
Case.getCurrentCaseThrows()
|
||||||
|
.getSleuthkitCase()
|
||||||
|
.getCaseDbAccessManager()
|
||||||
|
.delete(TABLE_NAME, deleteTemplateInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a stored tag in the case database. It is a wrapper
|
||||||
|
* for the tag id, the attached Content tag object, and the Java bean
|
||||||
|
* instance that describes the technical details for reconstructing the tag.
|
||||||
|
*
|
||||||
|
* @param <T> Generic class type that will be instantiated and filled in
|
||||||
|
* with data.
|
||||||
|
*/
|
||||||
|
public static class ContentViewerTag<T> {
|
||||||
|
|
||||||
|
private final long id;
|
||||||
|
private final ContentTag contentTag;
|
||||||
|
private final T details;
|
||||||
|
|
||||||
|
private ContentViewerTag(long id, ContentTag contentTag, T details) {
|
||||||
|
this.id = id;
|
||||||
|
this.contentTag = contentTag;
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentTag getContentTag() {
|
||||||
|
return contentTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System exception thrown in the event that class instance T could not be
|
||||||
|
* properly serialized.
|
||||||
|
*/
|
||||||
|
public static class SerializationException extends Exception {
|
||||||
|
|
||||||
|
public SerializationException(String message, Exception source) {
|
||||||
|
super(message, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prevent this class from being instantiated.
|
||||||
|
private ContentViewerTagManager() {
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,8 @@
|
|||||||
AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.all=All File Categories
|
AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.all=All File Categories
|
||||||
AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents
|
AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents
|
||||||
AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.media=Media
|
AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.media=Media
|
||||||
# {0} - threshold percent
|
|
||||||
AbstractCommonFilesMetadataBuilder.getPercentFilter.thresholdPercent=, Threshold {0}%
|
AbstractCommonFilesMetadataBuilder.getPercentFilter.thresholdPercent=, Threshold {0}%
|
||||||
# {0} - attr type
|
|
||||||
# {1} - threshold string
|
|
||||||
AllInterCaseCommonAttributeSearcher.buildTabTitle.titleInterAll=Common Properties (All Central Repository Cases, {0}{1})
|
AllInterCaseCommonAttributeSearcher.buildTabTitle.titleInterAll=Common Properties (All Central Repository Cases, {0}{1})
|
||||||
# {0} - build category
|
|
||||||
# {1} - threshold string
|
|
||||||
AllIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraAll=Common Properties (All Data Sources, {0}{1})
|
AllIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraAll=Common Properties (All Data Sources, {0}{1})
|
||||||
# {0} - number of datasources
|
# {0} - number of datasources
|
||||||
CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s).
|
CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s).
|
||||||
@ -103,13 +98,7 @@ CommonAttributePanel.organizeByCountRadio.text=Number of occurrences
|
|||||||
CommonAttributePanel.caseResultsRadioButton.text=Case
|
CommonAttributePanel.caseResultsRadioButton.text=Case
|
||||||
CommonAttributePanel.countResultsRadioButton.text=Number of data sources
|
CommonAttributePanel.countResultsRadioButton.text=Number of data sources
|
||||||
CommonAttributePanel.displayResultsLabel.text_2=Display results organized by:
|
CommonAttributePanel.displayResultsLabel.text_2=Display results organized by:
|
||||||
# {0} - case name
|
|
||||||
# {1} - attr type
|
|
||||||
# {2} - threshold string
|
|
||||||
SingleInterCaseCommonAttributeSearcher.buildTabTitle.titleInterSingle=Common Properties (Central Repository Case: {0}, {1}{2})
|
SingleInterCaseCommonAttributeSearcher.buildTabTitle.titleInterSingle=Common Properties (Central Repository Case: {0}, {1}{2})
|
||||||
# {0} - data source name
|
|
||||||
# {1} - build category
|
|
||||||
# {2} - threshold string
|
|
||||||
SingleIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraSingle=Common Properties (Data Source: {0}, {1}{2})
|
SingleIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraSingle=Common Properties (Data Source: {0}, {1}{2})
|
||||||
UserInputErrorManager.categories=No file categories are included in the search.
|
UserInputErrorManager.categories=No file categories are included in the search.
|
||||||
UserInputErrorManager.frequency=Invalid Frequency Percentage: 0 < % < 100.
|
UserInputErrorManager.frequency=Invalid Frequency Percentage: 0 < % < 100.
|
||||||
|
@ -75,6 +75,10 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
|
|||||||
|
|
||||||
public AccountsBrowser() {
|
public AccountsBrowser() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
|
jSplitPane1.setResizeWeight(0.5);
|
||||||
|
jSplitPane1.setDividerLocation(0.75);
|
||||||
|
|
||||||
outline = outlineView.getOutline();
|
outline = outlineView.getOutline();
|
||||||
outlineView.setPropertyColumns(
|
outlineView.setPropertyColumns(
|
||||||
"device", Bundle.AccountNode_device(),
|
"device", Bundle.AccountNode_device(),
|
||||||
|
@ -13,32 +13,7 @@
|
|||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
|
||||||
<Component id="filtersPane" min="-2" pref="265" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="browseVisualizeTabPane" pref="786" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
|
||||||
<Component id="filtersPane" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
|
||||||
<Component id="browseVisualizeTabPane" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane">
|
<Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -51,6 +26,11 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</AccessibilityProperties>
|
</AccessibilityProperties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="0" insetsBottom="15" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
@ -90,6 +70,11 @@
|
|||||||
<Dimension value="[256, 495]"/>
|
<Dimension value="[256, 495]"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="15" insetsBottom="15" insetsRight="5" anchor="18" weightX="0.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -22,12 +22,13 @@ import com.google.common.eventbus.Subscribe;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.Insets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.swing.GroupLayout;
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JTabbedPane;
|
import javax.swing.JTabbedPane;
|
||||||
import javax.swing.LayoutStyle;
|
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.windows.Mode;
|
import org.openide.windows.Mode;
|
||||||
@ -93,39 +94,39 @@ public final class CVTTopComponent extends TopComponent {
|
|||||||
*/
|
*/
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
browseVisualizeTabPane = new JTabbedPane();
|
browseVisualizeTabPane = new JTabbedPane();
|
||||||
accountsBrowser = new AccountsBrowser();
|
accountsBrowser = new AccountsBrowser();
|
||||||
vizPanel = new VisualizationPanel();
|
vizPanel = new VisualizationPanel();
|
||||||
filtersPane = new FiltersPanel();
|
filtersPane = new FiltersPanel();
|
||||||
|
|
||||||
|
setLayout(new GridBagLayout());
|
||||||
|
|
||||||
browseVisualizeTabPane.setFont(new Font("Tahoma", 0, 18)); // NOI18N
|
browseVisualizeTabPane.setFont(new Font("Tahoma", 0, 18)); // NOI18N
|
||||||
browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N
|
browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N
|
||||||
browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.vizPanel.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), vizPanel); // NOI18N
|
browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.vizPanel.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), vizPanel); // NOI18N
|
||||||
|
|
||||||
filtersPane.setMinimumSize(new Dimension(256, 495));
|
gridBagConstraints = new GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
GroupLayout layout = new GroupLayout(this);
|
gridBagConstraints.gridy = 0;
|
||||||
this.setLayout(layout);
|
gridBagConstraints.fill = GridBagConstraints.BOTH;
|
||||||
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addGap(6, 6, 6)
|
gridBagConstraints.weighty = 1.0;
|
||||||
.addComponent(filtersPane, GroupLayout.PREFERRED_SIZE, 265, GroupLayout.PREFERRED_SIZE)
|
gridBagConstraints.insets = new Insets(15, 0, 15, 15);
|
||||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
add(browseVisualizeTabPane, gridBagConstraints);
|
||||||
.addComponent(browseVisualizeTabPane, GroupLayout.PREFERRED_SIZE, 786, Short.MAX_VALUE)
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGap(6, 6, 6)
|
|
||||||
.addComponent(filtersPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addGap(5, 5, 5))
|
|
||||||
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addComponent(browseVisualizeTabPane)
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
|
|
||||||
browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N
|
browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N
|
||||||
|
|
||||||
|
filtersPane.setMinimumSize(new Dimension(256, 495));
|
||||||
|
gridBagConstraints = new GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new Insets(15, 15, 15, 5);
|
||||||
|
add(filtersPane, gridBagConstraints);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,3 +44,4 @@ SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Other O
|
|||||||
SummaryViewer_Creation_Date_Title=Creation Date
|
SummaryViewer_Creation_Date_Title=Creation Date
|
||||||
SummaryViewer_FileRefNameColumn_Title=Path
|
SummaryViewer_FileRefNameColumn_Title=Path
|
||||||
SummaryViewer_TabTitle=Summary
|
SummaryViewer_TabTitle=Summary
|
||||||
|
SummeryViewer_FileRef_Message=<Select one Accout to see File References>
|
||||||
|
@ -11,29 +11,38 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="contactPane" max="32767" attributes="0"/>
|
|
||||||
<Component id="outlineViewPanel" alignment="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="outlineViewPanel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="contactPane" pref="332" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane" name="contactPane">
|
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||||
</Component>
|
<Properties>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
|
<Property name="orientation" type="int" value="0"/>
|
||||||
</Component>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane" name="contactPane">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="right"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="left"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -23,7 +23,6 @@ import java.awt.KeyboardFocusManager;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||||
import org.netbeans.swing.outline.Outline;
|
import org.netbeans.swing.outline.Outline;
|
||||||
@ -126,6 +125,9 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer{
|
|||||||
updateOutlineViewPanel();
|
updateOutlineViewPanel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
splitPane.setResizeWeight(0.5);
|
||||||
|
splitPane.setDividerLocation(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -183,29 +185,32 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer{
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
|
splitPane = new javax.swing.JSplitPane();
|
||||||
contactPane = new org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane();
|
contactPane = new org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane();
|
||||||
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
setLayout(new java.awt.GridBagLayout());
|
||||||
this.setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
splitPane.setRightComponent(contactPane);
|
||||||
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
splitPane.setLeftComponent(outlineViewPanel);
|
||||||
.addComponent(outlineViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
);
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
layout.setVerticalGroup(
|
gridBagConstraints.gridx = 0;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.gridy = 0;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
.addComponent(outlineViewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, 332, Short.MAX_VALUE))
|
gridBagConstraints.weighty = 1.0;
|
||||||
);
|
add(splitPane, gridBagConstraints);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane contactPane;
|
private org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane contactPane;
|
||||||
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
|
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
|
||||||
|
private javax.swing.JSplitPane splitPane;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
}
|
}
|
||||||
|
@ -11,58 +11,57 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="thumbnailViewer" alignment="1" max="32767" attributes="0"/>
|
|
||||||
<Component id="contentViewer" alignment="1" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="separator" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="thumbnailViewer" pref="350" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="separator" min="-2" pref="2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="contentViewer" min="-2" pref="450" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail" name="thumbnailViewer">
|
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="orientation" type="int" value="0"/>
|
||||||
<Dimension value="[350, 102]"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[450, 400]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<AuxValues>
|
<Constraints>
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM)"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
</AuxValues>
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
</Component>
|
</Constraint>
|
||||||
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
</Constraints>
|
||||||
<Properties>
|
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||||
<Dimension value="[450, 400]"/>
|
<SubComponents>
|
||||||
</Property>
|
<Component class="org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail" name="thumbnailViewer">
|
||||||
</Properties>
|
<Properties>
|
||||||
<AuxValues>
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
<Dimension value="[350, 102]"/>
|
||||||
</AuxValues>
|
</Property>
|
||||||
</Component>
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Component class="javax.swing.JSeparator" name="separator">
|
<Dimension value="[450, 400]"/>
|
||||||
</Component>
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM)"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="left"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
||||||
|
<Properties>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[450, 400]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="right"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -65,6 +65,11 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
|||||||
* Creates new form ThumbnailViewer
|
* Creates new form ThumbnailViewer
|
||||||
*/
|
*/
|
||||||
public MediaViewer() {
|
public MediaViewer() {
|
||||||
|
initComponents();
|
||||||
|
|
||||||
|
splitPane.setResizeWeight(0.5);
|
||||||
|
splitPane.setDividerLocation(0.5);
|
||||||
|
|
||||||
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
|
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
|
||||||
|
|
||||||
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||||
@ -87,8 +92,6 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
initComponents();
|
|
||||||
|
|
||||||
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||||
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||||
handleNodeSelectionChange();
|
handleNodeSelectionChange();
|
||||||
@ -190,43 +193,37 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
|
splitPane = new javax.swing.JSplitPane();
|
||||||
thumbnailViewer = new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM);
|
thumbnailViewer = new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM);
|
||||||
contentViewer = new MessageDataContent();
|
contentViewer = new MessageDataContent();
|
||||||
separator = new javax.swing.JSeparator();
|
|
||||||
|
setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||||
|
|
||||||
thumbnailViewer.setMinimumSize(new java.awt.Dimension(350, 102));
|
thumbnailViewer.setMinimumSize(new java.awt.Dimension(350, 102));
|
||||||
thumbnailViewer.setPreferredSize(new java.awt.Dimension(450, 400));
|
thumbnailViewer.setPreferredSize(new java.awt.Dimension(450, 400));
|
||||||
|
splitPane.setLeftComponent(thumbnailViewer);
|
||||||
|
|
||||||
contentViewer.setPreferredSize(new java.awt.Dimension(450, 400));
|
contentViewer.setPreferredSize(new java.awt.Dimension(450, 400));
|
||||||
|
splitPane.setRightComponent(contentViewer);
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
this.setLayout(layout);
|
gridBagConstraints.gridx = 0;
|
||||||
layout.setHorizontalGroup(
|
gridBagConstraints.gridy = 0;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
.addComponent(thumbnailViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
.addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.weighty = 1.0;
|
||||||
.addContainerGap()
|
add(splitPane, gridBagConstraints);
|
||||||
.addComponent(separator)
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(thumbnailViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(contentViewer, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(3, 3, 3))
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
||||||
private javax.swing.JSeparator separator;
|
private javax.swing.JSplitPane splitPane;
|
||||||
private org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail thumbnailViewer;
|
private org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail thumbnailViewer;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
@ -18,13 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.communications.relationships;
|
package org.sleuthkit.autopsy.communications.relationships;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
@ -40,7 +37,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHO
|
|||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
|
||||||
import org.sleuthkit.datamodel.Tag;
|
|
||||||
import org.sleuthkit.datamodel.TimeUtilities;
|
import org.sleuthkit.datamodel.TimeUtilities;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.autopsy.communications.Utils;
|
import org.sleuthkit.autopsy.communications.Utils;
|
||||||
@ -72,7 +68,6 @@ final class MessageNode extends BlackboardArtifactNode {
|
|||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet sheet = super.createSheet();
|
Sheet sheet = super.createSheet();
|
||||||
List<Tag> tags = getAllTagsFromDatabase();
|
|
||||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||||
if (sheetSet == null) {
|
if (sheetSet == null) {
|
||||||
sheetSet = Sheet.createPropertiesSet();
|
sheetSet = Sheet.createPropertiesSet();
|
||||||
@ -81,17 +76,6 @@ final class MessageNode extends BlackboardArtifactNode {
|
|||||||
|
|
||||||
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
|
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
|
||||||
|
|
||||||
addScoreProperty(sheetSet, tags);
|
|
||||||
|
|
||||||
CorrelationAttributeInstance correlationAttribute = null;
|
|
||||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
|
||||||
correlationAttribute = getCorrelationAttributeInstance();
|
|
||||||
}
|
|
||||||
addCommentProperty(sheetSet, tags, correlationAttribute);
|
|
||||||
|
|
||||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
|
||||||
addCountProperty(sheetSet, correlationAttribute);
|
|
||||||
}
|
|
||||||
final BlackboardArtifact artifact = getArtifact();
|
final BlackboardArtifact artifact = getArtifact();
|
||||||
|
|
||||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||||
|
@ -11,32 +11,41 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,3,13,0,0,2,103"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="contentViewer" max="32767" attributes="0"/>
|
|
||||||
<Component id="outlineViewPanel" alignment="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="outlineViewPanel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="contentViewer" pref="390" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||||
<AuxValues>
|
<Properties>
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
<Property name="orientation" type="int" value="0"/>
|
||||||
</AuxValues>
|
</Properties>
|
||||||
</Component>
|
<Constraints>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
</Component>
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="bottom"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="left"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -23,7 +23,6 @@ import java.awt.KeyboardFocusManager;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||||
import org.netbeans.swing.outline.Outline;
|
import org.netbeans.swing.outline.Outline;
|
||||||
@ -68,6 +67,8 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
public MessagesViewer() {
|
public MessagesViewer() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
|
splitPane.setResizeWeight(0.5);
|
||||||
|
|
||||||
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
|
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
|
||||||
|
|
||||||
proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
||||||
@ -138,6 +139,8 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
updateOutlineViewPanel();
|
updateOutlineViewPanel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -192,29 +195,32 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
|
splitPane = new javax.swing.JSplitPane();
|
||||||
contentViewer = new MessageDataContent();
|
contentViewer = new MessageDataContent();
|
||||||
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
setLayout(new java.awt.GridBagLayout());
|
||||||
this.setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
splitPane.setBottomComponent(contentViewer);
|
||||||
.addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
splitPane.setLeftComponent(outlineViewPanel);
|
||||||
.addComponent(outlineViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
);
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
layout.setVerticalGroup(
|
gridBagConstraints.gridx = 0;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.gridy = 0;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
.addComponent(outlineViewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE))
|
gridBagConstraints.weighty = 1.0;
|
||||||
);
|
add(splitPane, gridBagConstraints);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
||||||
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
|
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
|
||||||
|
private javax.swing.JSplitPane splitPane;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<Properties>
|
||||||
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
@ -21,6 +24,7 @@
|
|||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
<Property name="horizontalScrollBarPolicy" type="int" value="32"/>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[300, 400]"/>
|
<Dimension value="[300, 400]"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
package org.sleuthkit.autopsy.communications.relationships;
|
package org.sleuthkit.autopsy.communications.relationships;
|
||||||
|
|
||||||
import java.awt.CardLayout;
|
import java.awt.CardLayout;
|
||||||
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
||||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||||
import org.openide.explorer.view.OutlineView;
|
import org.openide.explorer.view.OutlineView;
|
||||||
@ -99,6 +101,19 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
|
|||||||
outlineView.setEnabled(enabled);
|
outlineView.setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTableColumnsWidth(double... percentages) {
|
||||||
|
JTable table = outlineView.getOutline();
|
||||||
|
double total = 0;
|
||||||
|
for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) {
|
||||||
|
total += percentages[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) {
|
||||||
|
TableColumn column = table.getColumnModel().getColumn(i);
|
||||||
|
column.setPreferredWidth((int) (table.getPreferredSize().width * (percentages[i] / total)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* 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
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
@ -112,8 +127,10 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
|
|||||||
messagePanel = new javax.swing.JPanel();
|
messagePanel = new javax.swing.JPanel();
|
||||||
messageLabel = new javax.swing.JLabel();
|
messageLabel = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
setEnabled(false);
|
||||||
setLayout(new java.awt.CardLayout(5, 5));
|
setLayout(new java.awt.CardLayout(5, 5));
|
||||||
|
|
||||||
|
outlineView.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||||
outlineView.setPreferredSize(new java.awt.Dimension(300, 400));
|
outlineView.setPreferredSize(new java.awt.Dimension(300, 400));
|
||||||
add(outlineView, "outlineCard");
|
add(outlineView, "outlineCard");
|
||||||
|
|
||||||
|
@ -11,42 +11,22 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
|
|
||||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="scrollPane" alignment="1" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
|
|
||||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="scrollPane" alignment="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JScrollPane" name="scrollPane">
|
<Container class="javax.swing.JTabbedPane" name="tabPane">
|
||||||
<Properties>
|
<Events>
|
||||||
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
|
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="tabPaneStateChanged"/>
|
||||||
</Properties>
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="1" insetsLeft="1" insetsBottom="1" insetsRight="1" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
||||||
<SubComponents>
|
|
||||||
<Container class="javax.swing.JTabbedPane" name="tabPane">
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="tabPaneStateChanged"/>
|
|
||||||
</Events>
|
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
|
||||||
</Container>
|
|
||||||
</SubComponents>
|
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -55,8 +55,6 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
||||||
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
|
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
|
||||||
tabPane.add(mediaViewer.getDisplayName(), mediaViewer);
|
tabPane.add(mediaViewer.getDisplayName(), mediaViewer);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,33 +76,26 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
scrollPane = new javax.swing.JScrollPane();
|
|
||||||
tabPane = new javax.swing.JTabbedPane();
|
tabPane = new javax.swing.JTabbedPane();
|
||||||
|
|
||||||
scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
|
setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
tabPane.addChangeListener(new javax.swing.event.ChangeListener() {
|
tabPane.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||||
tabPaneStateChanged(evt);
|
tabPaneStateChanged(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
scrollPane.setViewportView(tabPane);
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
gridBagConstraints.gridy = 0;
|
||||||
this.setLayout(layout);
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
layout.setHorizontalGroup(
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addGap(0, 400, Short.MAX_VALUE)
|
gridBagConstraints.weighty = 1.0;
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
|
||||||
.addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING))
|
add(tabPane, gridBagConstraints);
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGap(0, 300, Short.MAX_VALUE)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(scrollPane))
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
|
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
|
||||||
@ -121,7 +112,6 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JScrollPane scrollPane;
|
|
||||||
private javax.swing.JTabbedPane tabPane;
|
private javax.swing.JTabbedPane tabPane;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
@ -11,36 +11,10 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,3,70,0,0,4,-35"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="countsPanel" max="32767" attributes="0"/>
|
|
||||||
<Component id="fileReferencesPanel" alignment="0" pref="485" max="32767" attributes="0"/>
|
|
||||||
<Component id="caseReferencesPanel" alignment="1" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="countsPanel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="fileReferencesPanel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="caseReferencesPanel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JPanel" name="countsPanel">
|
<Container class="javax.swing.JPanel" name="countsPanel">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -52,6 +26,11 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
@ -183,7 +162,7 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="fileReferencesPanel">
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="fileReferencesPanel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||||
@ -192,12 +171,14 @@
|
|||||||
</TitledBorder>
|
</TitledBorder>
|
||||||
</Border>
|
</Border>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[472, 300]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="caseReferencesPanel">
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="caseReferencesPanel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||||
@ -206,10 +187,12 @@
|
|||||||
</TitledBorder>
|
</TitledBorder>
|
||||||
</Border>
|
</Border>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[472, 300]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -46,7 +46,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
"SummaryViewer_FileRefNameColumn_Title=Path",
|
"SummaryViewer_FileRefNameColumn_Title=Path",
|
||||||
"SummaryViewer_CaseRefNameColumn_Title=Case Name",
|
"SummaryViewer_CaseRefNameColumn_Title=Case Name",
|
||||||
"SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Other Occurrences>",
|
"SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Other Occurrences>",
|
||||||
"SummaryViewer_Creation_Date_Title=Creation Date"
|
"SummaryViewer_Creation_Date_Title=Creation Date",
|
||||||
|
"SummeryViewer_FileRef_Message=<Select one Accout to see File References>",
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,6 +71,9 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_CaseRefNameColumn_Title());
|
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_CaseRefNameColumn_Title());
|
||||||
|
|
||||||
clearControls();
|
clearControls();
|
||||||
|
|
||||||
|
caseReferencesPanel.hideOutlineView(Bundle.SummaryViewer_CentralRepository_Message());
|
||||||
|
fileReferencesPanel.hideOutlineView(Bundle.SummeryViewer_FileRef_Message());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -97,6 +101,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
clearControls();
|
clearControls();
|
||||||
|
|
||||||
|
fileReferencesPanel.hideOutlineView(Bundle.SummeryViewer_FileRef_Message());
|
||||||
} else {
|
} else {
|
||||||
SelectionSummary summaryDetails = info.getSummary();
|
SelectionSummary summaryDetails = info.getSummary();
|
||||||
|
|
||||||
@ -106,6 +111,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
emailDataLabel.setText(Integer.toString(summaryDetails.getEmailCnt()));
|
emailDataLabel.setText(Integer.toString(summaryDetails.getEmailCnt()));
|
||||||
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt()));
|
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt()));
|
||||||
|
|
||||||
|
fileReferencesPanel.showOutlineView();
|
||||||
|
|
||||||
fileReferencesPanel.setNode(new AbstractNode(Children.create(new AccountSourceContentChildNodeFactory(info.getAccounts()), true)));
|
fileReferencesPanel.setNode(new AbstractNode(Children.create(new AccountSourceContentChildNodeFactory(info.getAccounts()), true)));
|
||||||
caseReferencesPanel.setNode(new AbstractNode(Children.create(new CorrelationCaseChildNodeFactory(info.getAccounts()), true)));
|
caseReferencesPanel.setNode(new AbstractNode(Children.create(new CorrelationCaseChildNodeFactory(info.getAccounts()), true)));
|
||||||
|
|
||||||
@ -178,6 +185,7 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
countsPanel = new javax.swing.JPanel();
|
countsPanel = new javax.swing.JPanel();
|
||||||
emailLabel = new javax.swing.JLabel();
|
emailLabel = new javax.swing.JLabel();
|
||||||
@ -193,6 +201,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
|
|
||||||
|
setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N
|
countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(emailLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(emailLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailLabel.text")); // NOI18N
|
||||||
@ -262,35 +272,33 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
|
|||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
add(countsPanel, gridBagConstraints);
|
||||||
|
|
||||||
fileReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.fileReferencesPanel.border.title"))); // NOI18N
|
fileReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.fileReferencesPanel.border.title"))); // NOI18N
|
||||||
fileReferencesPanel.setPreferredSize(new java.awt.Dimension(472, 300));
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 1;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
add(fileReferencesPanel, gridBagConstraints);
|
||||||
|
|
||||||
caseReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.caseReferencesPanel.border.title"))); // NOI18N
|
caseReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.caseReferencesPanel.border.title"))); // NOI18N
|
||||||
caseReferencesPanel.setPreferredSize(new java.awt.Dimension(472, 300));
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
gridBagConstraints.gridy = 2;
|
||||||
this.setLayout(layout);
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
layout.setHorizontalGroup(
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.weighty = 1.0;
|
||||||
.addContainerGap()
|
add(caseReferencesPanel, gridBagConstraints);
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(countsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addComponent(fileReferencesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
|
|
||||||
.addComponent(caseReferencesPanel, javax.swing.GroupLayout.Alignment.TRAILING, 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()
|
|
||||||
.addContainerGap()
|
|
||||||
.addComponent(countsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(fileReferencesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(caseReferencesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,9 +83,10 @@ MediaViewImagePanel.zoomResetButton.text=Reset
|
|||||||
MediaViewImagePanel.zoomTextField.text=
|
MediaViewImagePanel.zoomTextField.text=
|
||||||
MediaViewImagePanel.rotationTextField.text=
|
MediaViewImagePanel.rotationTextField.text=
|
||||||
MediaViewImagePanel.rotateLeftButton.toolTipText=
|
MediaViewImagePanel.rotateLeftButton.toolTipText=
|
||||||
HtmlPanel.showImagesToggleButton.text=Show Images
|
HtmlPanel.showImagesToggleButton.text=Download Images
|
||||||
MediaPlayerPanel.audioSlider.toolTipText=
|
MediaPlayerPanel.audioSlider.toolTipText=
|
||||||
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
|
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
|
||||||
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
|
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
|
||||||
MediaPlayerPanel.playButton.text=\u25ba
|
MediaPlayerPanel.playButton.text=\u25ba
|
||||||
MediaPlayerPanel.infoLabel.text=No Errors
|
MediaPlayerPanel.infoLabel.text=No Errors
|
||||||
|
MediaViewImagePanel.tagsMenu.text_1=Tags Menu
|
||||||
|
@ -22,7 +22,7 @@ GstVideoPanel.cannotProcFile.err=The media player cannot process this file.
|
|||||||
GstVideoPanel.noOpenCase.errMsg=No open case available.
|
GstVideoPanel.noOpenCase.errMsg=No open case available.
|
||||||
Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.
|
Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.
|
||||||
HtmlPanel_showImagesToggleButton_hide=Hide Images
|
HtmlPanel_showImagesToggleButton_hide=Hide Images
|
||||||
HtmlPanel_showImagesToggleButton_show=Show Images
|
HtmlPanel_showImagesToggleButton_show=Download Images
|
||||||
HtmlViewer_file_error=This file is missing or unreadable.
|
HtmlViewer_file_error=This file is missing or unreadable.
|
||||||
MediaFileViewer.initGst.gstException.msg=Error initializing gstreamer for audio/video viewing and frame extraction capabilities. Video and audio viewing will be disabled.
|
MediaFileViewer.initGst.gstException.msg=Error initializing gstreamer for audio/video viewing and frame extraction capabilities. Video and audio viewing will be disabled.
|
||||||
GstVideoPanel.setupVideo.infoLabel.text=Playback of deleted videos is not supported, use an external player.
|
GstVideoPanel.setupVideo.infoLabel.text=Playback of deleted videos is not supported, use an external player.
|
||||||
@ -44,7 +44,11 @@ MediaPlayerPanel.timeFormat=%02d:%02d:%02d
|
|||||||
MediaPlayerPanel.unknownTime=Unknown
|
MediaPlayerPanel.unknownTime=Unknown
|
||||||
MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory.
|
MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory.
|
||||||
MediaViewImagePanel.errorLabel.text=Could not load file into Media View.
|
MediaViewImagePanel.errorLabel.text=Could not load file into Media View.
|
||||||
|
MediaViewImagePanel.exportSaveText=Save
|
||||||
MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E
|
MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E
|
||||||
|
MediaViewImagePanel.fileChooserTitle=Choose a save location
|
||||||
|
MediaViewImagePanel.successfulExport=Tagged image was successfully saved.
|
||||||
|
MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk.
|
||||||
MediaViewVideoPanel.pauseButton.text=\u25ba
|
MediaViewVideoPanel.pauseButton.text=\u25ba
|
||||||
MediaViewVideoPanel.progressLabel.text=00:00
|
MediaViewVideoPanel.progressLabel.text=00:00
|
||||||
MediaViewVideoPanel.infoLabel.text=info
|
MediaViewVideoPanel.infoLabel.text=info
|
||||||
@ -145,12 +149,13 @@ MediaViewImagePanel.zoomResetButton.text=Reset
|
|||||||
MediaViewImagePanel.zoomTextField.text=
|
MediaViewImagePanel.zoomTextField.text=
|
||||||
MediaViewImagePanel.rotationTextField.text=
|
MediaViewImagePanel.rotationTextField.text=
|
||||||
MediaViewImagePanel.rotateLeftButton.toolTipText=
|
MediaViewImagePanel.rotateLeftButton.toolTipText=
|
||||||
HtmlPanel.showImagesToggleButton.text=Show Images
|
HtmlPanel.showImagesToggleButton.text=Download Images
|
||||||
MediaPlayerPanel.audioSlider.toolTipText=
|
MediaPlayerPanel.audioSlider.toolTipText=
|
||||||
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
|
MediaPlayerPanel.VolumeIcon.text=\ Volume
|
||||||
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
|
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
|
||||||
MediaPlayerPanel.playButton.text=\u25ba
|
MediaPlayerPanel.playButton.text=\u25ba
|
||||||
MediaPlayerPanel.infoLabel.text=No Errors
|
MediaPlayerPanel.infoLabel.text=No Errors
|
||||||
|
MediaViewImagePanel.tagsMenu.text_1=Tags Menu
|
||||||
# {0} - tableName
|
# {0} - tableName
|
||||||
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
|
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
|
||||||
# {0} - tableName
|
# {0} - tableName
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
|
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="0" pref="95" max="32767" attributes="0"/>
|
<EmptySpace min="0" pref="75" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Component id="htmlJPanel" max="32767" attributes="0"/>
|
<Component id="htmlJPanel" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.contentviewers;
|
package org.sleuthkit.autopsy.contentviewers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
@ -25,8 +30,9 @@ import javafx.concurrent.Worker;
|
|||||||
import javafx.scene.web.WebView;
|
import javafx.scene.web.WebView;
|
||||||
import javafx.embed.swing.JFXPanel;
|
import javafx.embed.swing.JFXPanel;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import org.jsoup.Jsoup;
|
import net.htmlparser.jericho.Attribute;
|
||||||
import org.jsoup.nodes.Node;
|
import net.htmlparser.jericho.OutputDocument;
|
||||||
|
import net.htmlparser.jericho.Source;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
@ -38,6 +44,7 @@ import org.w3c.dom.events.EventTarget;
|
|||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
final class HtmlPanel extends javax.swing.JPanel {
|
final class HtmlPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(HtmlPanel.class.getName());
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final String TEXT_TYPE = "text/plain";
|
private static final String TEXT_TYPE = "text/plain";
|
||||||
private final JFXPanel jfxPanel = new JFXPanel();
|
private final JFXPanel jfxPanel = new JFXPanel();
|
||||||
@ -92,26 +99,76 @@ final class HtmlPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans out input HTML string
|
* Cleans out input HTML string so it will not access resources over the internet
|
||||||
*
|
*
|
||||||
* @param htmlInString The HTML string to cleanse
|
* @param htmlInString The HTML string to cleanse
|
||||||
*
|
*
|
||||||
* @return The cleansed HTML String
|
* @return The cleansed HTML String
|
||||||
*/
|
*/
|
||||||
private String cleanseHTML(String htmlInString) {
|
private String cleanseHTML(String htmlInString) {
|
||||||
org.jsoup.nodes.Document doc = Jsoup.parse(htmlInString);
|
String returnString = "";
|
||||||
// remove all 'img' tags.
|
try {
|
||||||
doc.select("img").stream().forEach(Node::remove);
|
Source source = new Source(new StringReader(htmlInString));
|
||||||
// remove all 'span' tags, these are often images which are ads
|
OutputDocument document = new OutputDocument(source);
|
||||||
doc.select("span").stream().forEach(Node::remove);
|
//remove background images
|
||||||
return doc.html();
|
source.getAllTags().stream().filter((tag) -> (tag.toString().contains("background-image"))).forEachOrdered((tag) -> {
|
||||||
|
document.remove(tag);
|
||||||
|
});
|
||||||
|
//remove images
|
||||||
|
source.getAllElements("img").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove frames
|
||||||
|
source.getAllElements("frame").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove iframes
|
||||||
|
source.getAllElements("iframe").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove pictures
|
||||||
|
source.getAllElements("picture").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove svg
|
||||||
|
source.getAllElements("svg").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove audio
|
||||||
|
source.getAllElements("audio").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove video
|
||||||
|
source.getAllElements("video").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove tracks
|
||||||
|
source.getAllElements("track").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove embeded external elements
|
||||||
|
source.getAllElements("embed").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove linked elements
|
||||||
|
source.getAllElements("link").forEach((element) -> {
|
||||||
|
document.remove(element.getAllTags());
|
||||||
|
});
|
||||||
|
//remove other URI elements such as input boxes
|
||||||
|
List<Attribute> attributesToRemove = source.getURIAttributes();
|
||||||
|
document.remove(attributesToRemove);
|
||||||
|
returnString = document.toString();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Unable to read html for cleaning out URI elements with Jericho", ex);
|
||||||
|
}
|
||||||
|
return returnString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the panel to reflect the current show/hide images setting.
|
* Refresh the panel to reflect the current show/hide images setting.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
"HtmlPanel_showImagesToggleButton_show=Show Images",
|
"HtmlPanel_showImagesToggleButton_show=Download Images",
|
||||||
"HtmlPanel_showImagesToggleButton_hide=Hide Images",
|
"HtmlPanel_showImagesToggleButton_hide=Hide Images",
|
||||||
"Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.",})
|
"Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.",})
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
@ -164,7 +221,7 @@ final class HtmlPanel extends javax.swing.JPanel {
|
|||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addComponent(showImagesToggleButton)
|
.addComponent(showImagesToggleButton)
|
||||||
.addGap(0, 95, Short.MAX_VALUE))
|
.addGap(0, 75, Short.MAX_VALUE))
|
||||||
.addComponent(htmlJPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(htmlJPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
|
@ -11,30 +11,8 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="htmlPanel" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="htmlPanel" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
|
||||||
<Component class="org.sleuthkit.autopsy.contentviewers.HtmlPanel" name="htmlPanel">
|
|
||||||
</Component>
|
|
||||||
</SubComponents>
|
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -37,17 +37,18 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName());
|
private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName());
|
||||||
|
|
||||||
private static final String[] SUPPORTED_MIMETYPES = new String[]{
|
private static final String[] SUPPORTED_MIMETYPES = new String[]{
|
||||||
"text/html",
|
"text/html",
|
||||||
"application/xhtml+xml"
|
"application/xhtml+xml"
|
||||||
};
|
};
|
||||||
|
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form HtmlViewerPanel
|
* Creates new form HtmlViewerPanel
|
||||||
*/
|
*/
|
||||||
HtmlViewer() {
|
HtmlViewer() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
this.add(htmlPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,31 +82,12 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
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()
|
|
||||||
.addComponent(htmlPanel, 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()
|
|
||||||
.addContainerGap()
|
|
||||||
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
|
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getSupportedMIMETypes() {
|
public List<String> getSupportedMIMETypes() {
|
||||||
return Arrays.asList(SUPPORTED_MIMETYPES);
|
return Arrays.asList(SUPPORTED_MIMETYPES);
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,100,0,0,3,117"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||||
@ -200,6 +200,44 @@
|
|||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="zoomResetButtonActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="zoomResetButtonActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.Box$Filler" name="filler1">
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.Box$Filler" name="filler2">
|
||||||
|
<Properties>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[32767, 0]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalGlue"/>
|
||||||
|
</AuxValues>
|
||||||
|
</Component>
|
||||||
|
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||||
|
</Container>
|
||||||
|
<Component class="javax.swing.JButton" name="tagsMenu">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaViewImagePanel.tagsMenu.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
|
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[75, 21]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[75, 21]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[75, 21]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="tagsMenuMousePressed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
@ -20,18 +20,31 @@ package org.sleuthkit.autopsy.contentviewers;
|
|||||||
|
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyChangeSupport;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.ListChangeListener.Change;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.embed.swing.JFXPanel;
|
import javafx.embed.swing.JFXPanel;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.geometry.Rectangle2D;
|
import javafx.geometry.Rectangle2D;
|
||||||
import javafx.scene.Cursor;
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.Group;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@ -45,19 +58,39 @@ import javafx.scene.transform.Rotate;
|
|||||||
import javafx.scene.transform.Scale;
|
import javafx.scene.transform.Scale;
|
||||||
import javafx.scene.transform.Translate;
|
import javafx.scene.transform.Translate;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JSeparator;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.controlsfx.control.MaskerPane;
|
import org.controlsfx.control.MaskerPane;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.python.google.common.collect.Lists;
|
import org.python.google.common.collect.Lists;
|
||||||
import javafx.scene.Group;
|
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog;
|
||||||
import javafx.scene.input.MouseEvent;
|
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog.TagNameAndComment;
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.shape.Rectangle;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.SerializationException;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtility;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTag;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsGroup;
|
||||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image viewer part of the Media View layered pane. Uses JavaFX to display the
|
* Image viewer part of the Media View layered pane. Uses JavaFX to display the
|
||||||
@ -70,17 +103,30 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPanel {
|
class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPanel {
|
||||||
|
|
||||||
private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
|
private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
|
||||||
|
private final static Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName());
|
||||||
|
|
||||||
private final boolean fxInited;
|
private final boolean fxInited;
|
||||||
|
|
||||||
private JFXPanel fxPanel;
|
private JFXPanel fxPanel;
|
||||||
private Group imageGroup;
|
private AbstractFile file;
|
||||||
private ImageTaggingTool tagger;
|
private Group masterGroup;
|
||||||
|
private ImageTagsGroup tagsGroup;
|
||||||
|
private ImageTagCreator imageTagCreator;
|
||||||
private ImageView fxImageView;
|
private ImageView fxImageView;
|
||||||
private ScrollPane scrollPane;
|
private ScrollPane scrollPane;
|
||||||
private final ProgressBar progressBar = new ProgressBar();
|
private final ProgressBar progressBar = new ProgressBar();
|
||||||
private final MaskerPane maskerPane = new MaskerPane();
|
private final MaskerPane maskerPane = new MaskerPane();
|
||||||
|
|
||||||
|
private final JPopupMenu popupMenu = new JPopupMenu();
|
||||||
|
private final JMenuItem createTagMenuItem;
|
||||||
|
private final JMenuItem deleteTagMenuItem;
|
||||||
|
private final JMenuItem hideTagsMenuItem;
|
||||||
|
private final JMenuItem exportTagsMenuItem;
|
||||||
|
|
||||||
|
private final JFileChooser exportChooser;
|
||||||
|
|
||||||
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||||
|
|
||||||
private double zoomRatio;
|
private double zoomRatio;
|
||||||
private double rotation; // Can be 0, 90, 180, and 270.
|
private double rotation; // Can be 0, 90, 180, and 270.
|
||||||
|
|
||||||
@ -116,33 +162,163 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
public MediaViewImagePanel() {
|
public MediaViewImagePanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited();
|
fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited();
|
||||||
|
|
||||||
|
exportChooser = new JFileChooser();
|
||||||
|
exportChooser.setDialogTitle(Bundle.MediaViewImagePanel_fileChooserTitle());
|
||||||
|
|
||||||
|
//Build popupMenu when Tags Menu button is pressed.
|
||||||
|
createTagMenuItem = new JMenuItem("Create");
|
||||||
|
createTagMenuItem.addActionListener((event) -> createTag());
|
||||||
|
popupMenu.add(createTagMenuItem);
|
||||||
|
|
||||||
|
popupMenu.add(new JSeparator());
|
||||||
|
|
||||||
|
deleteTagMenuItem = new JMenuItem("Delete");
|
||||||
|
deleteTagMenuItem.addActionListener((event) -> deleteTag());
|
||||||
|
popupMenu.add(deleteTagMenuItem);
|
||||||
|
|
||||||
|
popupMenu.add(new JSeparator());
|
||||||
|
|
||||||
|
hideTagsMenuItem = new JMenuItem("Hide");
|
||||||
|
hideTagsMenuItem.addActionListener((event) -> showOrHideTags());
|
||||||
|
popupMenu.add(hideTagsMenuItem);
|
||||||
|
|
||||||
|
popupMenu.add(new JSeparator());
|
||||||
|
|
||||||
|
exportTagsMenuItem = new JMenuItem("Export");
|
||||||
|
exportTagsMenuItem.addActionListener((event) -> exportTags());
|
||||||
|
popupMenu.add(exportTagsMenuItem);
|
||||||
|
|
||||||
|
popupMenu.setPopupSize(300, 150);
|
||||||
|
|
||||||
if (fxInited) {
|
if (fxInited) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// build jfx ui (we could do this in FXML?)
|
||||||
|
fxImageView = new ImageView(); // will hold image
|
||||||
|
masterGroup = new Group(fxImageView);
|
||||||
|
tagsGroup = new ImageTagsGroup(fxImageView);
|
||||||
|
tagsGroup.getChildren().addListener((Change<? extends Node> c) -> {
|
||||||
|
if (c.getList().isEmpty()) {
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.EMPTY));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// build jfx ui (we could do this in FXML?)
|
subscribeTagMenuItemsToStateChanges();
|
||||||
fxImageView = new ImageView(); // will hold image
|
|
||||||
imageGroup = new Group();
|
|
||||||
imageGroup.getChildren().add(fxImageView);
|
|
||||||
scrollPane = new ScrollPane(imageGroup); // scrolls and sizes imageview
|
|
||||||
scrollPane.getStyleClass().add("bg"); //NOI18N
|
|
||||||
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
|
||||||
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
|
||||||
|
|
||||||
fxPanel = new JFXPanel(); // bridge jfx-swing
|
masterGroup.getChildren().add(tagsGroup);
|
||||||
Scene scene = new Scene(scrollPane); //root of jfx tree
|
|
||||||
scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
|
|
||||||
fxPanel.setScene(scene);
|
|
||||||
|
|
||||||
fxImageView.setSmooth(true);
|
//Update buttons when users select (or unselect) image tags.
|
||||||
fxImageView.setCache(true);
|
tagsGroup.addFocusChangeListener((event) -> {
|
||||||
|
if (event.getPropertyName().equals(ImageTagControls.NOT_FOCUSED.getName())) {
|
||||||
|
if (masterGroup.getChildren().contains(imageTagCreator)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EventQueue.invokeLater(() -> {
|
if (tagsGroup.getChildren().isEmpty()) {
|
||||||
add(fxPanel);//add jfx ui to JPanel
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
});
|
"state", null, State.EMPTY));
|
||||||
|
} else {
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.CREATE));
|
||||||
|
}
|
||||||
|
} else if (event.getPropertyName().equals(ImageTagControls.FOCUSED.getName())) {
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.SELECTED));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scrollPane = new ScrollPane(masterGroup); // scrolls and sizes imageview
|
||||||
|
scrollPane.getStyleClass().add("bg"); //NOI18N
|
||||||
|
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||||
|
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||||
|
|
||||||
|
fxPanel = new JFXPanel(); // bridge jfx-swing
|
||||||
|
Scene scene = new Scene(scrollPane); //root of jfx tree
|
||||||
|
scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
|
||||||
|
fxPanel.setScene(scene);
|
||||||
|
|
||||||
|
fxImageView.setSmooth(true);
|
||||||
|
fxImageView.setCache(true);
|
||||||
|
|
||||||
|
EventQueue.invokeLater(() -> {
|
||||||
|
add(fxPanel);//add jfx ui to JPanel
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle tags menu item enabling and disabling given the state of the
|
||||||
|
* content viewer. For example, when the tags group is empty (no tags on image),
|
||||||
|
* disable delete menu item, hide menu item, and export menu item.
|
||||||
|
*/
|
||||||
|
private void subscribeTagMenuItemsToStateChanges() {
|
||||||
|
pcs.addPropertyChangeListener((event) -> {
|
||||||
|
State currentState = (State) event.getNewValue();
|
||||||
|
switch (currentState) {
|
||||||
|
case CREATE:
|
||||||
|
createTagMenuItem.setEnabled(true);
|
||||||
|
deleteTagMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setEnabled(true);
|
||||||
|
exportTagsMenuItem.setEnabled(true);
|
||||||
|
break;
|
||||||
|
case SELECTED:
|
||||||
|
if (masterGroup.getChildren().contains(imageTagCreator)) {
|
||||||
|
imageTagCreator.disconnect();
|
||||||
|
masterGroup.getChildren().remove(imageTagCreator);
|
||||||
|
}
|
||||||
|
createTagMenuItem.setEnabled(false);
|
||||||
|
deleteTagMenuItem.setEnabled(true);
|
||||||
|
hideTagsMenuItem.setEnabled(true);
|
||||||
|
exportTagsMenuItem.setEnabled(true);
|
||||||
|
break;
|
||||||
|
case HIDDEN:
|
||||||
|
createTagMenuItem.setEnabled(false);
|
||||||
|
deleteTagMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setEnabled(true);
|
||||||
|
hideTagsMenuItem.setText(DisplayOptions.SHOW_TAGS.getName());
|
||||||
|
exportTagsMenuItem.setEnabled(false);
|
||||||
|
break;
|
||||||
|
case VISIBLE:
|
||||||
|
createTagMenuItem.setEnabled(true);
|
||||||
|
deleteTagMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setEnabled(true);
|
||||||
|
hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName());
|
||||||
|
exportTagsMenuItem.setEnabled(true);
|
||||||
|
break;
|
||||||
|
case DEFAULT:
|
||||||
|
case EMPTY:
|
||||||
|
if (masterGroup.getChildren().contains(imageTagCreator)) {
|
||||||
|
imageTagCreator.disconnect();
|
||||||
|
}
|
||||||
|
createTagMenuItem.setEnabled(true);
|
||||||
|
deleteTagMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName());
|
||||||
|
exportTagsMenuItem.setEnabled(false);
|
||||||
|
break;
|
||||||
|
case NONEMPTY:
|
||||||
|
createTagMenuItem.setEnabled(true);
|
||||||
|
deleteTagMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setEnabled(true);
|
||||||
|
exportTagsMenuItem.setEnabled(true);
|
||||||
|
break;
|
||||||
|
case DISABLE:
|
||||||
|
createTagMenuItem.setEnabled(false);
|
||||||
|
deleteTagMenuItem.setEnabled(false);
|
||||||
|
hideTagsMenuItem.setEnabled(false);
|
||||||
|
exportTagsMenuItem.setEnabled(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isInited() {
|
public boolean isInited() {
|
||||||
return fxInited;
|
return fxInited;
|
||||||
}
|
}
|
||||||
@ -154,10 +330,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
|
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
|
||||||
fxImageView.setImage(null);
|
fxImageView.setImage(null);
|
||||||
tagger.defaultSettings();
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.DEFAULT));
|
||||||
|
masterGroup.getChildren().clear();
|
||||||
scrollPane.setContent(null);
|
scrollPane.setContent(null);
|
||||||
scrollPane.setContent(imageGroup);
|
scrollPane.setContent(masterGroup);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,14 +382,31 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Image fxImage = readImageTask.get();
|
Image fxImage = readImageTask.get();
|
||||||
|
masterGroup.getChildren().clear();
|
||||||
|
tagsGroup.getChildren().clear();
|
||||||
|
this.file = file;
|
||||||
if (nonNull(fxImage)) {
|
if (nonNull(fxImage)) {
|
||||||
// We have a non-null image, so let's show it.
|
// We have a non-null image, so let's show it.
|
||||||
fxImageView.setImage(fxImage);
|
fxImageView.setImage(fxImage);
|
||||||
imageGroup.getChildren().remove(tagger);
|
|
||||||
tagger = new ImageTaggingTool(fxImageView, Color.RED);
|
|
||||||
imageGroup.getChildren().add(tagger);
|
|
||||||
resetView();
|
resetView();
|
||||||
scrollPane.setContent(imageGroup);
|
masterGroup.getChildren().add(fxImageView);
|
||||||
|
masterGroup.getChildren().add(tagsGroup);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<ContentTag> tags = Case.getCurrentCase().getServices()
|
||||||
|
.getTagsManager().getContentTagsByContent(file);
|
||||||
|
|
||||||
|
List<ContentViewerTag<ImageTagRegion>> contentViewerTags = getContentViewerTags(tags);
|
||||||
|
//Add all image tags
|
||||||
|
tagsGroup = buildImageTagsGroup(contentViewerTags);
|
||||||
|
if (!tagsGroup.getChildren().isEmpty()) {
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.NONEMPTY));
|
||||||
|
}
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
scrollPane.setContent(masterGroup);
|
||||||
} else {
|
} else {
|
||||||
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
|
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
|
||||||
}
|
}
|
||||||
@ -252,6 +446,52 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all ContentViewerTags that are of type 'ImageTagRegion' for the
|
||||||
|
* current file.
|
||||||
|
*
|
||||||
|
* @param contentTags
|
||||||
|
* @return
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws NoCurrentCaseException
|
||||||
|
*/
|
||||||
|
private List<ContentViewerTag<ImageTagRegion>> getContentViewerTags(List<ContentTag> contentTags)
|
||||||
|
throws TskCoreException, NoCurrentCaseException {
|
||||||
|
List<ContentViewerTag<ImageTagRegion>> contentViewerTags = new ArrayList<>();
|
||||||
|
for (ContentTag contentTag : contentTags) {
|
||||||
|
ContentViewerTag<ImageTagRegion> contentViewerTag = ContentViewerTagManager
|
||||||
|
.getTag(contentTag, ImageTagRegion.class);
|
||||||
|
if (contentViewerTag == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
contentViewerTags.add(contentViewerTag);
|
||||||
|
}
|
||||||
|
return contentViewerTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds ImageTag instances from stored ContentViewerTags of the
|
||||||
|
* appropriate type.
|
||||||
|
*
|
||||||
|
* @param contentTags
|
||||||
|
* @return
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws NoCurrentCaseException
|
||||||
|
*/
|
||||||
|
private ImageTagsGroup buildImageTagsGroup(List<ContentViewerTag<ImageTagRegion>> contentViewerTags) {
|
||||||
|
|
||||||
|
contentViewerTags.forEach(contentViewerTag -> {
|
||||||
|
/**
|
||||||
|
* Build the image tag, add an edit event call back to persist all
|
||||||
|
* edits made on this image tag instance.
|
||||||
|
*/
|
||||||
|
tagsGroup.getChildren().add(buildImageTag(contentViewerTag));
|
||||||
|
});
|
||||||
|
|
||||||
|
return tagsGroup;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return supported mime types
|
* @return supported mime types
|
||||||
*/
|
*/
|
||||||
@ -303,6 +543,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
zoomInButton = new javax.swing.JButton();
|
zoomInButton = new javax.swing.JButton();
|
||||||
jSeparator2 = new javax.swing.JToolBar.Separator();
|
jSeparator2 = new javax.swing.JToolBar.Separator();
|
||||||
zoomResetButton = new javax.swing.JButton();
|
zoomResetButton = new javax.swing.JButton();
|
||||||
|
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0));
|
||||||
|
filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
|
||||||
|
jPanel1 = new javax.swing.JPanel();
|
||||||
|
tagsMenu = new javax.swing.JButton();
|
||||||
|
|
||||||
setBackground(new java.awt.Color(0, 0, 0));
|
setBackground(new java.awt.Color(0, 0, 0));
|
||||||
addComponentListener(new java.awt.event.ComponentAdapter() {
|
addComponentListener(new java.awt.event.ComponentAdapter() {
|
||||||
@ -406,6 +650,23 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
toolbar.add(zoomResetButton);
|
toolbar.add(zoomResetButton);
|
||||||
|
toolbar.add(filler1);
|
||||||
|
toolbar.add(filler2);
|
||||||
|
toolbar.add(jPanel1);
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(tagsMenu, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.tagsMenu.text_1")); // NOI18N
|
||||||
|
tagsMenu.setFocusable(false);
|
||||||
|
tagsMenu.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
|
tagsMenu.setMaximumSize(new java.awt.Dimension(75, 21));
|
||||||
|
tagsMenu.setMinimumSize(new java.awt.Dimension(75, 21));
|
||||||
|
tagsMenu.setPreferredSize(new java.awt.Dimension(75, 21));
|
||||||
|
tagsMenu.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||||
|
tagsMenu.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||||
|
public void mousePressed(java.awt.event.MouseEvent evt) {
|
||||||
|
tagsMenuMousePressed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toolbar.add(tagsMenu);
|
||||||
|
|
||||||
add(toolbar);
|
add(toolbar);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
@ -450,12 +711,234 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
updateView();
|
updateView();
|
||||||
}//GEN-LAST:event_formComponentResized
|
}//GEN-LAST:event_formComponentResized
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the selected tag when the Delete button is pressed in the Tag
|
||||||
|
* Menu.
|
||||||
|
*/
|
||||||
|
private void deleteTag() {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
ImageTag tagInFocus = tagsGroup.getFocus();
|
||||||
|
if (tagInFocus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ContentViewerTag<ImageTagRegion> contentViewerTag = tagInFocus.getContentViewerTag();
|
||||||
|
scrollPane.setCursor(Cursor.WAIT);
|
||||||
|
ContentViewerTagManager.deleteTag(contentViewerTag);
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(contentViewerTag.getContentTag());
|
||||||
|
tagsGroup.getChildren().remove(tagInFocus);
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not delete image tag in case db", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollPane.setCursor(Cursor.DEFAULT);
|
||||||
|
});
|
||||||
|
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.CREATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables create tag logic when the Create button is pressed in the Tags
|
||||||
|
* Menu.
|
||||||
|
*/
|
||||||
|
private void createTag() {
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.DISABLE));
|
||||||
|
imageTagCreator = new ImageTagCreator(fxImageView);
|
||||||
|
|
||||||
|
PropertyChangeListener newTagListener = (event) -> {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
ImageTagRegion tag = (ImageTagRegion) event.getNewValue();
|
||||||
|
//Ask the user for tag name and comment
|
||||||
|
TagNameAndComment result = GetTagNameAndCommentDialog.doDialog();
|
||||||
|
if (result != null) {
|
||||||
|
//Persist and build image tag
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
|
scrollPane.setCursor(Cursor.WAIT);
|
||||||
|
ContentViewerTag<ImageTagRegion> contentViewerTag = storeImageTag(tag, result);
|
||||||
|
ImageTag imageTag = buildImageTag(contentViewerTag);
|
||||||
|
tagsGroup.getChildren().add(imageTag);
|
||||||
|
} catch (TskCoreException | SerializationException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollPane.setCursor(Cursor.DEFAULT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.CREATE));
|
||||||
|
});
|
||||||
|
|
||||||
|
//Remove image tag creator from panel
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
imageTagCreator.disconnect();
|
||||||
|
masterGroup.getChildren().remove(imageTagCreator);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
imageTagCreator.addNewTagListener(newTagListener);
|
||||||
|
Platform.runLater(() -> masterGroup.getChildren().add(imageTagCreator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ImageTag instance from the ContentViewerTag.
|
||||||
|
*
|
||||||
|
* @param contentViewerTag
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ImageTag buildImageTag(ContentViewerTag<ImageTagRegion> contentViewerTag) {
|
||||||
|
ImageTag imageTag = new ImageTag(contentViewerTag, fxImageView);
|
||||||
|
|
||||||
|
//Automatically persist edits made by user
|
||||||
|
imageTag.subscribeToEditEvents((edit) -> {
|
||||||
|
try {
|
||||||
|
scrollPane.setCursor(Cursor.WAIT);
|
||||||
|
ImageTagRegion newRegion = (ImageTagRegion) edit.getNewValue();
|
||||||
|
ContentViewerTagManager.updateTag(contentViewerTag, newRegion);
|
||||||
|
} catch (SerializationException | TskCoreException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
scrollPane.setCursor(Cursor.DEFAULT);
|
||||||
|
});
|
||||||
|
return imageTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the image tag by creating a ContentTag instance and associating
|
||||||
|
* the ImageTagRegion data with it in the case database.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param result
|
||||||
|
*/
|
||||||
|
private ContentViewerTag<ImageTagRegion> storeImageTag(ImageTagRegion data, TagNameAndComment result)
|
||||||
|
throws TskCoreException, SerializationException, NoCurrentCaseException {
|
||||||
|
scrollPane.setCursor(Cursor.WAIT);
|
||||||
|
try {
|
||||||
|
ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager()
|
||||||
|
.addContentTag(file, result.getTagName(), result.getComment());
|
||||||
|
return ContentViewerTagManager.saveTag(contentTag, data);
|
||||||
|
} finally {
|
||||||
|
scrollPane.setCursor(Cursor.DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides or show tags when the Hide or Show button is pressed in the Tags
|
||||||
|
* Menu.
|
||||||
|
*/
|
||||||
|
private void showOrHideTags() {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (DisplayOptions.HIDE_TAGS.getName().equals(hideTagsMenuItem.getText())) {
|
||||||
|
//Temporarily remove the tags group and update buttons
|
||||||
|
masterGroup.getChildren().remove(tagsGroup);
|
||||||
|
hideTagsMenuItem.setText(DisplayOptions.SHOW_TAGS.getName());
|
||||||
|
tagsGroup.clearFocus();
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.HIDDEN));
|
||||||
|
} else {
|
||||||
|
//Add tags group back in and update buttons
|
||||||
|
masterGroup.getChildren().add(tagsGroup);
|
||||||
|
hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName());
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
"state", null, State.VISIBLE));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"MediaViewImagePanel.exportSaveText=Save",
|
||||||
|
"MediaViewImagePanel.successfulExport=Tagged image was successfully saved.",
|
||||||
|
"MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk.",
|
||||||
|
"MediaViewImagePanel.fileChooserTitle=Choose a save location"
|
||||||
|
})
|
||||||
|
private void exportTags() {
|
||||||
|
tagsGroup.clearFocus();
|
||||||
|
exportChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||||
|
//Always base chooser location to export folder
|
||||||
|
exportChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
|
||||||
|
int returnVal = exportChooser.showDialog(this, Bundle.MediaViewImagePanel_exportSaveText());
|
||||||
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||||
|
new SwingWorker<Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground() {
|
||||||
|
try {
|
||||||
|
//Retrieve content viewer tags
|
||||||
|
List<ContentTag> tags = Case.getCurrentCase().getServices()
|
||||||
|
.getTagsManager().getContentTagsByContent(file);
|
||||||
|
List<ContentViewerTag<ImageTagRegion>> contentViewerTags = getContentViewerTags(tags);
|
||||||
|
|
||||||
|
//Pull out image tag regions
|
||||||
|
Collection<ImageTagRegion> regions = contentViewerTags.stream()
|
||||||
|
.map(cvTag -> cvTag.getDetails()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
//Apply tags to image and write to file
|
||||||
|
BufferedImage pngImage = ImageTagsUtility.writeTags(file, regions, "png");
|
||||||
|
Path output = Paths.get(exportChooser.getSelectedFile().getPath(),
|
||||||
|
FilenameUtils.getBaseName(file.getName()) + "-with_tags.png"); //NON-NLS
|
||||||
|
ImageIO.write(pngImage, "png", output.toFile());
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport());
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException | IOException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS
|
||||||
|
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tagsMenuMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagsMenuMousePressed
|
||||||
|
popupMenu.show(tagsMenu, -300 + tagsMenu.getWidth(), tagsMenu.getHeight() + 3);
|
||||||
|
}//GEN-LAST:event_tagsMenuMousePressed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display states for the show/hide tags button.
|
||||||
|
*/
|
||||||
|
enum DisplayOptions {
|
||||||
|
HIDE_TAGS("Hide"),
|
||||||
|
SHOW_TAGS("Show");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
DisplayOptions(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Different states that the content viewer can be in. These states drive
|
||||||
|
* which buttons are enabled for tagging.
|
||||||
|
*/
|
||||||
|
enum State {
|
||||||
|
HIDDEN,
|
||||||
|
VISIBLE,
|
||||||
|
SELECTED,
|
||||||
|
CREATE,
|
||||||
|
EMPTY,
|
||||||
|
NONEMPTY,
|
||||||
|
DEFAULT,
|
||||||
|
DISABLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.Box.Filler filler1;
|
||||||
|
private javax.swing.Box.Filler filler2;
|
||||||
|
private javax.swing.JPanel jPanel1;
|
||||||
private javax.swing.JToolBar.Separator jSeparator1;
|
private javax.swing.JToolBar.Separator jSeparator1;
|
||||||
private javax.swing.JToolBar.Separator jSeparator2;
|
private javax.swing.JToolBar.Separator jSeparator2;
|
||||||
private javax.swing.JButton rotateLeftButton;
|
private javax.swing.JButton rotateLeftButton;
|
||||||
private javax.swing.JButton rotateRightButton;
|
private javax.swing.JButton rotateRightButton;
|
||||||
private javax.swing.JTextField rotationTextField;
|
private javax.swing.JTextField rotationTextField;
|
||||||
|
private javax.swing.JButton tagsMenu;
|
||||||
private javax.swing.JToolBar toolbar;
|
private javax.swing.JToolBar toolbar;
|
||||||
private javax.swing.JButton zoomInButton;
|
private javax.swing.JButton zoomInButton;
|
||||||
private javax.swing.JButton zoomOutButton;
|
private javax.swing.JButton zoomOutButton;
|
||||||
@ -601,8 +1084,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
// Add the transforms in reverse order of intended execution.
|
// Add the transforms in reverse order of intended execution.
|
||||||
// Note: They MUST be added in this order to ensure translate is
|
// Note: They MUST be added in this order to ensure translate is
|
||||||
// executed last.
|
// executed last.
|
||||||
imageGroup.getTransforms().clear();
|
masterGroup.getTransforms().clear();
|
||||||
imageGroup.getTransforms().addAll(translate, rotate, scale);
|
masterGroup.getTransforms().addAll(translate, rotate, scale);
|
||||||
|
|
||||||
// Adjust scroll bar positions for view changes.
|
// Adjust scroll bar positions for view changes.
|
||||||
if (viewportWidth > fxPanel.getWidth()) {
|
if (viewportWidth > fxPanel.getWidth()) {
|
||||||
@ -618,107 +1101,4 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
rotationTextField.setText((int) rotation + "°");
|
rotationTextField.setText((int) rotation + "°");
|
||||||
zoomTextField.setText((Math.round(zoomRatio * 100.0)) + "%");
|
zoomTextField.setText((Math.round(zoomRatio * 100.0)) + "%");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables users to 'tag' a region of an image by clicking and dragging a
|
|
||||||
* rectangle overtop.
|
|
||||||
*/
|
|
||||||
class ImageTaggingTool extends Rectangle {
|
|
||||||
|
|
||||||
private final double imageWidth;
|
|
||||||
private final double imageHeight;
|
|
||||||
private final double imageOriginX;
|
|
||||||
private final double imageOriginY;
|
|
||||||
|
|
||||||
//Origin of the drag event.
|
|
||||||
private double rectangleOriginX;
|
|
||||||
private double rectangleOriginY;
|
|
||||||
|
|
||||||
//Rectangle lines should be 1.5% of the image. This level of thickness has
|
|
||||||
//a good balance between visual acuity and loss of selection at the borders
|
|
||||||
//of the image.
|
|
||||||
private double lineThicknessAsPercent = 1.5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds tagging support to an image, where the 'tag' rectangle will be
|
|
||||||
* the specified color.
|
|
||||||
*
|
|
||||||
* @param image Image to tag
|
|
||||||
* @param color Color of the 'tag' rectangle
|
|
||||||
*/
|
|
||||||
private ImageTaggingTool(ImageView image, Color color) {
|
|
||||||
defaultSettings();
|
|
||||||
|
|
||||||
imageWidth = image.getImage().getWidth();
|
|
||||||
imageHeight = image.getImage().getHeight();
|
|
||||||
imageOriginX = image.getX();
|
|
||||||
imageOriginY = image.getY();
|
|
||||||
|
|
||||||
setStroke(color);
|
|
||||||
setFill(color.deriveColor(0, 0, 0, 0));
|
|
||||||
|
|
||||||
//Calculate how many pixels the stroke width should be to guarentee
|
|
||||||
//a consistent % of image consumed by the rectangle border.
|
|
||||||
double min = Math.min(imageWidth, imageHeight);
|
|
||||||
double lineThicknessPixels = min * lineThicknessAsPercent / 100.0;
|
|
||||||
setStrokeWidth(lineThicknessPixels);
|
|
||||||
setVisible(false);
|
|
||||||
|
|
||||||
//Create a rectangle by left clicking on the image
|
|
||||||
image.setOnMousePressed((MouseEvent event) -> {
|
|
||||||
if (event.isSecondaryButtonDown()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Reset box on new click.
|
|
||||||
defaultSettings();
|
|
||||||
|
|
||||||
rectangleOriginX = event.getX();
|
|
||||||
rectangleOriginY = event.getY();
|
|
||||||
|
|
||||||
setX(rectangleOriginX);
|
|
||||||
setY(rectangleOriginY);
|
|
||||||
});
|
|
||||||
|
|
||||||
//Adjust the rectangle by dragging the left mouse button
|
|
||||||
image.setOnMouseDragged((MouseEvent event) -> {
|
|
||||||
if (event.isSecondaryButtonDown()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure the rectangle is contained within image boundaries and
|
|
||||||
* that the line thickness is kept within bounds.
|
|
||||||
*/
|
|
||||||
double newX = Math.min(Math.max(event.getX(), imageOriginX)
|
|
||||||
+ lineThicknessPixels / 2, imageWidth - lineThicknessPixels / 2);
|
|
||||||
double newY = Math.min(Math.max(event.getY(), imageOriginY)
|
|
||||||
+ lineThicknessPixels / 2, imageHeight - lineThicknessPixels / 2);
|
|
||||||
|
|
||||||
setVisible(true);
|
|
||||||
double offsetX = newX - rectangleOriginX;
|
|
||||||
if (offsetX < 0) {
|
|
||||||
setX(newX);
|
|
||||||
}
|
|
||||||
setWidth(Math.abs(offsetX));
|
|
||||||
|
|
||||||
double offsetY = newY - rectangleOriginY;
|
|
||||||
if (offsetY < 0) {
|
|
||||||
setY(newY);
|
|
||||||
}
|
|
||||||
setHeight(Math.abs(offsetY));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the rectangle to default dimensions.
|
|
||||||
*/
|
|
||||||
public final void defaultSettings() {
|
|
||||||
setX(0);
|
|
||||||
setY(0);
|
|
||||||
setWidth(0);
|
|
||||||
setHeight(0);
|
|
||||||
setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -271,22 +271,7 @@
|
|||||||
</Constraint>
|
</Constraint>
|
||||||
</Constraints>
|
</Constraints>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="htmlPanel" alignment="0" pref="647" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="htmlPanel" alignment="0" pref="362" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
|
||||||
<Component class="org.sleuthkit.autopsy.contentviewers.HtmlPanel" name="htmlPanel">
|
|
||||||
</Component>
|
|
||||||
</SubComponents>
|
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JScrollPane" name="rtfbodyScrollPane">
|
<Container class="javax.swing.JScrollPane" name="rtfbodyScrollPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
@ -87,7 +87,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
private static final int ATTM_TAB_INDEX = 4;
|
private static final int ATTM_TAB_INDEX = 4;
|
||||||
|
|
||||||
private final List<JTextComponent> textAreas;
|
private final List<JTextComponent> textAreas;
|
||||||
|
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
|
||||||
/**
|
/**
|
||||||
* Artifact currently being displayed
|
* Artifact currently being displayed
|
||||||
*/
|
*/
|
||||||
@ -101,6 +101,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
@NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
|
@NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
|
||||||
public MessageContentViewer() {
|
public MessageContentViewer() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
htmlPane.add(htmlPanel);
|
||||||
envelopePanel.setBackground(new Color(0, 0, 0, 38));
|
envelopePanel.setBackground(new Color(0, 0, 0, 38));
|
||||||
drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
|
drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
|
||||||
attachmentsScrollPane.setViewportView(drp);
|
attachmentsScrollPane.setViewportView(drp);
|
||||||
@ -153,7 +154,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
textbodyScrollPane = new javax.swing.JScrollPane();
|
textbodyScrollPane = new javax.swing.JScrollPane();
|
||||||
textbodyTextArea = new javax.swing.JTextArea();
|
textbodyTextArea = new javax.swing.JTextArea();
|
||||||
htmlPane = new javax.swing.JPanel();
|
htmlPane = new javax.swing.JPanel();
|
||||||
htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
|
|
||||||
rtfbodyScrollPane = new javax.swing.JScrollPane();
|
rtfbodyScrollPane = new javax.swing.JScrollPane();
|
||||||
rtfbodyTextPane = new javax.swing.JTextPane();
|
rtfbodyTextPane = new javax.swing.JTextPane();
|
||||||
attachmentsPanel = new javax.swing.JPanel();
|
attachmentsPanel = new javax.swing.JPanel();
|
||||||
@ -266,17 +266,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
|
|
||||||
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
|
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
|
||||||
|
|
||||||
javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane);
|
htmlPane.setLayout(new java.awt.BorderLayout());
|
||||||
htmlPane.setLayout(htmlPaneLayout);
|
|
||||||
htmlPaneLayout.setHorizontalGroup(
|
|
||||||
htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)
|
|
||||||
);
|
|
||||||
htmlPaneLayout.setVerticalGroup(
|
|
||||||
htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 362, Short.MAX_VALUE)
|
|
||||||
);
|
|
||||||
|
|
||||||
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
|
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
|
||||||
|
|
||||||
rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
||||||
@ -357,7 +347,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
private javax.swing.JScrollPane headersScrollPane;
|
private javax.swing.JScrollPane headersScrollPane;
|
||||||
private javax.swing.JTextArea headersTextArea;
|
private javax.swing.JTextArea headersTextArea;
|
||||||
private javax.swing.JPanel htmlPane;
|
private javax.swing.JPanel htmlPane;
|
||||||
private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
|
|
||||||
private javax.swing.JTabbedPane msgbodyTabbedPane;
|
private javax.swing.JTabbedPane msgbodyTabbedPane;
|
||||||
private javax.swing.JScrollPane rtfbodyScrollPane;
|
private javax.swing.JScrollPane rtfbodyScrollPane;
|
||||||
private javax.swing.JTextPane rtfbodyTextPane;
|
private javax.swing.JTextPane rtfbodyTextPane;
|
||||||
@ -680,18 +669,18 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet sheet = super.createSheet();
|
Sheet sheet = super.createSheet();
|
||||||
Set<String> keepProps = new HashSet<>(Arrays.asList(
|
Set<String> keepProps = new HashSet<>(Arrays.asList(
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
|
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
|
||||||
|
|
||||||
//Remove all other props except for the ones above
|
//Remove all other props except for the ones above
|
||||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||||
for(Property<?> p : sheetSet.getProperties()) {
|
for (Property<?> p : sheetSet.getProperties()) {
|
||||||
if(!keepProps.contains(p.getName())){
|
if (!keepProps.contains(p.getName())) {
|
||||||
sheetSet.remove(p.getName());
|
sheetSet.remove(p.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
343
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java
Executable file
343
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java
Executable file
@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
import com.sun.javafx.event.EventDispatchChainImpl;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyChangeSupport;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
import javafx.scene.shape.Rectangle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tagged region displayed over an image. This class contains a "physical tag"
|
||||||
|
* and 8 edit "handles". The physical tag is a plain old rectangle that defines
|
||||||
|
* the tag boundaries. The edit handles serve two purposes. One is to represent
|
||||||
|
* selection. All 8 edit handles will become visible overtop the physical tag
|
||||||
|
* when the user clicks on the rectangle. The other purpose is to allow the user to edit
|
||||||
|
* and manipulate the physical tag boundaries (hence the name, edit handle).
|
||||||
|
* This class should be treated as a logical image tag.
|
||||||
|
*/
|
||||||
|
public final class ImageTag extends Group {
|
||||||
|
|
||||||
|
// Used to tell the 8 edit handles to hide if this tag is no longer selected
|
||||||
|
private final EventDispatchChainImpl ALL_CHILDREN;
|
||||||
|
|
||||||
|
//Notifies listeners that the user has editted the tag boundaries
|
||||||
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||||
|
|
||||||
|
//The underlying presistent tag details that this image tag originates from
|
||||||
|
private final ContentViewerTag<ImageTagRegion> appTag;
|
||||||
|
|
||||||
|
public ImageTag(ContentViewerTag<ImageTagRegion> contentViewerTag, ImageView image) {
|
||||||
|
ALL_CHILDREN = new EventDispatchChainImpl();
|
||||||
|
this.appTag = contentViewerTag;
|
||||||
|
|
||||||
|
this.getChildren().addListener((ListChangeListener<Node>) change -> {
|
||||||
|
change.next();
|
||||||
|
change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher()));
|
||||||
|
});
|
||||||
|
|
||||||
|
ImageTagRegion details = contentViewerTag.getDetails();
|
||||||
|
PhysicalTag physicalTag = new PhysicalTag(details);
|
||||||
|
|
||||||
|
//Defines the max allowable boundary that a user may drag any given handle.
|
||||||
|
Boundary dragBoundary = (x, y) -> {
|
||||||
|
double boundingX = image.getX();
|
||||||
|
double boundingY = image.getY();
|
||||||
|
double width = image.getImage().getWidth();
|
||||||
|
double height = image.getImage().getHeight();
|
||||||
|
|
||||||
|
return x > boundingX + details.getStrokeThickness() / 2
|
||||||
|
&& x < boundingX + width - details.getStrokeThickness() / 2
|
||||||
|
&& y > boundingY + details.getStrokeThickness() / 2
|
||||||
|
&& y < boundingY + height - details.getStrokeThickness() / 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
EditHandle bottomLeft = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.bottom(), Position.left())
|
||||||
|
.setDrag(dragBoundary, Draggable.bottom(), Draggable.left());
|
||||||
|
|
||||||
|
EditHandle bottomRight = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.bottom(), Position.right())
|
||||||
|
.setDrag(dragBoundary, Draggable.bottom(), Draggable.right());
|
||||||
|
|
||||||
|
EditHandle topLeft = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.top(), Position.left())
|
||||||
|
.setDrag(dragBoundary, Draggable.top(), Draggable.left());
|
||||||
|
|
||||||
|
EditHandle topRight = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.top(), Position.right())
|
||||||
|
.setDrag(dragBoundary, Draggable.top(), Draggable.right());
|
||||||
|
|
||||||
|
EditHandle bottomMiddle = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.bottom(), Position.xMiddle())
|
||||||
|
.setDrag(dragBoundary, Draggable.bottom());
|
||||||
|
|
||||||
|
EditHandle topMiddle = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.top(), Position.xMiddle())
|
||||||
|
.setDrag(dragBoundary, Draggable.top());
|
||||||
|
|
||||||
|
EditHandle rightMiddle = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.right(), Position.yMiddle())
|
||||||
|
.setDrag(dragBoundary, Draggable.right());
|
||||||
|
|
||||||
|
EditHandle leftMiddle = new EditHandle(physicalTag)
|
||||||
|
.setPosition(Position.left(), Position.yMiddle())
|
||||||
|
.setDrag(dragBoundary, Draggable.left());
|
||||||
|
|
||||||
|
//The "logical" tag is the Group
|
||||||
|
this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft,
|
||||||
|
topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle);
|
||||||
|
|
||||||
|
Tooltip.install(this, new Tooltip(contentViewerTag.getContentTag()
|
||||||
|
.getName().getDisplayName()));
|
||||||
|
|
||||||
|
this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event));
|
||||||
|
this.addEventHandler(ImageTagControls.FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new listener for edit events. These events are generated when a
|
||||||
|
* user drags on one of the edit "knobs" of the tag.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public void subscribeToEditEvents(PropertyChangeListener listener) {
|
||||||
|
pcs.addPropertyChangeListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content viewer tag that this class represents.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ContentViewerTag<ImageTagRegion> getContentViewerTag() {
|
||||||
|
return appTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plain old rectangle that represents an unselected Image Tag
|
||||||
|
*/
|
||||||
|
class PhysicalTag extends Rectangle {
|
||||||
|
|
||||||
|
public PhysicalTag(ImageTagRegion details) {
|
||||||
|
this.setStroke(Color.RED);
|
||||||
|
this.setFill(Color.RED.deriveColor(0, 0, 0, 0));
|
||||||
|
this.setStrokeWidth(details.getStrokeThickness());
|
||||||
|
|
||||||
|
setX(details.getX());
|
||||||
|
setY(details.getY());
|
||||||
|
setWidth(details.getWidth());
|
||||||
|
setHeight(details.getHeight());
|
||||||
|
|
||||||
|
this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> this.setOpacity(1));
|
||||||
|
this.addEventHandler(ImageTagControls.FOCUSED, event -> this.setOpacity(0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a portable description of the tag region.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ImageTagRegion getState() {
|
||||||
|
return new ImageTagRegion()
|
||||||
|
.setX(this.getX())
|
||||||
|
.setY(this.getY())
|
||||||
|
.setWidth(this.getWidth())
|
||||||
|
.setHeight(this.getHeight())
|
||||||
|
.setStrokeThickness(this.getStrokeWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draggable "knob" used to manipulate the physical tag boundaries.
|
||||||
|
*/
|
||||||
|
class EditHandle extends Circle {
|
||||||
|
|
||||||
|
private final PhysicalTag parent;
|
||||||
|
|
||||||
|
public EditHandle(PhysicalTag parent) {
|
||||||
|
this.setVisible(false);
|
||||||
|
|
||||||
|
//Hide when the tag is not selected.
|
||||||
|
this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> this.setVisible(false));
|
||||||
|
this.addEventHandler(ImageTagControls.FOCUSED, event -> this.setVisible(true));
|
||||||
|
|
||||||
|
this.setRadius(parent.getStrokeWidth());
|
||||||
|
this.setFill(parent.getStroke());
|
||||||
|
|
||||||
|
this.setOnDragDetected(event -> {
|
||||||
|
this.getParent().setCursor(Cursor.CLOSED_HAND);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setOnMouseReleased(event -> {
|
||||||
|
this.getParent().setCursor(Cursor.DEFAULT);
|
||||||
|
pcs.firePropertyChange(new PropertyChangeEvent(this, "Tag Edit", null, parent.getState()));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the positioning of this edit handle on the physical tag.
|
||||||
|
*
|
||||||
|
* @param vals
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public EditHandle setPosition(Position... vals) {
|
||||||
|
for (Position pos : vals) {
|
||||||
|
parent.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(parent, this));
|
||||||
|
parent.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(parent, this));
|
||||||
|
pos.set(parent, this);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the drag capabilities for manipulating the physical tag.
|
||||||
|
*
|
||||||
|
* @param bounds
|
||||||
|
* @param vals
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public EditHandle setDrag(Boundary bounds, Draggable... vals) {
|
||||||
|
this.setOnMouseDragged((event) -> {
|
||||||
|
for (Draggable drag : vals) {
|
||||||
|
drag.perform(parent, event, bounds);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position strategies for "sticking" to a location on the physical tag when
|
||||||
|
* it is resized.
|
||||||
|
*/
|
||||||
|
static interface Position {
|
||||||
|
|
||||||
|
void set(PhysicalTag parent, Circle knob);
|
||||||
|
|
||||||
|
static Position left() {
|
||||||
|
return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Position right() {
|
||||||
|
return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Position top() {
|
||||||
|
return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Position bottom() {
|
||||||
|
return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Position xMiddle() {
|
||||||
|
return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Position yMiddle() {
|
||||||
|
return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the bounding box for which dragging is allowable.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
static interface Boundary {
|
||||||
|
|
||||||
|
boolean isPointInBounds(double x, double y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drag strategies for manipulating the physical tag from a given side of
|
||||||
|
* the rectangle.
|
||||||
|
*/
|
||||||
|
static interface Draggable {
|
||||||
|
|
||||||
|
void perform(PhysicalTag parent, MouseEvent event, Boundary b);
|
||||||
|
|
||||||
|
static Draggable bottom() {
|
||||||
|
return (parent, event, bounds) -> {
|
||||||
|
if (!bounds.isPointInBounds(event.getX(), event.getY())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double deltaY = event.getY() - parent.getY();
|
||||||
|
if (deltaY > 0) {
|
||||||
|
parent.setHeight(deltaY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Draggable top() {
|
||||||
|
return (parent, event, bounds) -> {
|
||||||
|
if (!bounds.isPointInBounds(event.getX(), event.getY())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double deltaY = parent.getY() + parent.getHeight() - event.getY();
|
||||||
|
if (deltaY < parent.getY() + parent.getHeight() && deltaY > 0) {
|
||||||
|
parent.setHeight(deltaY);
|
||||||
|
parent.setY(event.getY());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Draggable left() {
|
||||||
|
return (parent, event, bounds) -> {
|
||||||
|
if (!bounds.isPointInBounds(event.getX(), event.getY())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double deltaX = parent.getX() + parent.getWidth() - event.getX();
|
||||||
|
if (deltaX < parent.getX() + parent.getWidth() && deltaX > 0) {
|
||||||
|
parent.setWidth(deltaX);
|
||||||
|
parent.setX(event.getX());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Draggable right() {
|
||||||
|
return (parent, event, bounds) -> {
|
||||||
|
if (!bounds.isPointInBounds(event.getX(), event.getY())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double deltaX = event.getX() - parent.getX();
|
||||||
|
if (deltaX > 0) {
|
||||||
|
parent.setWidth(deltaX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
import javafx.event.Event;
|
||||||
|
import javafx.event.EventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus events for ImageTags to consume. These events trigger selection behavior
|
||||||
|
* on ImageTags and are originated from the ImageTagsGroup class.
|
||||||
|
*/
|
||||||
|
public class ImageTagControls {
|
||||||
|
public static final EventType<Event> NOT_FOCUSED = new EventType<>("NOT_FOCUSED");
|
||||||
|
public static final EventType<Event> FOCUSED = new EventType<>("FOCUSED");
|
||||||
|
}
|
180
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java
Executable file
180
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java
Executable file
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyChangeSupport;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Rectangle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates image tags. This class attaches itself to a source image, waiting
|
||||||
|
* for mouse press, mouse drag, and mouse release events. Upon a mouse release
|
||||||
|
* event, any listeners are updated with the portable description of the new tag
|
||||||
|
* boundaries (ImageTagRegion).
|
||||||
|
*/
|
||||||
|
public final class ImageTagCreator extends Rectangle {
|
||||||
|
|
||||||
|
//Origin of the drag event.
|
||||||
|
private double rectangleOriginX, rectangleOriginY;
|
||||||
|
|
||||||
|
//Rectangle lines should be 1.5% of the image. This level of thickness has
|
||||||
|
//a good balance between visual acuity and loss of selection at the borders
|
||||||
|
//of the image.
|
||||||
|
private final static double LINE_THICKNESS_PERCENT = 1.5;
|
||||||
|
private final double minArea;
|
||||||
|
|
||||||
|
//Used to update listeners of the new tag boundaries
|
||||||
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||||
|
|
||||||
|
private final EventHandler<MouseEvent> mousePressed;
|
||||||
|
private final EventHandler<MouseEvent> mouseDragged;
|
||||||
|
private final EventHandler<MouseEvent> mouseReleased;
|
||||||
|
|
||||||
|
//Handles the unregistering this ImageTagCreator from mouse press, mouse drag,
|
||||||
|
//and mouse release events of the source image.
|
||||||
|
private final Runnable disconnectRunnable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tagging support to an image, where the 'tag' rectangle will be the
|
||||||
|
* specified color.
|
||||||
|
*
|
||||||
|
* @param image Image to tag
|
||||||
|
*/
|
||||||
|
public ImageTagCreator(ImageView image) {
|
||||||
|
setStroke(Color.RED);
|
||||||
|
setFill(Color.RED.deriveColor(0, 0, 0, 0));
|
||||||
|
|
||||||
|
//Calculate how many pixels the stroke width should be to guarentee
|
||||||
|
//a consistent % of image consumed by the rectangle border.
|
||||||
|
double min = Math.min(image.getImage().getWidth(), image.getImage().getHeight());
|
||||||
|
double lineThicknessPixels = min * LINE_THICKNESS_PERCENT / 100.0;
|
||||||
|
setStrokeWidth(lineThicknessPixels);
|
||||||
|
minArea = lineThicknessPixels * lineThicknessPixels;
|
||||||
|
setVisible(false);
|
||||||
|
|
||||||
|
this.mousePressed = (MouseEvent event) -> {
|
||||||
|
if (event.isSecondaryButtonDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset box on new click.
|
||||||
|
defaultSettings();
|
||||||
|
rectangleOriginX = event.getX();
|
||||||
|
rectangleOriginY = event.getY();
|
||||||
|
|
||||||
|
setX(rectangleOriginX);
|
||||||
|
setY(rectangleOriginY);
|
||||||
|
};
|
||||||
|
|
||||||
|
image.addEventHandler(MouseEvent.MOUSE_PRESSED, this.mousePressed);
|
||||||
|
|
||||||
|
this.mouseDragged = (MouseEvent event) -> {
|
||||||
|
if (event.isSecondaryButtonDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double currentX = event.getX(), currentY = event.getY();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the rectangle is contained within image boundaries and
|
||||||
|
* that the line thickness is kept within bounds.
|
||||||
|
*/
|
||||||
|
double newX = Math.min(Math.max(currentX, image.getX())
|
||||||
|
+ lineThicknessPixels / 2, image.getImage().getWidth() - lineThicknessPixels / 2);
|
||||||
|
double newY = Math.min(Math.max(currentY, image.getY())
|
||||||
|
+ lineThicknessPixels / 2, image.getImage().getHeight() - lineThicknessPixels / 2);
|
||||||
|
|
||||||
|
setVisible(true);
|
||||||
|
double offsetX = newX - rectangleOriginX;
|
||||||
|
if (offsetX < 0) {
|
||||||
|
setX(newX);
|
||||||
|
}
|
||||||
|
setWidth(Math.abs(offsetX));
|
||||||
|
|
||||||
|
double offsetY = newY - rectangleOriginY;
|
||||||
|
if (offsetY < 0) {
|
||||||
|
setY(newY);
|
||||||
|
}
|
||||||
|
setHeight(Math.abs(offsetY));
|
||||||
|
};
|
||||||
|
|
||||||
|
image.addEventHandler(MouseEvent.MOUSE_DRAGGED, this.mouseDragged);
|
||||||
|
|
||||||
|
this.mouseReleased = event -> {
|
||||||
|
//Reject any drags that are too small to count as a meaningful tag.
|
||||||
|
//Meaningful is described as having an area that is visible that is
|
||||||
|
//not consumed by the thickness of the stroke.
|
||||||
|
if ((this.getWidth() - this.getStrokeWidth())
|
||||||
|
* (this.getHeight() - this.getStrokeWidth()) <= minArea) {
|
||||||
|
defaultSettings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pcs.firePropertyChange(new PropertyChangeEvent(this, "New Tag",
|
||||||
|
null, new ImageTagRegion()
|
||||||
|
.setX(this.getX())
|
||||||
|
.setY(this.getY())
|
||||||
|
.setWidth(this.getWidth())
|
||||||
|
.setHeight(this.getHeight())
|
||||||
|
.setStrokeThickness(lineThicknessPixels)));
|
||||||
|
};
|
||||||
|
|
||||||
|
image.addEventHandler(MouseEvent.MOUSE_RELEASED, this.mouseReleased);
|
||||||
|
|
||||||
|
//Used to remove itself from mouse events on the source image
|
||||||
|
disconnectRunnable = () -> {
|
||||||
|
defaultSettings();
|
||||||
|
image.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleased);
|
||||||
|
image.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragged);
|
||||||
|
image.removeEventHandler(MouseEvent.MOUSE_PRESSED, mousePressed);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a PCL for new tag events. Listeners are updated with a portable
|
||||||
|
* description (ImageTagRegion) of the new tag, which represent the
|
||||||
|
* rectangle boundaries.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public void addNewTagListener(PropertyChangeListener listener) {
|
||||||
|
this.pcs.addPropertyChangeListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes itself from mouse events on the source image.
|
||||||
|
*/
|
||||||
|
public void disconnect() {
|
||||||
|
this.disconnectRunnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the rectangle to default dimensions.
|
||||||
|
*/
|
||||||
|
private void defaultSettings() {
|
||||||
|
setWidth(0);
|
||||||
|
setHeight(0);
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bean representation of an image tag. This class is used for storage and
|
||||||
|
* retrieval of ImageTags from the case database.
|
||||||
|
*/
|
||||||
|
public class ImageTagRegion {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These fields will be serialized and stored in the case database by the
|
||||||
|
* ContentViewerTagManager.
|
||||||
|
*/
|
||||||
|
private double x;
|
||||||
|
private double y;
|
||||||
|
private double width;
|
||||||
|
private double height;
|
||||||
|
|
||||||
|
private double strokeThickness;
|
||||||
|
|
||||||
|
public ImageTagRegion setStrokeThickness(double thickness) {
|
||||||
|
this.strokeThickness = thickness;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageTagRegion setX(double x) {
|
||||||
|
this.x = x;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageTagRegion setWidth(double width) {
|
||||||
|
this.width = width;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageTagRegion setY(double y) {
|
||||||
|
this.y = y;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageTagRegion setHeight(double height) {
|
||||||
|
this.height = height;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getStrokeThickness() {
|
||||||
|
return strokeThickness;
|
||||||
|
}
|
||||||
|
}
|
134
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java
Executable file
134
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java
Executable file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
import com.sun.javafx.event.EventDispatchChainImpl;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyChangeSupport;
|
||||||
|
import javafx.event.Event;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the focus and z-ordering of ImageTags. Only one image tag may be
|
||||||
|
* selected at a time. Image tags show their 8 edit "handles" upon selection
|
||||||
|
* (see ImageTag class for more details) and get the highest z-ordering to make
|
||||||
|
* editing easier. This class is responsible for setting and dropping focus as
|
||||||
|
* the user navigates from tag to tag. The ImageTag is treated as a logical
|
||||||
|
* unit, however it's underlying representation consists of the physical
|
||||||
|
* rectangle and the 8 edit handles. JavaFX will report selection on the Node
|
||||||
|
* level (so either the Rectangle, or a singe edit handle), which makes keeping
|
||||||
|
* the entire image tag in focus a non-trivial problem.
|
||||||
|
*/
|
||||||
|
public final class ImageTagsGroup extends Group {
|
||||||
|
|
||||||
|
private final EventDispatchChainImpl NO_OP_CHAIN = new EventDispatchChainImpl();
|
||||||
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||||
|
|
||||||
|
private volatile ImageTag currentFocus;
|
||||||
|
|
||||||
|
public ImageTagsGroup(Node backDrop) {
|
||||||
|
|
||||||
|
//Reset focus of current selection if the back drop has focus.
|
||||||
|
backDrop.setOnMousePressed((mouseEvent) -> {
|
||||||
|
if (currentFocus != null) {
|
||||||
|
currentFocus.getEventDispatcher().dispatchEvent(
|
||||||
|
new Event(ImageTagControls.NOT_FOCUSED), NO_OP_CHAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pcs.firePropertyChange(new PropertyChangeEvent(this,
|
||||||
|
ImageTagControls.NOT_FOCUSED.getName(), currentFocus, null));
|
||||||
|
currentFocus = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
//Set the focus of selected tag
|
||||||
|
this.addEventFilter(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> {
|
||||||
|
if (!e.isPrimaryButtonDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pull out the logical image tag that this node is associated with
|
||||||
|
Node topLevelChild = e.getPickResult().getIntersectedNode();
|
||||||
|
while (!this.getChildren().contains(topLevelChild)) {
|
||||||
|
topLevelChild = topLevelChild.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
requestFocus((ImageTag) topLevelChild);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to focus change events on Image tags.
|
||||||
|
*
|
||||||
|
* @param fcl PCL to be notified which Image tag has been selected.
|
||||||
|
*/
|
||||||
|
public void addFocusChangeListener(PropertyChangeListener fcl) {
|
||||||
|
this.pcs.addPropertyChangeListener(fcl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the image tag that current has focus.
|
||||||
|
*
|
||||||
|
* @return ImageTag instance or null if no tag is in focus.
|
||||||
|
*/
|
||||||
|
public ImageTag getFocus() {
|
||||||
|
return currentFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the current focus
|
||||||
|
*/
|
||||||
|
public void clearFocus() {
|
||||||
|
if(currentFocus != null) {
|
||||||
|
resetFocus(currentFocus);
|
||||||
|
currentFocus = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the logical image tag that it is no longer in focus.
|
||||||
|
*
|
||||||
|
* @param n
|
||||||
|
*/
|
||||||
|
private void resetFocus(ImageTag n) {
|
||||||
|
n.getEventDispatcher().dispatchEvent(new Event(ImageTagControls.NOT_FOCUSED), NO_OP_CHAIN);
|
||||||
|
this.pcs.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.NOT_FOCUSED.getName(), n, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the logical image that it is in focus.
|
||||||
|
*
|
||||||
|
* @param n
|
||||||
|
*/
|
||||||
|
private void requestFocus(ImageTag n) {
|
||||||
|
if (n.equals(currentFocus)) {
|
||||||
|
return;
|
||||||
|
} else if (currentFocus != null && !currentFocus.equals(n)) {
|
||||||
|
resetFocus(currentFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
n.getEventDispatcher().dispatchEvent(new Event(ImageTagControls.FOCUSED), NO_OP_CHAIN);
|
||||||
|
this.pcs.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.FOCUSED.getName(), currentFocus, n));
|
||||||
|
|
||||||
|
currentFocus = n;
|
||||||
|
n.toFront();
|
||||||
|
}
|
||||||
|
}
|
141
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java
Executable file
141
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java
Executable file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.MatOfByte;
|
||||||
|
import org.opencv.core.MatOfInt;
|
||||||
|
import org.opencv.core.Point;
|
||||||
|
import org.opencv.core.Scalar;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
import org.opencv.highgui.Highgui;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for handling content viewer tags on images.
|
||||||
|
*/
|
||||||
|
public final class ImageTagsUtility {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sizes for thumbnails
|
||||||
|
*/
|
||||||
|
public enum IconSize {
|
||||||
|
SMALL(50),
|
||||||
|
MEDIUM(100),
|
||||||
|
LARGE(200);
|
||||||
|
|
||||||
|
private final int SIZE;
|
||||||
|
|
||||||
|
IconSize(int size) {
|
||||||
|
this.SIZE = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embeds the tag regions into an image.
|
||||||
|
*
|
||||||
|
* @param file Base Image
|
||||||
|
* @param tagRegions Tag regions to be saved into the image
|
||||||
|
* @param outputEncoding Format of image (jpg, png, etc). See OpenCV for
|
||||||
|
* supported formats. Do not include a "."
|
||||||
|
* @return Output image as a BufferedImage
|
||||||
|
*
|
||||||
|
* @throws TskCoreException Cannot read from abstract file
|
||||||
|
* @throws IOException Could not create buffered image from OpenCV result
|
||||||
|
*/
|
||||||
|
public static BufferedImage writeTags(AbstractFile file, Collection<ImageTagRegion> tagRegions,
|
||||||
|
String outputEncoding) throws TskCoreException, IOException {
|
||||||
|
byte[] imageInMemory = new byte[(int) file.getSize()];
|
||||||
|
file.read(imageInMemory, 0, file.getSize());
|
||||||
|
Mat originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_UNCHANGED);
|
||||||
|
|
||||||
|
tagRegions.forEach((region) -> {
|
||||||
|
Core.rectangle(
|
||||||
|
originalImage, //Matrix obj of the image
|
||||||
|
new Point(region.getX(), region.getY()), //p1
|
||||||
|
new Point(region.getX() + region.getWidth(), region.getY() + region.getHeight()), //p2
|
||||||
|
new Scalar(0, 0, 255), //Scalar object for color
|
||||||
|
(int) Math.rint(region.getStrokeThickness())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
MatOfByte matOfByte = new MatOfByte();
|
||||||
|
MatOfInt params = new MatOfInt(Highgui.IMWRITE_JPEG_QUALITY, 100);
|
||||||
|
Highgui.imencode("." + outputEncoding, originalImage, matOfByte, params);
|
||||||
|
|
||||||
|
try (ByteArrayInputStream imageStream = new ByteArrayInputStream(matOfByte.toArray())) {
|
||||||
|
BufferedImage result = ImageIO.read(imageStream);
|
||||||
|
originalImage.release();
|
||||||
|
matOfByte.release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a thumbnail version of the image with tags applied.
|
||||||
|
*
|
||||||
|
* @param file Input file to apply tags & produce thumbnail from
|
||||||
|
* @param tagRegions Tags to apply
|
||||||
|
* @param iconSize Size of the output thumbnail
|
||||||
|
* @param outputEncoding Format of thumbnail (jpg, png, etc). See OpenCV for
|
||||||
|
* supported formats. Do not include a "."
|
||||||
|
* @return BufferedImage representing the thumbnail
|
||||||
|
*
|
||||||
|
* @throws TskCoreException Could not read from file
|
||||||
|
* @throws IOException Could not create buffered image from OpenCV result
|
||||||
|
*/
|
||||||
|
public static BufferedImage makeThumbnail(AbstractFile file, Collection<ImageTagRegion> tagRegions,
|
||||||
|
IconSize iconSize, String outputEncoding) throws TskCoreException, IOException {
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
|
BufferedImage result = writeTags(file, tagRegions, outputEncoding);
|
||||||
|
ImageIO.write(result, outputEncoding, baos);
|
||||||
|
Mat markedUpImage = Highgui.imdecode(new MatOfByte(baos.toByteArray()), Highgui.IMREAD_UNCHANGED);
|
||||||
|
Mat thumbnail = new Mat();
|
||||||
|
Size resize = new Size(iconSize.getSize(), iconSize.getSize());
|
||||||
|
|
||||||
|
Imgproc.resize(markedUpImage, thumbnail, resize);
|
||||||
|
MatOfByte matOfByte = new MatOfByte();
|
||||||
|
Highgui.imencode("." + outputEncoding, thumbnail, matOfByte);
|
||||||
|
|
||||||
|
try (ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(matOfByte.toArray())) {
|
||||||
|
BufferedImage thumbnailImage = ImageIO.read(thumbnailStream);
|
||||||
|
thumbnail.release();
|
||||||
|
matOfByte.release();
|
||||||
|
markedUpImage.release();
|
||||||
|
return thumbnailImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageTagsUtility() {
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ import org.openide.nodes.Node;
|
|||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataContentViewer that displays text with the TextViewers available.
|
* A DataContentViewer that displays text with the TextViewers available.
|
||||||
@ -90,6 +91,17 @@ public class TextContentViewer implements DataContentViewer {
|
|||||||
if (node == null) {
|
if (node == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// get the node's File, if it has one
|
||||||
|
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
|
||||||
|
if (file == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable the text content viewer for directories and empty files
|
||||||
|
if (file.isDir() || file.getSize() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return panel.isSupported(node);
|
return panel.isSupported(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ public class TextContentViewerPanel extends javax.swing.JPanel implements DataCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deterime wether the content viewer which displays this panel isSupported.
|
* Determine whether the content viewer which displays this panel isSupported.
|
||||||
* This panel is supported if any of the TextViewer's displayed in it are
|
* This panel is supported if any of the TextViewer's displayed in it are
|
||||||
* supported.
|
* supported.
|
||||||
*
|
*
|
||||||
|
@ -3,13 +3,7 @@ Installer.closing.confirmationDialog.title=Ingest is Running
|
|||||||
# {0} - exception message
|
# {0} - exception message
|
||||||
Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0}
|
Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0}
|
||||||
OpenIDE-Module-Display-Category=Infrastructure
|
OpenIDE-Module-Display-Category=Infrastructure
|
||||||
OpenIDE-Module-Long-Description=\
|
OpenIDE-Module-Long-Description=This is the core Autopsy module.\n\nThe module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\nThe framework included in the module contains APIs for developing modules for ingest, viewers and reporting. The modules can be deployed as Plugins using the Autopsy plugin installer.\nThis module should not be uninstalled - without it, Autopsy will not run.\n\nFor more information, see http://www.sleuthkit.org/autopsy/
|
||||||
This is the core Autopsy module.\n\n\
|
|
||||||
The module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\n\
|
|
||||||
The framework included in the module contains APIs for developing modules for ingest, viewers and reporting. \
|
|
||||||
The modules can be deployed as Plugins using the Autopsy plugin installer.\n\
|
|
||||||
This module should not be uninstalled - without it, Autopsy will not run.\n\n\
|
|
||||||
For more information, see http://www.sleuthkit.org/autopsy/
|
|
||||||
OpenIDE-Module-Name=Autopsy-Core
|
OpenIDE-Module-Name=Autopsy-Core
|
||||||
OpenIDE-Module-Short-Description=Autopsy Core Module
|
OpenIDE-Module-Short-Description=Autopsy Core Module
|
||||||
org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml
|
org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml
|
||||||
|
@ -504,10 +504,10 @@ public final class UserPreferences {
|
|||||||
/**
|
/**
|
||||||
* Get the maximum number of results to display in a result table.
|
* Get the maximum number of results to display in a result table.
|
||||||
*
|
*
|
||||||
* @return Saved value or default (0) which indicates no max.
|
* @return Saved value or default (10,000).
|
||||||
*/
|
*/
|
||||||
public static int getResultsTablePageSize() {
|
public static int getResultsTablePageSize() {
|
||||||
return preferences.getInt(RESULTS_TABLE_PAGE_SIZE, 0);
|
return preferences.getInt(RESULTS_TABLE_PAGE_SIZE, 10_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -216,4 +216,5 @@ DataResultViewerTable.pagesLabel.text=Pages:
|
|||||||
DataResultViewerTable.pageNumLabel.text=
|
DataResultViewerTable.pageNumLabel.text=
|
||||||
DataResultViewerTable.pageLabel.text=Page:
|
DataResultViewerTable.pageLabel.text=Page:
|
||||||
ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table:
|
ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table:
|
||||||
ViewPreferencesPanel.maxResultsLabel.toolTipText=<html>\nAll results are shown in the results table if this value is 0 (default).\n<br>You may want to consider setting this value if you have large numbers of results that are taking a long time to display.\n</html>
|
ViewPreferencesPanel.maxResultsLabel.toolTipText=<html>\nSetting this value to 0 will display all results in the results table.\n<br>Note that setting this value to 0 may result in poor UI responsiveness when there are large numbers of results.\n</html>
|
||||||
|
DataResultViewerTable.exportCSVButton.text=Save table as CSV
|
||||||
|
@ -32,6 +32,7 @@ DataResultViewerTable.commentRenderer.noComment.toolTip=No comments found
|
|||||||
DataResultViewerTable.commentRenderer.tagComment.toolTip=Comment exists on associated tag(s)
|
DataResultViewerTable.commentRenderer.tagComment.toolTip=Comment exists on associated tag(s)
|
||||||
DataResultViewerTable.countRender.name=O
|
DataResultViewerTable.countRender.name=O
|
||||||
DataResultViewerTable.countRender.toolTip=O(ccurrences) indicates the number of data sources containing the item in the Central Repository
|
DataResultViewerTable.countRender.toolTip=O(ccurrences) indicates the number of data sources containing the item in the Central Repository
|
||||||
|
DataResultViewerTable.exportCSVButtonActionPerformed.empty=No data to export
|
||||||
DataResultViewerTable.firstColLbl=Name
|
DataResultViewerTable.firstColLbl=Name
|
||||||
DataResultViewerTable.goToPageTextField.err=Invalid page number
|
DataResultViewerTable.goToPageTextField.err=Invalid page number
|
||||||
# {0} - totalPages
|
# {0} - totalPages
|
||||||
@ -62,9 +63,9 @@ DataContentViewerHex.totalPageLabel.text_1=100
|
|||||||
DataContentViewerHex.pageLabel2.text=Page
|
DataContentViewerHex.pageLabel2.text=Page
|
||||||
|
|
||||||
# Product Information panel
|
# Product Information panel
|
||||||
LBL_Description=<div style=\"font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif;\">\n <b>Product Version:</b> {0} ({9}) <br><b>Sleuth Kit Version:</b> {7} <br><b>Netbeans RCP Build:</b> {8} <br> <b>Java:</b> {1}; {2}<br> <b>System:</b> {3}; {4}; {5}<br><b>Userdir:</b> {6}</div>
|
LBL_Description=<div style="font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif;">\n <b>Product Version:</b> {0} ({9}) <br><b>Sleuth Kit Version:</b> {7} <br><b>Netbeans RCP Build:</b> {8} <br> <b>Java:</b> {1}; {2}<br> <b>System:</b> {3}; {4}; {5}<br><b>Userdir:</b> {6}</div>
|
||||||
Format_OperatingSystem_Value={0} version {1} running on {2}
|
Format_OperatingSystem_Value={0} version {1} running on {2}
|
||||||
LBL_Copyright=<div style\="font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style\="color: \#1E2A60;" href\="http://www.sleuthkit.org">http://www.sleuthkit.org</a>.</li><li>Training: <a style\="color: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2018. </div>
|
LBL_Copyright=<div style="font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style="color: #1E2A60;" href="http://www.sleuthkit.org">http://www.sleuthkit.org</a>.</li><li>Training: <a style="color: #1E2A60;" href="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style="color: #1E2A60;" href="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2018. </div>
|
||||||
SortChooser.dialogTitle=Choose Sort Criteria
|
SortChooser.dialogTitle=Choose Sort Criteria
|
||||||
ThumbnailViewChildren.progress.cancelling=(Cancelling)
|
ThumbnailViewChildren.progress.cancelling=(Cancelling)
|
||||||
# {0} - file name
|
# {0} - file name
|
||||||
@ -94,7 +95,7 @@ DataResultViewerThumbnail.pageNextButton.text=
|
|||||||
DataResultViewerThumbnail.imagesLabel.text=Images:
|
DataResultViewerThumbnail.imagesLabel.text=Images:
|
||||||
DataResultViewerThumbnail.imagesRangeLabel.text=-
|
DataResultViewerThumbnail.imagesRangeLabel.text=-
|
||||||
DataResultViewerThumbnail.pageNumLabel.text=-
|
DataResultViewerThumbnail.pageNumLabel.text=-
|
||||||
DataResultViewerThumbnail.filePathLabel.text=\ \ \
|
DataResultViewerThumbnail.filePathLabel.text=\
|
||||||
DataResultViewerThumbnail.goToPageLabel.text=Go to Page:
|
DataResultViewerThumbnail.goToPageLabel.text=Go to Page:
|
||||||
DataResultViewerThumbnail.goToPageField.text=
|
DataResultViewerThumbnail.goToPageField.text=
|
||||||
AdvancedConfigurationDialog.cancelButton.text=Cancel
|
AdvancedConfigurationDialog.cancelButton.text=Cancel
|
||||||
@ -269,4 +270,5 @@ DataResultViewerTable.pagesLabel.text=Pages:
|
|||||||
DataResultViewerTable.pageNumLabel.text=
|
DataResultViewerTable.pageNumLabel.text=
|
||||||
DataResultViewerTable.pageLabel.text=Page:
|
DataResultViewerTable.pageLabel.text=Page:
|
||||||
ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table:
|
ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table:
|
||||||
ViewPreferencesPanel.maxResultsLabel.toolTipText=<html>\nAll results are shown in the results table if this value is 0 (default).\n<br>You may want to consider setting this value if you have large numbers of results that are taking a long time to display.\n</html>
|
ViewPreferencesPanel.maxResultsLabel.toolTipText=<html>\nSetting this value to 0 will display all results in the results table.\n<br>Note that setting this value to 0 may result in poor UI responsiveness when there are large numbers of results.\n</html>
|
||||||
|
DataResultViewerTable.exportCSVButton.text=Save table as CSV
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="outlineView" alignment="0" max="32767" attributes="0"/>
|
<Component id="outlineView" pref="904" max="32767" attributes="0"/>
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace pref="608" max="32767" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="pageLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="pageLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="pageNumLabel" min="-2" pref="53" max="-2" attributes="0"/>
|
<Component id="pageNumLabel" min="-2" pref="53" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
|
||||||
<Component id="pagesLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="pagesLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
<Component id="pagePrevButton" linkSize="1" min="-2" pref="16" max="-2" attributes="0"/>
|
<Component id="pagePrevButton" linkSize="1" min="-2" pref="16" max="-2" attributes="0"/>
|
||||||
@ -32,14 +32,15 @@
|
|||||||
<Component id="gotoPageLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="gotoPageLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="gotoPageTextField" min="-2" pref="33" max="-2" attributes="0"/>
|
<Component id="gotoPageTextField" min="-2" pref="33" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
|
<Component id="exportCSVButton" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="2" attributes="0">
|
<Group type="103" groupAlignment="2" attributes="0">
|
||||||
<Component id="pageLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
<Component id="pageLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="pageNumLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
<Component id="pageNumLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||||
@ -48,9 +49,10 @@
|
|||||||
<Component id="pageNextButton" linkSize="2" alignment="2" min="-2" pref="15" max="-2" attributes="0"/>
|
<Component id="pageNextButton" linkSize="2" alignment="2" min="-2" pref="15" max="-2" attributes="0"/>
|
||||||
<Component id="gotoPageLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
<Component id="gotoPageLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="gotoPageTextField" alignment="2" min="-2" max="-2" attributes="0"/>
|
<Component id="gotoPageTextField" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="exportCSVButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||||
<Component id="outlineView" pref="324" max="32767" attributes="0"/>
|
<Component id="outlineView" pref="321" max="32767" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -164,5 +166,15 @@
|
|||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="gotoPageTextFieldActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="gotoPageTextFieldActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="exportCSVButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerTable.exportCSVButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="exportCSVButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -77,6 +77,7 @@ import org.openide.util.lookup.ServiceProvider;
|
|||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
|
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
|
||||||
@ -177,6 +178,13 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
initializePagingSupport();
|
initializePagingSupport();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the CSV export button for the common properties results
|
||||||
|
*/
|
||||||
|
if (this instanceof org.sleuthkit.autopsy.commonpropertiessearch.CommonAttributesSearchResultsViewerTable) {
|
||||||
|
exportCSVButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure the child OutlineView (explorer view) component.
|
* Configure the child OutlineView (explorer view) component.
|
||||||
*/
|
*/
|
||||||
@ -293,20 +301,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
try {
|
try {
|
||||||
/*
|
if (rootNode != null) {
|
||||||
* If the given node is not null and has children, set it as the
|
|
||||||
* root context of the child OutlineView, otherwise make an
|
|
||||||
* "empty"node the root context.
|
|
||||||
*
|
|
||||||
* IMPORTANT NOTE: This is the first of many times where a
|
|
||||||
* getChildren call on the current root node causes all of the
|
|
||||||
* children of the root node to be created and defeats lazy child
|
|
||||||
* node creation, if it is enabled. It also likely leads to many
|
|
||||||
* case database round trips.
|
|
||||||
*/
|
|
||||||
if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
|
|
||||||
this.rootNode = rootNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if we have previously created a paging support
|
* Check to see if we have previously created a paging support
|
||||||
* class for this node.
|
* class for this node.
|
||||||
@ -355,6 +350,21 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the given node is not null and has children, set it as the
|
||||||
|
* root context of the child OutlineView, otherwise make an
|
||||||
|
* "empty"node the root context.
|
||||||
|
*
|
||||||
|
* IMPORTANT NOTE: This is the first of many times where a
|
||||||
|
* getChildren call on the current root node causes all of the
|
||||||
|
* children of the root node to be created and defeats lazy child
|
||||||
|
* node creation, if it is enabled. It also likely leads to many
|
||||||
|
* case database round trips.
|
||||||
|
*/
|
||||||
|
if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
|
||||||
|
this.rootNode = rootNode;
|
||||||
|
|
||||||
this.getExplorerManager().setRootContext(this.rootNode);
|
this.getExplorerManager().setRootContext(this.rootNode);
|
||||||
setupTable();
|
setupTable();
|
||||||
@ -1291,6 +1301,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);
|
outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);
|
||||||
gotoPageLabel = new javax.swing.JLabel();
|
gotoPageLabel = new javax.swing.JLabel();
|
||||||
gotoPageTextField = new javax.swing.JTextField();
|
gotoPageTextField = new javax.swing.JTextField();
|
||||||
|
exportCSVButton = new javax.swing.JButton();
|
||||||
|
|
||||||
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.pageLabel.text")); // NOI18N
|
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.pageLabel.text")); // NOI18N
|
||||||
|
|
||||||
@ -1338,17 +1349,24 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exportCSVButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.exportCSVButton.text")); // NOI18N
|
||||||
|
exportCSVButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
exportCSVButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 904, Short.MAX_VALUE)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addContainerGap(608, Short.MAX_VALUE)
|
.addContainerGap()
|
||||||
.addComponent(pageLabel)
|
.addComponent(pageLabel)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addGap(14, 14, 14)
|
||||||
.addComponent(pagesLabel)
|
.addComponent(pagesLabel)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
@ -1358,7 +1376,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
.addComponent(gotoPageLabel)
|
.addComponent(gotoPageLabel)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap())
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
|
.addComponent(exportCSVButton))
|
||||||
);
|
);
|
||||||
|
|
||||||
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {pageNextButton, pagePrevButton});
|
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {pageNextButton, pagePrevButton});
|
||||||
@ -1366,7 +1385,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addGap(3, 3, 3)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
||||||
.addComponent(pageLabel)
|
.addComponent(pageLabel)
|
||||||
.addComponent(pageNumLabel)
|
.addComponent(pageNumLabel)
|
||||||
@ -1374,9 +1393,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
.addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addComponent(gotoPageLabel)
|
.addComponent(gotoPageLabel)
|
||||||
.addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addComponent(exportCSVButton))
|
||||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE)
|
.addGap(3, 3, 3)
|
||||||
|
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE)
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1397,7 +1417,19 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
pagingSupport.gotoPage();
|
pagingSupport.gotoPage();
|
||||||
}//GEN-LAST:event_gotoPageTextFieldActionPerformed
|
}//GEN-LAST:event_gotoPageTextFieldActionPerformed
|
||||||
|
|
||||||
|
@NbBundle.Messages({"DataResultViewerTable.exportCSVButtonActionPerformed.empty=No data to export"
|
||||||
|
})
|
||||||
|
private void exportCSVButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportCSVButtonActionPerformed
|
||||||
|
Node currentRoot = this.getExplorerManager().getRootContext();
|
||||||
|
if (currentRoot != null && currentRoot.getChildren().getNodesCount() > 0) {
|
||||||
|
org.sleuthkit.autopsy.directorytree.ExportCSVAction.saveNodesToCSV(java.util.Arrays.asList(currentRoot.getChildren().getNodes()), this);
|
||||||
|
} else {
|
||||||
|
MessageNotifyUtil.Message.info(Bundle.DataResultViewerTable_exportCSVButtonActionPerformed_empty());
|
||||||
|
}
|
||||||
|
}//GEN-LAST:event_exportCSVButtonActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JButton exportCSVButton;
|
||||||
private javax.swing.JLabel gotoPageLabel;
|
private javax.swing.JLabel gotoPageLabel;
|
||||||
private javax.swing.JTextField gotoPageTextField;
|
private javax.swing.JTextField gotoPageTextField;
|
||||||
private org.openide.explorer.view.OutlineView outlineView;
|
private org.openide.explorer.view.OutlineView outlineView;
|
||||||
|
@ -11,217 +11,278 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-119,0,0,4,73"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="1" attributes="0">
|
|
||||||
<Component id="iconView" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="pageLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="pageNumLabel" min="-2" pref="95" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="pagesLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="pagePrevButton" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
|
||||||
<Component id="pageNextButton" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="goToPageLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="goToPageField" min="-2" pref="54" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
|
|
||||||
<Component id="imagesLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="imagesRangeLabel" min="-2" pref="91" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="thumbnailSizeComboBox" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
|
|
||||||
<Component id="sortButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="sortLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Component id="filePathLabel" alignment="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Group type="103" groupAlignment="2" attributes="0">
|
|
||||||
<Component id="pageLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="pageNumLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="pagesLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="pagePrevButton" alignment="2" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<Component id="pageNextButton" alignment="2" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<Component id="goToPageLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="goToPageField" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="imagesLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="imagesRangeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="thumbnailSizeComboBox" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="sortButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="sortLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
|
|
||||||
<Component id="iconView" pref="322" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="filePathLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JLabel" name="pageLabel">
|
<Container class="javax.swing.JPanel" name="buttonBarPanel">
|
||||||
<Properties>
|
<Constraints>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<BorderConstraints direction="North"/>
|
||||||
</Property>
|
</Constraint>
|
||||||
</Properties>
|
</Constraints>
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="pagesLabel">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout">
|
||||||
<Properties>
|
<Property name="alignment" type="int" value="0"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Layout>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<SubComponents>
|
||||||
</Property>
|
<Container class="javax.swing.JPanel" name="pagesPanel">
|
||||||
</Properties>
|
|
||||||
</Component>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<Component class="javax.swing.JButton" name="pagePrevButton">
|
<SubComponents>
|
||||||
<Properties>
|
<Container class="javax.swing.JPanel" name="pageNumberPane">
|
||||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<Constraints>
|
||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
</Property>
|
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="0.0" weightY="0.0"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Constraint>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pagePrevButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
</Constraints>
|
||||||
</Property>
|
|
||||||
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"/>
|
<SubComponents>
|
||||||
</Property>
|
<Component class="javax.swing.JLabel" name="pageLabel">
|
||||||
<Property name="focusable" type="boolean" value="false"/>
|
<Properties>
|
||||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
<Insets value="[2, 0, 2, 0]"/>
|
</Property>
|
||||||
</Property>
|
</Properties>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Constraints>
|
||||||
<Dimension value="[55, 23]"/>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
</Property>
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="9" anchor="23" weightX="0.0" weightY="1.0"/>
|
||||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
</Constraint>
|
||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"/>
|
</Constraints>
|
||||||
</Property>
|
</Component>
|
||||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
<Component class="javax.swing.JLabel" name="pageNumLabel">
|
||||||
</Properties>
|
<Properties>
|
||||||
<Events>
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pagePrevButtonActionPerformed"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pageNumLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Events>
|
</Property>
|
||||||
</Component>
|
</Properties>
|
||||||
<Component class="javax.swing.JButton" name="pageNextButton">
|
<Constraints>
|
||||||
<Properties>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="15" anchor="23" weightX="1.0" weightY="0.0"/>
|
||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"/>
|
</Constraint>
|
||||||
</Property>
|
</Constraints>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Component>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pageNextButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
</SubComponents>
|
||||||
</Property>
|
</Container>
|
||||||
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
</SubComponents>
|
||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"/>
|
</Container>
|
||||||
</Property>
|
<Container class="javax.swing.JPanel" name="pageButtonPanel">
|
||||||
<Property name="focusable" type="boolean" value="false"/>
|
|
||||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
<SubComponents>
|
||||||
<Insets value="[2, 0, 2, 0]"/>
|
<Component class="javax.swing.JLabel" name="pagesLabel">
|
||||||
</Property>
|
<Properties>
|
||||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Dimension value="[27, 23]"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
</Properties>
|
||||||
<Dimension value="[27, 23]"/>
|
<Constraints>
|
||||||
</Property>
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="9" anchor="17" weightX="0.0" weightY="1.0"/>
|
||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"/>
|
</Constraint>
|
||||||
</Property>
|
</Constraints>
|
||||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
</Component>
|
||||||
</Properties>
|
<Component class="javax.swing.JButton" name="pagePrevButton">
|
||||||
<Events>
|
<Properties>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pageNextButtonActionPerformed"/>
|
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
</Events>
|
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"/>
|
||||||
</Component>
|
</Property>
|
||||||
<Component class="javax.swing.JLabel" name="imagesLabel">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Properties>
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pagePrevButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Property>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.imagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
</Property>
|
<Border info="null"/>
|
||||||
</Properties>
|
</Property>
|
||||||
</Component>
|
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
<Component class="javax.swing.JLabel" name="imagesRangeLabel">
|
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"/>
|
||||||
<Properties>
|
</Property>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.imagesRangeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||||
</Property>
|
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||||
</Properties>
|
<Insets value="[0, 0, 0, 0]"/>
|
||||||
</Component>
|
</Property>
|
||||||
<Component class="javax.swing.JLabel" name="pageNumLabel">
|
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
<Properties>
|
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Property>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pageNumLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||||
</Property>
|
</Properties>
|
||||||
</Properties>
|
<Events>
|
||||||
</Component>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pagePrevButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="2" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="pageNextButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.pageNextButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
|
<Border info="null"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
|
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||||
|
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||||
|
<Insets value="[0, 0, 0, 0]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[27, 23]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[27, 23]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pageNextButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="2" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="15" anchor="23" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
<Container class="javax.swing.JPanel" name="pageGotoPane">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="goToPageLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.goToPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="9" anchor="17" weightX="0.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JTextField" name="goToPageField">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.goToPageField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="goToPageFieldActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="2" fill="0" ipadX="75" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="15" anchor="23" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
<Container class="javax.swing.JPanel" name="imagePane">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="imagesLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.imagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="9" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="imagesRangeLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.imagesRangeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="15" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
<Component class="javax.swing.JComboBox" name="thumbnailSizeComboBox">
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="thumbnailSizeComboBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox<>()"/>
|
||||||
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||||
|
</AuxValues>
|
||||||
|
</Component>
|
||||||
|
<Container class="javax.swing.JPanel" name="sortPane">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="sortLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.sortLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="0.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="sortButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.sortButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sortButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="0" insetsRight="9" anchor="23" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
<Component class="javax.swing.JLabel" name="filePathLabel">
|
<Component class="javax.swing.JLabel" name="filePathLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.filePathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.filePathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
<Constraints>
|
||||||
<Component class="javax.swing.JLabel" name="goToPageLabel">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
<Properties>
|
<BorderConstraints direction="South"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Constraint>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.goToPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
</Constraints>
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JTextField" name="goToPageField">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.goToPageField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="goToPageFieldActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JComboBox" name="thumbnailSizeComboBox">
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="thumbnailSizeComboBoxActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
<AuxValues>
|
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox<>()"/>
|
|
||||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
|
||||||
</AuxValues>
|
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="org.openide.explorer.view.IconView" name="iconView">
|
<Component class="org.openide.explorer.view.IconView" name="iconView">
|
||||||
</Component>
|
<Constraints>
|
||||||
<Component class="javax.swing.JButton" name="sortButton">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
<Properties>
|
<BorderConstraints direction="Center"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
</Constraint>
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.sortButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
</Constraints>
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sortButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="sortLabel">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataResultViewerThumbnail.sortLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -122,6 +122,11 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
currentPage = -1;
|
currentPage = -1;
|
||||||
totalPages = 0;
|
totalPages = 0;
|
||||||
currentPageImages = 0;
|
currentPageImages = 0;
|
||||||
|
|
||||||
|
// The GUI builder is using FlowLayout therefore this change so have no
|
||||||
|
// impact on the initally designed layout. This change will just effect
|
||||||
|
// how the components are laid out as size of the window changes.
|
||||||
|
buttonBarPanel.setLayout(new WrapLayout(java.awt.FlowLayout.LEFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,33 +137,84 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
|
buttonBarPanel = new javax.swing.JPanel();
|
||||||
|
pagesPanel = new javax.swing.JPanel();
|
||||||
|
pageNumberPane = new javax.swing.JPanel();
|
||||||
pageLabel = new javax.swing.JLabel();
|
pageLabel = new javax.swing.JLabel();
|
||||||
|
pageNumLabel = new javax.swing.JLabel();
|
||||||
|
pageButtonPanel = new javax.swing.JPanel();
|
||||||
pagesLabel = new javax.swing.JLabel();
|
pagesLabel = new javax.swing.JLabel();
|
||||||
pagePrevButton = new javax.swing.JButton();
|
pagePrevButton = new javax.swing.JButton();
|
||||||
pageNextButton = new javax.swing.JButton();
|
pageNextButton = new javax.swing.JButton();
|
||||||
imagesLabel = new javax.swing.JLabel();
|
pageGotoPane = new javax.swing.JPanel();
|
||||||
imagesRangeLabel = new javax.swing.JLabel();
|
|
||||||
pageNumLabel = new javax.swing.JLabel();
|
|
||||||
filePathLabel = new javax.swing.JLabel();
|
|
||||||
goToPageLabel = new javax.swing.JLabel();
|
goToPageLabel = new javax.swing.JLabel();
|
||||||
goToPageField = new javax.swing.JTextField();
|
goToPageField = new javax.swing.JTextField();
|
||||||
|
imagePane = new javax.swing.JPanel();
|
||||||
|
imagesLabel = new javax.swing.JLabel();
|
||||||
|
imagesRangeLabel = new javax.swing.JLabel();
|
||||||
thumbnailSizeComboBox = new javax.swing.JComboBox<>();
|
thumbnailSizeComboBox = new javax.swing.JComboBox<>();
|
||||||
iconView = new org.openide.explorer.view.IconView();
|
sortPane = new javax.swing.JPanel();
|
||||||
sortButton = new javax.swing.JButton();
|
|
||||||
sortLabel = new javax.swing.JLabel();
|
sortLabel = new javax.swing.JLabel();
|
||||||
|
sortButton = new javax.swing.JButton();
|
||||||
|
filePathLabel = new javax.swing.JLabel();
|
||||||
|
iconView = new org.openide.explorer.view.IconView();
|
||||||
|
|
||||||
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
buttonBarPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
|
||||||
|
|
||||||
|
pagesPanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
pageNumberPane.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageLabel.text")); // NOI18N
|
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
|
||||||
|
pageNumberPane.add(pageLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
pageNumLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNumLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
|
||||||
|
pageNumberPane.add(pageNumLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
pagesPanel.add(pageNumberPane, gridBagConstraints);
|
||||||
|
|
||||||
|
buttonBarPanel.add(pagesPanel);
|
||||||
|
|
||||||
|
pageButtonPanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
pagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagesLabel.text")); // NOI18N
|
pagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagesLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
|
||||||
|
pageButtonPanel.add(pagesLabel, gridBagConstraints);
|
||||||
|
|
||||||
pagePrevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
|
pagePrevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
|
||||||
pagePrevButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagePrevButton.text")); // NOI18N
|
pagePrevButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagePrevButton.text")); // NOI18N
|
||||||
|
pagePrevButton.setBorder(null);
|
||||||
pagePrevButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
|
pagePrevButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
|
||||||
pagePrevButton.setFocusable(false);
|
pagePrevButton.setFocusable(false);
|
||||||
pagePrevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
pagePrevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
pagePrevButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
pagePrevButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
|
||||||
pagePrevButton.setPreferredSize(new java.awt.Dimension(55, 23));
|
|
||||||
pagePrevButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N
|
pagePrevButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N
|
||||||
pagePrevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
pagePrevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||||
pagePrevButton.addActionListener(new java.awt.event.ActionListener() {
|
pagePrevButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -166,13 +222,20 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
pagePrevButtonActionPerformed(evt);
|
pagePrevButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.gridheight = 2;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
pageButtonPanel.add(pagePrevButton, gridBagConstraints);
|
||||||
|
|
||||||
pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
|
pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
|
||||||
pageNextButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNextButton.text")); // NOI18N
|
pageNextButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNextButton.text")); // NOI18N
|
||||||
|
pageNextButton.setBorder(null);
|
||||||
pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
|
pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
|
||||||
pageNextButton.setFocusable(false);
|
pageNextButton.setFocusable(false);
|
||||||
pageNextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
pageNextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
pageNextButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
pageNextButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
|
||||||
pageNextButton.setMaximumSize(new java.awt.Dimension(27, 23));
|
pageNextButton.setMaximumSize(new java.awt.Dimension(27, 23));
|
||||||
pageNextButton.setMinimumSize(new java.awt.Dimension(27, 23));
|
pageNextButton.setMinimumSize(new java.awt.Dimension(27, 23));
|
||||||
pageNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N
|
pageNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N
|
||||||
@ -182,16 +245,27 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
pageNextButtonActionPerformed(evt);
|
pageNextButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 2;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.gridheight = 2;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
|
||||||
|
pageButtonPanel.add(pageNextButton, gridBagConstraints);
|
||||||
|
|
||||||
imagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesLabel.text")); // NOI18N
|
buttonBarPanel.add(pageButtonPanel);
|
||||||
|
|
||||||
imagesRangeLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesRangeLabel.text")); // NOI18N
|
pageGotoPane.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
pageNumLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNumLabel.text")); // NOI18N
|
|
||||||
|
|
||||||
filePathLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.filePathLabel.text")); // NOI18N
|
|
||||||
|
|
||||||
goToPageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageLabel.text")); // NOI18N
|
goToPageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
|
||||||
|
pageGotoPane.add(goToPageLabel, gridBagConstraints);
|
||||||
|
|
||||||
goToPageField.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageField.text")); // NOI18N
|
goToPageField.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageField.text")); // NOI18N
|
||||||
goToPageField.addActionListener(new java.awt.event.ActionListener() {
|
goToPageField.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -199,12 +273,49 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
goToPageFieldActionPerformed(evt);
|
goToPageFieldActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.gridheight = 2;
|
||||||
|
gridBagConstraints.ipadx = 75;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
|
||||||
|
pageGotoPane.add(goToPageField, gridBagConstraints);
|
||||||
|
|
||||||
|
buttonBarPanel.add(pageGotoPane);
|
||||||
|
|
||||||
|
imagePane.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
imagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9);
|
||||||
|
imagePane.add(imagesLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
imagesRangeLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesRangeLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15);
|
||||||
|
imagePane.add(imagesRangeLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
buttonBarPanel.add(imagePane);
|
||||||
|
|
||||||
thumbnailSizeComboBox.addActionListener(new java.awt.event.ActionListener() {
|
thumbnailSizeComboBox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
thumbnailSizeComboBoxActionPerformed(evt);
|
thumbnailSizeComboBoxActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
buttonBarPanel.add(thumbnailSizeComboBox);
|
||||||
|
|
||||||
|
sortPane.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
sortLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
sortPane.add(sortLabel, gridBagConstraints);
|
||||||
|
|
||||||
sortButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortButton.text")); // NOI18N
|
sortButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortButton.text")); // NOI18N
|
||||||
sortButton.addActionListener(new java.awt.event.ActionListener() {
|
sortButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
@ -212,65 +323,20 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
sortButtonActionPerformed(evt);
|
sortButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 9);
|
||||||
|
sortPane.add(sortButton, gridBagConstraints);
|
||||||
|
|
||||||
sortLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortLabel.text")); // NOI18N
|
buttonBarPanel.add(sortPane);
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
add(buttonBarPanel, java.awt.BorderLayout.NORTH);
|
||||||
this.setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
filePathLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.filePathLabel.text")); // NOI18N
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
add(filePathLabel, java.awt.BorderLayout.SOUTH);
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
add(iconView, java.awt.BorderLayout.CENTER);
|
||||||
.addContainerGap()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
|
||||||
.addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
|
||||||
.addComponent(pageLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(pagesLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(0, 0, 0)
|
|
||||||
.addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(goToPageLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(12, 12, 12)
|
|
||||||
.addComponent(imagesLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(imagesRangeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(30, 30, 30)
|
|
||||||
.addComponent(sortButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addComponent(sortLabel))
|
|
||||||
.addComponent(filePathLabel, javax.swing.GroupLayout.Alignment.LEADING, 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()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
|
||||||
.addComponent(pageLabel)
|
|
||||||
.addComponent(pageNumLabel)
|
|
||||||
.addComponent(pagesLabel)
|
|
||||||
.addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(goToPageLabel)
|
|
||||||
.addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(imagesLabel)
|
|
||||||
.addComponent(imagesRangeLabel)
|
|
||||||
.addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(sortButton)
|
|
||||||
.addComponent(sortLabel))
|
|
||||||
.addGap(13, 13, 13)
|
|
||||||
.addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, 322, Short.MAX_VALUE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(filePathLabel))
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void pagePrevButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pagePrevButtonActionPerformed
|
private void pagePrevButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pagePrevButtonActionPerformed
|
||||||
@ -355,19 +421,26 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JPanel buttonBarPanel;
|
||||||
private javax.swing.JLabel filePathLabel;
|
private javax.swing.JLabel filePathLabel;
|
||||||
private javax.swing.JTextField goToPageField;
|
private javax.swing.JTextField goToPageField;
|
||||||
private javax.swing.JLabel goToPageLabel;
|
private javax.swing.JLabel goToPageLabel;
|
||||||
private org.openide.explorer.view.IconView iconView;
|
private org.openide.explorer.view.IconView iconView;
|
||||||
|
private javax.swing.JPanel imagePane;
|
||||||
private javax.swing.JLabel imagesLabel;
|
private javax.swing.JLabel imagesLabel;
|
||||||
private javax.swing.JLabel imagesRangeLabel;
|
private javax.swing.JLabel imagesRangeLabel;
|
||||||
|
private javax.swing.JPanel pageButtonPanel;
|
||||||
|
private javax.swing.JPanel pageGotoPane;
|
||||||
private javax.swing.JLabel pageLabel;
|
private javax.swing.JLabel pageLabel;
|
||||||
private javax.swing.JButton pageNextButton;
|
private javax.swing.JButton pageNextButton;
|
||||||
private javax.swing.JLabel pageNumLabel;
|
private javax.swing.JLabel pageNumLabel;
|
||||||
|
private javax.swing.JPanel pageNumberPane;
|
||||||
private javax.swing.JButton pagePrevButton;
|
private javax.swing.JButton pagePrevButton;
|
||||||
private javax.swing.JLabel pagesLabel;
|
private javax.swing.JLabel pagesLabel;
|
||||||
|
private javax.swing.JPanel pagesPanel;
|
||||||
private javax.swing.JButton sortButton;
|
private javax.swing.JButton sortButton;
|
||||||
private javax.swing.JLabel sortLabel;
|
private javax.swing.JLabel sortLabel;
|
||||||
|
private javax.swing.JPanel sortPane;
|
||||||
private javax.swing.JComboBox<String> thumbnailSizeComboBox;
|
private javax.swing.JComboBox<String> thumbnailSizeComboBox;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import java.util.EnumSet;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JSpinner;
|
||||||
import org.netbeans.spi.options.OptionsPanelController;
|
import org.netbeans.spi.options.OptionsPanelController;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||||
@ -55,6 +56,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
|||||||
groupByDataSourceCheckbox.setEnabled(evt.getNewValue() != null);
|
groupByDataSourceCheckbox.setEnabled(evt.getNewValue() != null);
|
||||||
});
|
});
|
||||||
this.timeZoneList.setListData(TimeZoneUtils.createTimeZoneList().stream().toArray(String[]::new));
|
this.timeZoneList.setListData(TimeZoneUtils.createTimeZoneList().stream().toArray(String[]::new));
|
||||||
|
|
||||||
|
// Disable manual editing of max results spinner
|
||||||
|
((JSpinner.DefaultEditor)maxResultsSpinner.getEditor()).getTextField().setEditable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
203
Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java
Executable file
203
Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java
Executable file
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.corecomponents;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FlowLayout subclass that fully supports wrapping of components.
|
||||||
|
*
|
||||||
|
* Originally written by Rob Camick
|
||||||
|
* https://tips4java.wordpress.com/2008/11/06/wrap-layout/
|
||||||
|
*/
|
||||||
|
class WrapLayout extends FlowLayout {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>WrapLayout</code> with a left alignment and a
|
||||||
|
* default 5-unit horizontal and vertical gap.
|
||||||
|
*/
|
||||||
|
public WrapLayout() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>FlowLayout</code> with the specified alignment
|
||||||
|
* and a default 5-unit horizontal and vertical gap. The value of the
|
||||||
|
* alignment argument must be one of <code>WrapLayout</code>,
|
||||||
|
* <code>WrapLayout</code>, or <code>WrapLayout</code>.
|
||||||
|
*
|
||||||
|
* @param align the alignment value
|
||||||
|
*/
|
||||||
|
public WrapLayout(int align) {
|
||||||
|
super(align);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new flow layout manager with the indicated alignment and
|
||||||
|
* the indicated horizontal and vertical gaps.
|
||||||
|
* <p>
|
||||||
|
* The value of the alignment argument must be one of
|
||||||
|
* <code>WrapLayout</code>, <code>WrapLayout</code>, or
|
||||||
|
* <code>WrapLayout</code>.
|
||||||
|
*
|
||||||
|
* @param align the alignment value
|
||||||
|
* @param hgap the horizontal gap between components
|
||||||
|
* @param vgap the vertical gap between components
|
||||||
|
*/
|
||||||
|
public WrapLayout(int align, int hgap, int vgap) {
|
||||||
|
super(align, hgap, vgap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the preferred dimensions for this layout given the
|
||||||
|
* <i>visible</i> components in the specified target container.
|
||||||
|
*
|
||||||
|
* @param target the component which needs to be laid out
|
||||||
|
*
|
||||||
|
* @return the preferred dimensions to lay out the subcomponents of the
|
||||||
|
* specified container
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Dimension preferredLayoutSize(Container target) {
|
||||||
|
return layoutSize(target, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum dimensions needed to layout the <i>visible</i>
|
||||||
|
* components contained in the specified target container.
|
||||||
|
*
|
||||||
|
* @param target the component which needs to be laid out
|
||||||
|
*
|
||||||
|
* @return the minimum dimensions to lay out the subcomponents of the
|
||||||
|
* specified container
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Dimension minimumLayoutSize(Container target) {
|
||||||
|
Dimension minimum = layoutSize(target, false);
|
||||||
|
minimum.width -= (getHgap() + 1);
|
||||||
|
return minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum or preferred dimension needed to layout the
|
||||||
|
* target container.
|
||||||
|
*
|
||||||
|
* @param target target to get layout size for
|
||||||
|
* @param preferred should preferred size be calculated
|
||||||
|
*
|
||||||
|
* @return the dimension to layout the target container
|
||||||
|
*/
|
||||||
|
private Dimension layoutSize(Container target, boolean preferred) {
|
||||||
|
synchronized (target.getTreeLock()) {
|
||||||
|
// Each row must fit with the width allocated to the containter.
|
||||||
|
// When the container width = 0, the preferred width of the container
|
||||||
|
// has not yet been calculated so lets ask for the maximum.
|
||||||
|
|
||||||
|
int targetWidth = target.getSize().width;
|
||||||
|
Container container = target;
|
||||||
|
|
||||||
|
while (container.getSize().width == 0 && container.getParent() != null) {
|
||||||
|
container = container.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
targetWidth = container.getSize().width;
|
||||||
|
|
||||||
|
if (targetWidth == 0) {
|
||||||
|
targetWidth = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgap = getHgap();
|
||||||
|
int vgap = getVgap();
|
||||||
|
Insets insets = target.getInsets();
|
||||||
|
int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
|
||||||
|
int maxWidth = targetWidth - horizontalInsetsAndGap;
|
||||||
|
|
||||||
|
// Fit components into the allowed width
|
||||||
|
Dimension dim = new Dimension(0, 0);
|
||||||
|
int rowWidth = 0;
|
||||||
|
int rowHeight = 0;
|
||||||
|
|
||||||
|
int nmembers = target.getComponentCount();
|
||||||
|
|
||||||
|
for (int i = 0; i < nmembers; i++) {
|
||||||
|
Component m = target.getComponent(i);
|
||||||
|
|
||||||
|
if (m.isVisible()) {
|
||||||
|
Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
|
||||||
|
|
||||||
|
// Can't add the component to current row. Start a new row.
|
||||||
|
if (rowWidth + d.width > maxWidth) {
|
||||||
|
addRow(dim, rowWidth, rowHeight);
|
||||||
|
rowWidth = 0;
|
||||||
|
rowHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a horizontal gap for all components after the first
|
||||||
|
if (rowWidth != 0) {
|
||||||
|
rowWidth += hgap;
|
||||||
|
}
|
||||||
|
|
||||||
|
rowWidth += d.width;
|
||||||
|
rowHeight = Math.max(rowHeight, d.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addRow(dim, rowWidth, rowHeight);
|
||||||
|
|
||||||
|
dim.width += horizontalInsetsAndGap;
|
||||||
|
dim.height += insets.top + insets.bottom + vgap * 2;
|
||||||
|
|
||||||
|
// When using a scroll pane or the DecoratedLookAndFeel we need to
|
||||||
|
// make sure the preferred size is less than the size of the
|
||||||
|
// target containter so shrinking the container size works
|
||||||
|
// correctly. Removing the horizontal gap is an easy way to do this.
|
||||||
|
Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
|
||||||
|
|
||||||
|
if (scrollPane != null && target.isValid()) {
|
||||||
|
dim.width -= (hgap + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A new row has been completed. Use the dimensions of this row to
|
||||||
|
* update the preferred size for the container.
|
||||||
|
*
|
||||||
|
* @param dim update the width and height when appropriate @param
|
||||||
|
* rowWidth the width of the row to add @param rowHeight the height of
|
||||||
|
* the row to add
|
||||||
|
*/
|
||||||
|
private void addRow(Dimension dim, int rowWidth, int rowHeight) {
|
||||||
|
dim.width = Math.max(dim.width, rowWidth);
|
||||||
|
|
||||||
|
if (dim.height > 0) {
|
||||||
|
dim.height += getVgap();
|
||||||
|
}
|
||||||
|
|
||||||
|
dim.height += rowHeight;
|
||||||
|
}
|
||||||
|
}
|
@ -23,9 +23,7 @@ PlatformUtil.getProcVmUsed.sigarNotInit.msg=Cannot get virt mem used, sigar not
|
|||||||
PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0}
|
PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0}
|
||||||
PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1}
|
PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1}
|
||||||
PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2}
|
PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2}
|
||||||
PlatformUtil.getAllMemUsageInfo.usageText={0}\n\
|
PlatformUtil.getAllMemUsageInfo.usageText={0}\n{1}\nProcess Virtual Memory: {2}
|
||||||
{1}\n\
|
|
||||||
Process Virtual Memory: {2}
|
|
||||||
# {0} - file name
|
# {0} - file name
|
||||||
ReadImageTask.mesageText=Reading image: {0}
|
ReadImageTask.mesageText=Reading image: {0}
|
||||||
StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract
|
StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract
|
||||||
|
@ -221,7 +221,8 @@ public class StringExtract {
|
|||||||
StringExtractResult resWin = null;
|
StringExtractResult resWin = null;
|
||||||
if (enableUTF8 && resUTF16 != null) {
|
if (enableUTF8 && resUTF16 != null) {
|
||||||
resWin = runUTF16 && resUTF16.numChars > resUTF8.numChars ? resUTF16 : resUTF8;
|
resWin = runUTF16 && resUTF16.numChars > resUTF8.numChars ? resUTF16 : resUTF8;
|
||||||
} else if (enableUTF16) {
|
} else if (runUTF16) {
|
||||||
|
//Only let resUTF16 "win" if it was actually run.
|
||||||
resWin = resUTF16;
|
resWin = resUTF16;
|
||||||
} else if (enableUTF8) {
|
} else if (enableUTF8) {
|
||||||
resWin = resUTF8;
|
resWin = resUTF8;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@ -27,8 +26,6 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
@ -65,6 +62,7 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.Tag;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -76,15 +74,10 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends AbstractContentNode<T> {
|
public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends AbstractContentNode<T> {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName());
|
private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName());
|
||||||
@NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description")
|
|
||||||
private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc();
|
|
||||||
|
|
||||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
|
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
|
||||||
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED);
|
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED);
|
||||||
|
|
||||||
private static final ExecutorService translationPool;
|
|
||||||
private static final Integer MAX_POOL_SIZE = 10;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param abstractFile file to wrap
|
* @param abstractFile file to wrap
|
||||||
*/
|
*/
|
||||||
@ -101,7 +94,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (UserPreferences.displayTranslatedFileNames()) {
|
if (UserPreferences.displayTranslatedFileNames()) {
|
||||||
AbstractAbstractFileNode.translationPool.submit(new TranslationTask(
|
backgroundTasksPool.submit(new TranslationTask(
|
||||||
new WeakReference<>(this), weakPcl));
|
new WeakReference<>(this), weakPcl));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,13 +103,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
|
||||||
//Initialize this pool only once! This will be used by every instance of AAFN
|
|
||||||
//to do their heavy duty SCO column and translation updates.
|
|
||||||
translationPool = Executors.newFixedThreadPool(MAX_POOL_SIZE,
|
|
||||||
new ThreadFactoryBuilder().setNameFormat("translation-task-thread-%d").build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The finalizer removes event listeners as the BlackboardArtifactNode is
|
* The finalizer removes event listeners as the BlackboardArtifactNode is
|
||||||
* being garbage collected. Yes, we know that finalizers are considered to
|
* being garbage collected. Yes, we know that finalizers are considered to
|
||||||
@ -137,16 +123,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Event signals to indicate the background tasks have completed processing.
|
|
||||||
* Currently, we have one property task in the background:
|
|
||||||
*
|
|
||||||
* 1) Retreiving the translation of the file name
|
|
||||||
*/
|
|
||||||
enum NodeSpecificEvents {
|
|
||||||
TRANSLATION_AVAILABLE,
|
|
||||||
}
|
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
String eventType = evt.getPropertyName();
|
String eventType = evt.getPropertyName();
|
||||||
|
|
||||||
@ -190,7 +166,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
|
} else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
|
||||||
ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
|
ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
|
||||||
if (event.getAddedTag().getContent().equals(content)) {
|
if (event.getAddedTag().getContent().equals(content)) {
|
||||||
List<ContentTag> tags = getContentTagsFromDatabase();
|
List<Tag> tags = this.getAllTagsFromDatabase();
|
||||||
Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
|
Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
|
||||||
Score value = scorePropAndDescr.getLeft();
|
Score value = scorePropAndDescr.getLeft();
|
||||||
String descr = scorePropAndDescr.getRight();
|
String descr = scorePropAndDescr.getRight();
|
||||||
@ -202,7 +178,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
|
} else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
|
||||||
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
|
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
|
||||||
if (event.getDeletedTagInfo().getContentID() == content.getId()) {
|
if (event.getDeletedTagInfo().getContentID() == content.getId()) {
|
||||||
List<ContentTag> tags = getContentTagsFromDatabase();
|
List<Tag> tags = getAllTagsFromDatabase();
|
||||||
Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
|
Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
|
||||||
Score value = scorePropAndDescr.getLeft();
|
Score value = scorePropAndDescr.getLeft();
|
||||||
String descr = scorePropAndDescr.getRight();
|
String descr = scorePropAndDescr.getRight();
|
||||||
@ -214,7 +190,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
} else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
|
} else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
|
||||||
CommentChangedEvent event = (CommentChangedEvent) evt;
|
CommentChangedEvent event = (CommentChangedEvent) evt;
|
||||||
if (event.getContentID() == content.getId()) {
|
if (event.getContentID() == content.getId()) {
|
||||||
List<ContentTag> tags = getContentTagsFromDatabase();
|
List<Tag> tags = getAllTagsFromDatabase();
|
||||||
CorrelationAttributeInstance attribute = getCorrelationAttributeInstance();
|
CorrelationAttributeInstance attribute = getCorrelationAttributeInstance();
|
||||||
updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, getCommentProperty(tags, attribute)));
|
updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, getCommentProperty(tags, attribute)));
|
||||||
}
|
}
|
||||||
@ -223,6 +199,18 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
//Set the tooltip
|
//Set the tooltip
|
||||||
this.setShortDescription(content.getName());
|
this.setShortDescription(content.getName());
|
||||||
updateSheet(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, content.getName()));
|
updateSheet(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, content.getName()));
|
||||||
|
} else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString())) {
|
||||||
|
SCOData scoData = (SCOData) evt.getNewValue();
|
||||||
|
if (scoData.getScoreAndDescription() != null) {
|
||||||
|
updateSheet(new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
|
||||||
|
}
|
||||||
|
if (scoData.getComment() != null) {
|
||||||
|
updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, scoData.getComment()));
|
||||||
|
}
|
||||||
|
if (scoData.getCountAndDescription() != null
|
||||||
|
&& !UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
|
||||||
|
updateSheet(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@ -235,38 +223,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
*/
|
*/
|
||||||
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
|
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the values of the properties in the current property sheet with
|
|
||||||
* the new properties being passed in. Only if that property exists in the
|
|
||||||
* current sheet will it be applied. That way, we allow for subclasses to
|
|
||||||
* add their own (or omit some!) properties and we will not accidentally
|
|
||||||
* disrupt their UI.
|
|
||||||
*
|
|
||||||
* Race condition if not synchronized. Only one update should be applied at
|
|
||||||
* a time.
|
|
||||||
*
|
|
||||||
* @param newProps New file property instances to be updated in the current
|
|
||||||
* sheet.
|
|
||||||
*/
|
|
||||||
private synchronized void updateSheet(NodeProperty<?>... newProps) {
|
|
||||||
//Refresh ONLY those properties in the sheet currently. Subclasses may have
|
|
||||||
//only added a subset of our properties or their own props.s
|
|
||||||
Sheet visibleSheet = this.getSheet();
|
|
||||||
Sheet.Set visibleSheetSet = visibleSheet.get(Sheet.PROPERTIES);
|
|
||||||
Property<?>[] visibleProps = visibleSheetSet.getProperties();
|
|
||||||
for (NodeProperty<?> newProp : newProps) {
|
|
||||||
for (int i = 0; i < visibleProps.length; i++) {
|
|
||||||
if (visibleProps[i].getName().equals(newProp.getName())) {
|
|
||||||
visibleProps[i] = newProp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
visibleSheetSet.put(visibleProps);
|
|
||||||
visibleSheet.put(visibleSheetSet);
|
|
||||||
//setSheet() will notify Netbeans to update this node in the UI.
|
|
||||||
this.setSheet(visibleSheet);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is called when the node is first initialized. Any new updates or
|
* This is called when the node is first initialized. Any new updates or
|
||||||
* changes happen by directly manipulating the sheet. That means we can fire
|
* changes happen by directly manipulating the sheet. That means we can fire
|
||||||
@ -368,18 +324,17 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
properties.add(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, ""));
|
properties.add(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
//SCO column prereq info..
|
// Create place holders for S C O
|
||||||
List<ContentTag> tags = getContentTagsFromDatabase();
|
properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), VALUE_LOADING, ""));
|
||||||
CorrelationAttributeInstance attribute = getCorrelationAttributeInstance();
|
properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), VALUE_LOADING, ""));
|
||||||
|
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
||||||
Pair<DataResultViewerTable.Score, String> scoreAndDescription = getScorePropertyAndDescription(tags);
|
properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, ""));
|
||||||
properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoreAndDescription.getRight(), scoreAndDescription.getLeft()));
|
|
||||||
DataResultViewerTable.HasCommentStatus comment = getCommentProperty(tags, attribute);
|
|
||||||
properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, comment));
|
|
||||||
if (!UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
|
|
||||||
Pair<Long, String> countAndDescription = getCountPropertyAndDescription(attribute);
|
|
||||||
properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), countAndDescription.getRight(), countAndDescription.getLeft()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the SCO columns data in a background task
|
||||||
|
backgroundTasksPool.submit(new GetSCOTask(
|
||||||
|
new WeakReference<>(this), weakPcl));
|
||||||
|
|
||||||
properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content)));
|
properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content)));
|
||||||
properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getMtime(), content)));
|
properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getMtime(), content)));
|
||||||
properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCtime(), content)));
|
properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCtime(), content)));
|
||||||
@ -437,13 +392,13 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"AbstractAbstractFileNode.createSheet.count.displayName=O",
|
"AbstractAbstractFileNode.createSheet.count.displayName=O",
|
||||||
"AbstractAbstractFileNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated",
|
|
||||||
"AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
|
"AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
|
||||||
"# {0} - occuranceCount",
|
"# {0} - occurenceCount",
|
||||||
"AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value"})
|
"AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurences of the MD5 correlation value"})
|
||||||
Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute) {
|
@Override
|
||||||
|
protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) {
|
||||||
Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting
|
Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting
|
||||||
String description = Bundle.AbstractAbstractFileNode_createSheet_count_noCentralRepo_description();
|
String description = defaultDescription;
|
||||||
try {
|
try {
|
||||||
//don't perform the query if there is no correlation value
|
//don't perform the query if there is no correlation value
|
||||||
if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
|
if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
|
||||||
@ -457,7 +412,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
} catch (CorrelationAttributeNormalizationException ex) {
|
} catch (CorrelationAttributeNormalizationException ex) {
|
||||||
logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
|
logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair.of(count, description);
|
return Pair.of(count, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +422,8 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
"AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
|
"AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
|
||||||
"AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
|
"AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
|
||||||
"AbstractAbstractFileNode.createSheet.noScore.description=No score"})
|
"AbstractAbstractFileNode.createSheet.noScore.description=No score"})
|
||||||
Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<ContentTag> tags) {
|
@Override
|
||||||
|
protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
|
||||||
DataResultViewerTable.Score score = DataResultViewerTable.Score.NO_SCORE;
|
DataResultViewerTable.Score score = DataResultViewerTable.Score.NO_SCORE;
|
||||||
String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
|
String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
|
||||||
if (content.getKnown() == TskData.FileKnown.BAD) {
|
if (content.getKnown() == TskData.FileKnown.BAD) {
|
||||||
@ -486,7 +441,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
if (!tags.isEmpty() && (score == DataResultViewerTable.Score.NO_SCORE || score == DataResultViewerTable.Score.INTERESTING_SCORE)) {
|
if (!tags.isEmpty() && (score == DataResultViewerTable.Score.NO_SCORE || score == DataResultViewerTable.Score.INTERESTING_SCORE)) {
|
||||||
score = DataResultViewerTable.Score.INTERESTING_SCORE;
|
score = DataResultViewerTable.Score.INTERESTING_SCORE;
|
||||||
description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description();
|
description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description();
|
||||||
for (ContentTag tag : tags) {
|
for (Tag tag : tags) {
|
||||||
if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
|
if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
|
||||||
score = DataResultViewerTable.Score.NOTABLE_SCORE;
|
score = DataResultViewerTable.Score.NOTABLE_SCORE;
|
||||||
description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description();
|
description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description();
|
||||||
@ -499,11 +454,12 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"AbstractAbstractFileNode.createSheet.comment.displayName=C"})
|
"AbstractAbstractFileNode.createSheet.comment.displayName=C"})
|
||||||
HasCommentStatus getCommentProperty(List<ContentTag> tags, CorrelationAttributeInstance attribute) {
|
@Override
|
||||||
|
protected HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||||
|
|
||||||
DataResultViewerTable.HasCommentStatus status = !tags.isEmpty() ? DataResultViewerTable.HasCommentStatus.TAG_NO_COMMENT : DataResultViewerTable.HasCommentStatus.NO_COMMENT;
|
DataResultViewerTable.HasCommentStatus status = !tags.isEmpty() ? DataResultViewerTable.HasCommentStatus.TAG_NO_COMMENT : DataResultViewerTable.HasCommentStatus.NO_COMMENT;
|
||||||
|
|
||||||
for (ContentTag tag : tags) {
|
for (Tag tag : tags) {
|
||||||
if (!StringUtils.isBlank(tag.getComment())) {
|
if (!StringUtils.isBlank(tag.getComment())) {
|
||||||
//if the tag is null or empty or contains just white space it will indicate there is not a comment
|
//if the tag is null or empty or contains just white space it will indicate there is not a comment
|
||||||
status = DataResultViewerTable.HasCommentStatus.TAG_COMMENT;
|
status = DataResultViewerTable.HasCommentStatus.TAG_COMMENT;
|
||||||
@ -571,7 +527,13 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
@Override
|
||||||
|
protected List<Tag> getAllTagsFromDatabase() {
|
||||||
|
return new ArrayList<>(getContentTagsFromDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||||
CorrelationAttributeInstance attribute = null;
|
CorrelationAttributeInstance attribute = null;
|
||||||
if (EamDb.isEnabled() && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
|
if (EamDb.isEnabled() && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
|
||||||
attribute = EamArtifactUtil.getInstanceFromContent(content);
|
attribute = EamArtifactUtil.getInstanceFromContent(content);
|
||||||
|
@ -18,20 +18,29 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.Tag;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
@ -51,22 +60,55 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
private static final Logger logger = Logger.getLogger(AbstractContentNode.class.getName());
|
private static final Logger logger = Logger.getLogger(AbstractContentNode.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles aspects that depend on the Content object
|
* A pool of background tasks to run any long computation needed to populate
|
||||||
*
|
* this node.
|
||||||
* @param content Underlying Content instances
|
|
||||||
*/
|
*/
|
||||||
AbstractContentNode(T content) {
|
static final ExecutorService backgroundTasksPool;
|
||||||
this(content, Lookups.singleton(content) );
|
private static final Integer MAX_POOL_SIZE = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default no description string
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({"AbstractContentNode.nodescription=no description",
|
||||||
|
"AbstractContentNode.valueLoading=value loading"})
|
||||||
|
protected static final String NO_DESCR = Bundle.AbstractContentNode_nodescription();
|
||||||
|
protected static final String VALUE_LOADING = Bundle.AbstractContentNode_valueLoading();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event signals to indicate the background tasks have completed processing.
|
||||||
|
* Currently, we have one property task in the background:
|
||||||
|
*
|
||||||
|
* 1) Retrieving the translation of the file name
|
||||||
|
*/
|
||||||
|
enum NodeSpecificEvents {
|
||||||
|
TRANSLATION_AVAILABLE,
|
||||||
|
SCO_AVAILABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
//Initialize this pool only once! This will be used by every instance of AAFN
|
||||||
|
//to do their heavy duty SCO column and translation updates.
|
||||||
|
backgroundTasksPool = Executors.newFixedThreadPool(MAX_POOL_SIZE,
|
||||||
|
new ThreadFactoryBuilder().setNameFormat("content-node-background-task-%d").build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles aspects that depend on the Content object
|
* Handles aspects that depend on the Content object
|
||||||
*
|
*
|
||||||
* @param content Underlying Content instances
|
* @param content Underlying Content instances
|
||||||
* @param lookup The Lookup object for the node.
|
*/
|
||||||
|
AbstractContentNode(T content) {
|
||||||
|
this(content, Lookups.singleton(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles aspects that depend on the Content object
|
||||||
|
*
|
||||||
|
* @param content Underlying Content instances
|
||||||
|
* @param lookup The Lookup object for the node.
|
||||||
*/
|
*/
|
||||||
AbstractContentNode(T content, Lookup lookup) {
|
AbstractContentNode(T content, Lookup lookup) {
|
||||||
super(Children.create(new ContentChildren(content), true), lookup);
|
super(Children.create(new ContentChildren(content), false), lookup);
|
||||||
this.content = content;
|
this.content = content;
|
||||||
//super.setName(ContentUtils.getSystemName(content));
|
//super.setName(ContentUtils.getSystemName(content));
|
||||||
super.setName("content_" + Long.toString(content.getId())); //NON-NLS
|
super.setName("content_" + Long.toString(content.getId())); //NON-NLS
|
||||||
@ -106,13 +148,14 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
* loading.
|
* loading.
|
||||||
*
|
*
|
||||||
* @param c The content object to look for children on
|
* @param c The content object to look for children on
|
||||||
|
*
|
||||||
* @return true if has children
|
* @return true if has children
|
||||||
*/
|
*/
|
||||||
public static boolean contentHasVisibleContentChildren(Content c){
|
public static boolean contentHasVisibleContentChildren(Content c) {
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if( ! c.hasChildren()) {
|
if (!c.hasChildren()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
@ -122,18 +165,17 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
String query = "SELECT COUNT(obj_id) AS count FROM "
|
String query = "SELECT COUNT(obj_id) AS count FROM "
|
||||||
+ " ( SELECT obj_id FROM tsk_objects WHERE par_obj_id = " + c.getId() + " AND type = "
|
+ " ( SELECT obj_id FROM tsk_objects WHERE par_obj_id = " + c.getId() + " AND type = "
|
||||||
+ TskData.ObjectType.ARTIFACT.getObjectType()
|
+ TskData.ObjectType.ARTIFACT.getObjectType()
|
||||||
+ " INTERSECT SELECT artifact_obj_id FROM blackboard_artifacts WHERE obj_id = " + c.getId()
|
+ " INTERSECT SELECT artifact_obj_id FROM blackboard_artifacts WHERE obj_id = " + c.getId()
|
||||||
+ " AND (artifact_type_id = " + ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
|
+ " AND (artifact_type_id = " + ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
|
||||||
+ " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + ") "
|
+ " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + ") "
|
||||||
+ " UNION SELECT obj_id FROM tsk_objects WHERE par_obj_id = " + c.getId()
|
+ " UNION SELECT obj_id FROM tsk_objects WHERE par_obj_id = " + c.getId()
|
||||||
+ " AND type = " + TskData.ObjectType.ABSTRACTFILE.getObjectType() + ") AS OBJECT_IDS"; //NON-NLS;
|
+ " AND type = " + TskData.ObjectType.ABSTRACTFILE.getObjectType() + ") AS OBJECT_IDS"; //NON-NLS;
|
||||||
|
|
||||||
|
|
||||||
try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(query)) {
|
try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(query)) {
|
||||||
ResultSet resultSet = dbQuery.getResultSet();
|
ResultSet resultSet = dbQuery.getResultSet();
|
||||||
if(resultSet.next()){
|
if (resultSet.next()) {
|
||||||
return (0 < resultSet.getInt("count"));
|
return (0 < resultSet.getInt("count"));
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | SQLException | NoCurrentCaseException ex) {
|
} catch (TskCoreException | SQLException | NoCurrentCaseException ex) {
|
||||||
@ -240,4 +282,82 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
public int read(byte[] buf, long offset, long len) throws TskException {
|
public int read(byte[] buf, long offset, long len) throws TskException {
|
||||||
return content.read(buf, offset, len);
|
return content.read(buf, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the values of the properties in the current property sheet with
|
||||||
|
* the new properties being passed in. Only if that property exists in the
|
||||||
|
* current sheet will it be applied. That way, we allow for subclasses to
|
||||||
|
* add their own (or omit some!) properties and we will not accidentally
|
||||||
|
* disrupt their UI.
|
||||||
|
*
|
||||||
|
* Race condition if not synchronized. Only one update should be applied at
|
||||||
|
* a time.
|
||||||
|
*
|
||||||
|
* @param newProps New file property instances to be updated in the current
|
||||||
|
* sheet.
|
||||||
|
*/
|
||||||
|
protected synchronized void updateSheet(NodeProperty<?>... newProps) {
|
||||||
|
//Refresh ONLY those properties in the sheet currently. Subclasses may have
|
||||||
|
//only added a subset of our properties or their own props.s
|
||||||
|
Sheet visibleSheet = this.getSheet();
|
||||||
|
Sheet.Set visibleSheetSet = visibleSheet.get(Sheet.PROPERTIES);
|
||||||
|
Property<?>[] visibleProps = visibleSheetSet.getProperties();
|
||||||
|
for (NodeProperty<?> newProp : newProps) {
|
||||||
|
for (int i = 0; i < visibleProps.length; i++) {
|
||||||
|
if (visibleProps[i].getName().equals(newProp.getName())) {
|
||||||
|
visibleProps[i] = newProp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visibleSheetSet.put(visibleProps);
|
||||||
|
visibleSheet.put(visibleSheetSet);
|
||||||
|
//setSheet() will notify Netbeans to update this node in the UI.
|
||||||
|
this.setSheet(visibleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and returns a list of all tags associated with this content node.
|
||||||
|
*
|
||||||
|
* @return list of tags associated with the node.
|
||||||
|
*/
|
||||||
|
abstract protected List<Tag> getAllTagsFromDatabase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns correlation attribute instance for the underlying content of the
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* @return correlation attribute instance for the underlying content of the
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
abstract protected CorrelationAttributeInstance getCorrelationAttributeInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Score property for the node.
|
||||||
|
*
|
||||||
|
* @param tags list of tags.
|
||||||
|
*
|
||||||
|
* @return Score property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
abstract protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns comment property for the node.
|
||||||
|
*
|
||||||
|
* @param tags list of tags
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
*
|
||||||
|
* @return Comment property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
abstract protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns occurrences/count property for the node.
|
||||||
|
*
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
* @param defaultDescription a description to use when none is determined by
|
||||||
|
* the getCountPropertyAndDescription method
|
||||||
|
*
|
||||||
|
* @return count property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
abstract protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription);
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,12 @@ public abstract class BaseChildFactory<T extends Content> extends ChildFactory.D
|
|||||||
* If pageSize is set split keys into pages, otherwise create a
|
* If pageSize is set split keys into pages, otherwise create a
|
||||||
* single page containing all keys.
|
* single page containing all keys.
|
||||||
*/
|
*/
|
||||||
pages = Lists.partition(keys, pageSize > 0 ? pageSize : keys.size());
|
if (keys.isEmpty()) {
|
||||||
|
pages.clear();
|
||||||
|
} else {
|
||||||
|
pages = Lists.partition(keys, pageSize > 0 ? pageSize : keys.size());
|
||||||
|
}
|
||||||
|
|
||||||
if (pages.size() != oldPageCount) {
|
if (pages.size() != oldPageCount) {
|
||||||
try {
|
try {
|
||||||
// Number of pages has changed so we need to send out a notification.
|
// Number of pages has changed so we need to send out a notification.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -22,6 +22,7 @@ import com.google.common.cache.Cache;
|
|||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -37,6 +38,7 @@ import java.util.logging.Level;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -55,11 +57,13 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
|
|||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.Score;
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.Score;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
|
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStatus;
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStatus;
|
||||||
|
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.backgroundTasksPool;
|
||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager;
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager;
|
||||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||||
@ -96,9 +100,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
|
|
||||||
private List<NodeProperty<? extends Object>> customProperties;
|
private List<NodeProperty<? extends Object>> customProperties;
|
||||||
|
|
||||||
private final static String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text");
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Artifact types which should have the full unique path of the associated
|
* Artifact types which should have the full unique path of the associated
|
||||||
* content as a property.
|
* content as a property.
|
||||||
@ -150,6 +151,18 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
removeListeners();
|
removeListeners();
|
||||||
contentCache.invalidateAll();
|
contentCache.invalidateAll();
|
||||||
}
|
}
|
||||||
|
} else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString())) {
|
||||||
|
SCOData scoData = (SCOData) evt.getNewValue();
|
||||||
|
if (scoData.getScoreAndDescription() != null) {
|
||||||
|
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
|
||||||
|
}
|
||||||
|
if (scoData.getComment() != null) {
|
||||||
|
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, scoData.getComment()));
|
||||||
|
}
|
||||||
|
if (scoData.getCountAndDescription() != null
|
||||||
|
&& !UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
|
||||||
|
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -335,8 +348,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet sheet = super.createSheet();
|
Sheet sheet = super.createSheet();
|
||||||
List<Tag> tags = getAllTagsFromDatabase();
|
|
||||||
|
|
||||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||||
if (sheetSet == null) {
|
if (sheetSet == null) {
|
||||||
sheetSet = Sheet.createPropertiesSet();
|
sheetSet = Sheet.createPropertiesSet();
|
||||||
@ -351,17 +362,17 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
NO_DESCR,
|
NO_DESCR,
|
||||||
this.getSourceName()));
|
this.getSourceName()));
|
||||||
|
|
||||||
addScoreProperty(sheetSet, tags);
|
// Create place holders for S C O
|
||||||
|
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, ""));
|
||||||
CorrelationAttributeInstance correlationAttribute = null;
|
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, ""));
|
||||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
||||||
correlationAttribute = getCorrelationAttributeInstance();
|
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, ""));
|
||||||
}
|
}
|
||||||
addCommentProperty(sheetSet, tags, correlationAttribute);
|
|
||||||
|
|
||||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
// Get the SCO columns data in a background task
|
||||||
addCountProperty(sheetSet, correlationAttribute);
|
backgroundTasksPool.submit(new GetSCOTask(
|
||||||
}
|
new WeakReference<>(this), weakPcl));
|
||||||
|
|
||||||
if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||||
try {
|
try {
|
||||||
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||||
@ -520,6 +531,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
* @return a list of tags which on the artifact or the file it is associated
|
* @return a list of tags which on the artifact or the file it is associated
|
||||||
* with
|
* with
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
protected final List<Tag> getAllTagsFromDatabase() {
|
protected final List<Tag> getAllTagsFromDatabase() {
|
||||||
List<Tag> tags = new ArrayList<>();
|
List<Tag> tags = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
@ -569,6 +581,13 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
|
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the correlation attribute for the associated file
|
||||||
|
*
|
||||||
|
* @return the correlation attribute for the file associated with this
|
||||||
|
* BlackboardArtifactNode
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
protected final CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
protected final CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||||
CorrelationAttributeInstance correlationAttribute = null;
|
CorrelationAttributeInstance correlationAttribute = null;
|
||||||
if (EamDb.isEnabled()) {
|
if (EamDb.isEnabled()) {
|
||||||
@ -581,16 +600,37 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
* Used by (subclasses of) BlackboardArtifactNode to add the comment
|
* Used by (subclasses of) BlackboardArtifactNode to add the comment
|
||||||
* property to their sheets.
|
* property to their sheets.
|
||||||
*
|
*
|
||||||
* @param sheetSet the modifiable Sheet.Set returned by
|
* @param sheetSet the modifiable Sheet.Set to add the property to
|
||||||
* Sheet.get(Sheet.PROPERTIES)
|
|
||||||
* @param tags the list of tags associated with the file
|
* @param tags the list of tags associated with the file
|
||||||
* @param attribute the correlation attribute associated with this
|
* @param attribute the correlation attribute associated with this
|
||||||
* artifact's associated file, null if central repo is not
|
* artifact's associated file, null if central repo is not
|
||||||
* enabled
|
* enabled
|
||||||
|
*
|
||||||
|
* @deprecated Use the GetSCOTask to get this data on a background
|
||||||
|
* thread..., and then update the property sheet asynchronously
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C",
|
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C",
|
||||||
"BlackboardArtifactNode.createSheet.comment.displayName=C"})
|
"BlackboardArtifactNode.createSheet.comment.displayName=C"})
|
||||||
|
@Deprecated
|
||||||
protected final void addCommentProperty(Sheet.Set sheetSet, List<Tag> tags, CorrelationAttributeInstance attribute) {
|
protected final void addCommentProperty(Sheet.Set sheetSet, List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||||
|
HasCommentStatus status = getCommentProperty(tags, attribute);
|
||||||
|
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR,
|
||||||
|
status));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the comment property for the node
|
||||||
|
*
|
||||||
|
* @param tags the list of tags associated with the file
|
||||||
|
* @param attribute the correlation attribute associated with this
|
||||||
|
* artifact's associated file, null if central repo is not
|
||||||
|
* enabled
|
||||||
|
*
|
||||||
|
* @return comment property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||||
|
|
||||||
HasCommentStatus status = tags.size() > 0 ? HasCommentStatus.TAG_NO_COMMENT : HasCommentStatus.NO_COMMENT;
|
HasCommentStatus status = tags.size() > 0 ? HasCommentStatus.TAG_NO_COMMENT : HasCommentStatus.NO_COMMENT;
|
||||||
for (Tag tag : tags) {
|
for (Tag tag : tags) {
|
||||||
if (!StringUtils.isBlank(tag.getComment())) {
|
if (!StringUtils.isBlank(tag.getComment())) {
|
||||||
@ -609,17 +649,18 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
status = HasCommentStatus.CR_COMMENT;
|
status = HasCommentStatus.CR_COMMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR,
|
return status;
|
||||||
status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by (subclasses of) BlackboardArtifactNode to add the Score property
|
* Used by (subclasses of) BlackboardArtifactNode to add the Score property
|
||||||
* to their sheets.
|
* to their sheets.
|
||||||
*
|
*
|
||||||
* @param sheetSet the modifiable Sheet.Set returned by
|
* @param sheetSet the modifiable Sheet.Set to add the property to
|
||||||
* Sheet.get(Sheet.PROPERTIES)
|
|
||||||
* @param tags the list of tags associated with the file
|
* @param tags the list of tags associated with the file
|
||||||
|
*
|
||||||
|
* @deprecated Use the GetSCOTask to get this data on a background
|
||||||
|
* thread..., and then update the property sheet asynchronously
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.score.name=S",
|
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.score.name=S",
|
||||||
"BlackboardArtifactNode.createSheet.score.displayName=S",
|
"BlackboardArtifactNode.createSheet.score.displayName=S",
|
||||||
@ -628,7 +669,21 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
"BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.",
|
"BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.",
|
||||||
"BlackboardArtifactNode.createSheet.notableTaggedItem.description=Result or associated file tagged with notable tag.",
|
"BlackboardArtifactNode.createSheet.notableTaggedItem.description=Result or associated file tagged with notable tag.",
|
||||||
"BlackboardArtifactNode.createSheet.noScore.description=No score"})
|
"BlackboardArtifactNode.createSheet.noScore.description=No score"})
|
||||||
protected final void addScoreProperty(Sheet.Set sheetSet, List<Tag> tags) {
|
@Deprecated
|
||||||
|
protected final void addScorePropertyAndDescription(Sheet.Set sheetSet, List<Tag> tags) {
|
||||||
|
Pair<DataResultViewerTable.Score, String> scoreAndDescription = getScorePropertyAndDescription(tags);
|
||||||
|
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoreAndDescription.getRight(), scoreAndDescription.getLeft()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the score property for the node.
|
||||||
|
*
|
||||||
|
* @param tags the list of tags associated with the file
|
||||||
|
*
|
||||||
|
* @return score property and description
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
|
||||||
Score score = Score.NO_SCORE;
|
Score score = Score.NO_SCORE;
|
||||||
String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
|
String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
|
||||||
if (associated instanceof AbstractFile) {
|
if (associated instanceof AbstractFile) {
|
||||||
@ -673,34 +728,61 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), description, score));
|
|
||||||
|
return Pair.of(score, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by (subclasses of) BlackboardArtifactNode to add the Occurrences
|
||||||
|
* property to their sheets.
|
||||||
|
*
|
||||||
|
* @param sheetSet the modifiable Sheet.Set to add the property to
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
*
|
||||||
|
* @deprecated Use the GetSCOTask to get this data on a background
|
||||||
|
* thread..., and then update the property sheet asynchronously
|
||||||
|
*/
|
||||||
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.count.name=O",
|
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.count.name=O",
|
||||||
"BlackboardArtifactNode.createSheet.count.displayName=O",
|
"BlackboardArtifactNode.createSheet.count.displayName=O",
|
||||||
"BlackboardArtifactNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated",
|
"BlackboardArtifactNode.createSheet.count.noCorrelationAttributes.description=No correlation properties found",
|
||||||
"BlackboardArtifactNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this artifact's associated file when the column was populated",
|
"BlackboardArtifactNode.createSheet.count.noCorrelationValues.description=Unable to find other occurrences because no value exists for the available correlation property",
|
||||||
"# {0} - occuranceCount",
|
"# {0} - occurenceCount",
|
||||||
"BlackboardArtifactNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value"})
|
"# {1} - attributeType",
|
||||||
|
"BlackboardArtifactNode.createSheet.count.description=There were {0} datasource(s) found with occurrences of the correlation value of type {1}"})
|
||||||
|
@Deprecated
|
||||||
protected final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute) {
|
protected final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute) {
|
||||||
Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting
|
Pair<Long, String> countAndDescription = getCountPropertyAndDescription(attribute, Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationAttributes_description());
|
||||||
String description = Bundle.BlackboardArtifactNode_createSheet_count_noCentralRepo_description();
|
sheetSet.put(
|
||||||
|
new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), countAndDescription.getRight(), countAndDescription.getLeft()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Occurrences property for the node.
|
||||||
|
*
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
* @param defaultDescription
|
||||||
|
*
|
||||||
|
* @return count and description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) {
|
||||||
|
Long count = -1L;
|
||||||
|
String description = defaultDescription;
|
||||||
try {
|
try {
|
||||||
//don't perform the query if there is no correlation value
|
//don't perform the query if there is no correlation value
|
||||||
if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
|
if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
|
||||||
count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attribute.getCorrelationType(), attribute.getCorrelationValue());
|
count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attribute.getCorrelationType(), attribute.getCorrelationValue());
|
||||||
description = Bundle.BlackboardArtifactNode_createSheet_count_description(count);
|
description = Bundle.BlackboardArtifactNode_createSheet_count_description(count, attribute.getCorrelationType().getDisplayName());
|
||||||
} else if (attribute != null) {
|
} else if (attribute != null) {
|
||||||
description = Bundle.BlackboardArtifactNode_createSheet_count_hashLookupNotRun_description();
|
description = Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationValues_description();
|
||||||
}
|
}
|
||||||
} catch (EamDbException ex) {
|
} catch (EamDbException ex) {
|
||||||
logger.log(Level.WARNING, "Error getting count of datasources with correlation attribute", ex);
|
logger.log(Level.WARNING, "Error getting count of datasources with correlation attribute", ex);
|
||||||
} catch (CorrelationAttributeNormalizationException ex) {
|
} catch (CorrelationAttributeNormalizationException ex) {
|
||||||
logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
|
logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
|
||||||
}
|
}
|
||||||
sheetSet.put(
|
return Pair.of(count, description);
|
||||||
new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), description, count));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSheet() {
|
private void updateSheet() {
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
AbstractAbstractFileNode.accessTimeColLbl=Access Time
|
AbstractAbstractFileNode.accessTimeColLbl=Access Time
|
||||||
AbstractAbstractFileNode.addFileProperty.desc=no description
|
|
||||||
AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.
|
AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.
|
||||||
AbstractAbstractFileNode.changeTimeColLbl=Change Time
|
AbstractAbstractFileNode.changeTimeColLbl=Change Time
|
||||||
AbstractAbstractFileNode.createdTimeColLbl=Created Time
|
AbstractAbstractFileNode.createdTimeColLbl=Created Time
|
||||||
AbstractAbstractFileNode.createSheet.comment.displayName=C
|
AbstractAbstractFileNode.createSheet.comment.displayName=C
|
||||||
AbstractAbstractFileNode.createSheet.comment.name=C
|
AbstractAbstractFileNode.createSheet.comment.name=C
|
||||||
# {0} - occuranceCount
|
# {0} - occurenceCount
|
||||||
AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value
|
AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurences of the MD5 correlation value
|
||||||
AbstractAbstractFileNode.createSheet.count.displayName=O
|
AbstractAbstractFileNode.createSheet.count.displayName=O
|
||||||
AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated
|
AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated
|
||||||
AbstractAbstractFileNode.createSheet.count.name=O
|
AbstractAbstractFileNode.createSheet.count.name=O
|
||||||
AbstractAbstractFileNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated
|
|
||||||
AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.
|
AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.
|
||||||
AbstractAbstractFileNode.createSheet.noScore.description=No score
|
AbstractAbstractFileNode.createSheet.noScore.description=No score
|
||||||
AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.
|
AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.
|
||||||
@ -37,13 +35,14 @@ AbstractAbstractFileNode.tagsProperty.displayName=Tags
|
|||||||
AbstractAbstractFileNode.typeDirColLbl=Type(Dir)
|
AbstractAbstractFileNode.typeDirColLbl=Type(Dir)
|
||||||
AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)
|
AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)
|
||||||
AbstractAbstractFileNode.useridColLbl=UserID
|
AbstractAbstractFileNode.useridColLbl=UserID
|
||||||
|
AbstractContentNode.nodescription=no description
|
||||||
|
AbstractContentNode.valueLoading=value loading
|
||||||
AbstractFsContentNode.noDesc.text=no description
|
AbstractFsContentNode.noDesc.text=no description
|
||||||
ArtifactStringContent.attrsTableHeader.sources=Source(s)
|
ArtifactStringContent.attrsTableHeader.sources=Source(s)
|
||||||
ArtifactStringContent.attrsTableHeader.type=Type
|
ArtifactStringContent.attrsTableHeader.type=Type
|
||||||
ArtifactStringContent.attrsTableHeader.value=Value
|
ArtifactStringContent.attrsTableHeader.value=Value
|
||||||
ArtifactStringContent.failedToGetAttributes.message=Failed to get some or all attributes from case database
|
ArtifactStringContent.failedToGetAttributes.message=Failed to get some or all attributes from case database
|
||||||
ArtifactStringContent.failedToGetSourcePath.message=Failed to get source file path from case database
|
ArtifactStringContent.failedToGetSourcePath.message=Failed to get source file path from case database
|
||||||
# {0} - node name
|
|
||||||
BaseChildFactory.NoSuchEventBusException.message=No event bus for node: {0}
|
BaseChildFactory.NoSuchEventBusException.message=No event bus for node: {0}
|
||||||
BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details
|
BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details
|
||||||
BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details
|
BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details
|
||||||
@ -53,12 +52,13 @@ BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type
|
|||||||
BlackboardArtifactNode.createSheet.artifactType.name=Result Type
|
BlackboardArtifactNode.createSheet.artifactType.name=Result Type
|
||||||
BlackboardArtifactNode.createSheet.comment.displayName=C
|
BlackboardArtifactNode.createSheet.comment.displayName=C
|
||||||
BlackboardArtifactNode.createSheet.comment.name=C
|
BlackboardArtifactNode.createSheet.comment.name=C
|
||||||
# {0} - occuranceCount
|
# {0} - occurenceCount
|
||||||
BlackboardArtifactNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value
|
# {1} - attributeType
|
||||||
|
BlackboardArtifactNode.createSheet.count.description=There were {0} datasource(s) found with occurrences of the correlation value of type {1}
|
||||||
BlackboardArtifactNode.createSheet.count.displayName=O
|
BlackboardArtifactNode.createSheet.count.displayName=O
|
||||||
BlackboardArtifactNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this artifact's associated file when the column was populated
|
|
||||||
BlackboardArtifactNode.createSheet.count.name=O
|
BlackboardArtifactNode.createSheet.count.name=O
|
||||||
BlackboardArtifactNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated
|
BlackboardArtifactNode.createSheet.count.noCorrelationAttributes.description=No correlation properties found
|
||||||
|
BlackboardArtifactNode.createSheet.count.noCorrelationValues.description=Unable to find other occurrences because no value exists for the available correlation property
|
||||||
BlackboardArtifactNode.createSheet.fileSize.displayName=Size
|
BlackboardArtifactNode.createSheet.fileSize.displayName=Size
|
||||||
BlackboardArtifactNode.createSheet.fileSize.name=Size
|
BlackboardArtifactNode.createSheet.fileSize.name=Size
|
||||||
BlackboardArtifactNode.createSheet.interestingResult.description=Result has an interesting result associated with it.
|
BlackboardArtifactNode.createSheet.interestingResult.description=Result has an interesting result associated with it.
|
||||||
@ -114,6 +114,8 @@ FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype
|
|||||||
FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description
|
FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description
|
||||||
FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type
|
FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type
|
||||||
FileTypesByMimeTypeNode.createSheet.mediaType.name=Type
|
FileTypesByMimeTypeNode.createSheet.mediaType.name=Type
|
||||||
|
GetSCOTask.occurrences.defaultDescription=No correlation properties found
|
||||||
|
GetSCOTask.occurrences.multipleProperties=Multiple different correlation properties exist for this result
|
||||||
ImageNode.action.runIngestMods.text=Run Ingest Modules
|
ImageNode.action.runIngestMods.text=Run Ingest Modules
|
||||||
ImageNode.createSheet.deviceId.desc=Device ID of the image
|
ImageNode.createSheet.deviceId.desc=Device ID of the image
|
||||||
ImageNode.createSheet.deviceId.displayName=Device ID
|
ImageNode.createSheet.deviceId.displayName=Device ID
|
||||||
@ -260,10 +262,10 @@ ImageNode.getActions.viewInNewWin.text=View in New Window
|
|||||||
ImageNode.createSheet.name.name=Name
|
ImageNode.createSheet.name.name=Name
|
||||||
ImageNode.createSheet.name.displayName=Name
|
ImageNode.createSheet.name.displayName=Name
|
||||||
ImageNode.createSheet.name.desc=no description
|
ImageNode.createSheet.name.desc=no description
|
||||||
Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null\!
|
Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null!
|
||||||
Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""\!
|
Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""!
|
||||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n\nDetails: {0}
|
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed!\n\nDetails: {0}
|
||||||
Installer.tskLibErr.err=Fatal Error\!
|
Installer.tskLibErr.err=Fatal Error!
|
||||||
InterestingHits.interestingItems.text=INTERESTING ITEMS
|
InterestingHits.interestingItems.text=INTERESTING ITEMS
|
||||||
InterestingHits.displayName.text=Interesting Items
|
InterestingHits.displayName.text=Interesting Items
|
||||||
InterestingHits.createSheet.name.name=Name
|
InterestingHits.createSheet.name.name=Name
|
||||||
|
@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.actions.ReplaceBlackboardArtifactTagAction;
|
|||||||
import org.sleuthkit.autopsy.actions.ReplaceContentTagAction;
|
import org.sleuthkit.autopsy.actions.ReplaceContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
@ -92,6 +93,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -119,6 +121,7 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -155,6 +158,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());//
|
actionsList.add(ExtractAction.getInstance());//
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -189,6 +193,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -223,6 +228,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -257,6 +263,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -291,6 +298,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -325,6 +333,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -379,6 +388,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -415,6 +425,7 @@ public class DataModelActionsFactory {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
|
@ -57,7 +57,7 @@ public class DataSourcesNode extends DisplayableItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DataSourcesNode(long dsObjId) {
|
public DataSourcesNode(long dsObjId) {
|
||||||
super(Children.create(new DataSourcesNodeChildren(dsObjId), true), Lookups.singleton(NAME));
|
super(Children.create(new DataSourcesNodeChildren(dsObjId), false), Lookups.singleton(NAME));
|
||||||
displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME;
|
displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -37,7 +36,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -59,7 +57,7 @@ import org.sleuthkit.datamodel.VirtualDirectory;
|
|||||||
public class DeletedContent implements AutopsyVisitableItem {
|
public class DeletedContent implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
@NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System",
|
@NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System",
|
||||||
"DeletedContent.allDelFilter.text=All"})
|
"DeletedContent.allDelFilter.text=All"})
|
||||||
@ -105,11 +103,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
public DeletedContent(SleuthkitCase skCase, long dsObjId) {
|
public DeletedContent(SleuthkitCase skCase, long dsObjId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = dsObjId;
|
this.filteringDSObjId = dsObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
long filteringDataSourceObjId() {
|
long filteringDataSourceObjId() {
|
||||||
return this.datasourceObjId;
|
return this.filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -439,7 +437,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
|
@ -28,6 +28,7 @@ import org.openide.util.Utilities;
|
|||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
@ -89,6 +90,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(ViewFileInTimelineAction.createViewFileAction(content));
|
actionsList.add(ViewFileInTimelineAction.createViewFileAction(content));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(new RunIngestModulesAction(content));
|
actionsList.add(new RunIngestModulesAction(content));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
|
@ -28,7 +28,6 @@ import java.util.HashMap;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -40,7 +39,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -88,7 +86,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final EmailResults emailResults;
|
private final EmailResults emailResults;
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -110,7 +108,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public EmailExtracted(SleuthkitCase skCase, long objId) {
|
public EmailExtracted(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
emailResults = new EmailResults();
|
emailResults = new EmailResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,8 +160,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
+ "attribute_type_id=" + pathAttrId //NON-NLS
|
+ "attribute_type_id=" + pathAttrId //NON-NLS
|
||||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
||||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||||
|
@ -26,7 +26,6 @@ import java.util.Comparator;
|
|||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
@ -35,7 +34,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -64,7 +62,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
private SleuthkitCase skCase; // set to null after case has been closed
|
private SleuthkitCase skCase; // set to null after case has been closed
|
||||||
private Blackboard blackboard;
|
private Blackboard blackboard;
|
||||||
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
|
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs extracted content object
|
* Constructs extracted content object
|
||||||
@ -83,7 +81,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public ExtractedContent(SleuthkitCase skCase, long objId) {
|
public ExtractedContent(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
this.blackboard = skCase.getBlackboard();
|
this.blackboard = skCase.getBlackboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,8 +305,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
protected boolean createKeys(List<BlackboardArtifact.Type> list) {
|
protected boolean createKeys(List<BlackboardArtifact.Type> list) {
|
||||||
if (skCase != null) {
|
if (skCase != null) {
|
||||||
try {
|
try {
|
||||||
List<BlackboardArtifact.Type> types = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
|
List<BlackboardArtifact.Type> types = (filteringDSObjId > 0) ?
|
||||||
blackboard.getArtifactTypesInUse(datasourceObjId) :
|
blackboard.getArtifactTypesInUse(filteringDSObjId) :
|
||||||
skCase.getArtifactTypesInUse() ;
|
skCase.getArtifactTypesInUse() ;
|
||||||
|
|
||||||
types.removeAll(doNotShow);
|
types.removeAll(doNotShow);
|
||||||
@ -372,8 +370,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
// a performance increase might be had by adding a
|
// a performance increase might be had by adding a
|
||||||
// "getBlackboardArtifactCount()" method to skCase
|
// "getBlackboardArtifactCount()" method to skCase
|
||||||
try {
|
try {
|
||||||
this.childCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
|
this.childCount = (filteringDSObjId > 0) ?
|
||||||
blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) :
|
blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId) :
|
||||||
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
||||||
} catch (TskException ex) {
|
} catch (TskException ex) {
|
||||||
Logger.getLogger(TypeNode.class.getName())
|
Logger.getLogger(TypeNode.class.getName())
|
||||||
@ -501,8 +499,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
protected List<BlackboardArtifact> makeKeys() {
|
protected List<BlackboardArtifact> makeKeys() {
|
||||||
if (skCase != null) {
|
if (skCase != null) {
|
||||||
try {
|
try {
|
||||||
return Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
return (filteringDSObjId > 0)
|
||||||
? blackboard.getArtifacts(type.getTypeID(), datasourceObjId)
|
? blackboard.getArtifacts(type.getTypeID(), filteringDSObjId)
|
||||||
: skCase.getBlackboardArtifacts(type.getTypeID());
|
: skCase.getBlackboardArtifacts(type.getTypeID());
|
||||||
} catch (TskException ex) {
|
} catch (TskException ex) {
|
||||||
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
||||||
|
@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
|||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
@ -173,6 +174,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(null); // Creates an item separator
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // Creates an item separator
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
@ -24,7 +24,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -37,9 +36,7 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -63,7 +60,7 @@ import org.sleuthkit.datamodel.VirtualDirectory;
|
|||||||
public class FileSize implements AutopsyVisitableItem {
|
public class FileSize implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
public enum FileSizeFilter implements AutopsyVisitableItem {
|
public enum FileSizeFilter implements AutopsyVisitableItem {
|
||||||
|
|
||||||
@ -105,7 +102,7 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
public FileSize(SleuthkitCase skCase, long dsObjId) {
|
public FileSize(SleuthkitCase skCase, long dsObjId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = dsObjId;
|
this.filteringDSObjId = dsObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -118,7 +115,7 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long filteringDataSourceObjId() {
|
long filteringDataSourceObjId() {
|
||||||
return this.datasourceObjId;
|
return this.filteringDSObjId;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Root node. Children are nodes for specific sizes.
|
* Root node. Children are nodes for specific sizes.
|
||||||
@ -437,7 +434,7 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
|
query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
|
||||||
|
|
||||||
// filter by datasource if indicated in case preferences
|
// filter by datasource if indicated in case preferences
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -39,7 +38,6 @@ import org.openide.util.NbBundle;
|
|||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -366,7 +364,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
+ (UserPreferences.hideKnownFilesInViewsTree()
|
+ (UserPreferences.hideKnownFilesInViewsTree()
|
||||||
? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
|
? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
|
||||||
: " ")
|
: " ")
|
||||||
+ (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
+ (filteringDataSourceObjId() > 0
|
||||||
? " AND data_source_obj_id = " + filteringDataSourceObjId()
|
? " AND data_source_obj_id = " + filteringDataSourceObjId()
|
||||||
: " ")
|
: " ")
|
||||||
+ " AND (extension IN (" + filter.getFilter().stream()
|
+ " AND (extension IN (" + filter.getFilter().stream()
|
||||||
|
@ -28,7 +28,6 @@ import java.util.EnumSet;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -42,7 +41,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
|
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
|
||||||
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
|
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
|
||||||
@ -103,7 +101,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
|||||||
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
|
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
|
||||||
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
|
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
|
||||||
+ "))"
|
+ "))"
|
||||||
+ ( Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
|
+ ( (filteringDataSourceObjId() > 0) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
|
||||||
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
|
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
106
Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java
Normal file
106
Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.List;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
|
||||||
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Background task to get Score, Comment and Occurrences values for an Abstract
|
||||||
|
* content node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class GetSCOTask implements Runnable {
|
||||||
|
|
||||||
|
private final WeakReference<AbstractContentNode<?>> weakNodeRef;
|
||||||
|
private final PropertyChangeListener listener;
|
||||||
|
|
||||||
|
GetSCOTask(WeakReference<AbstractContentNode<?>> weakContentRef, PropertyChangeListener listener) {
|
||||||
|
this.weakNodeRef = weakContentRef;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Messages({"GetSCOTask.occurrences.defaultDescription=No correlation properties found",
|
||||||
|
"GetSCOTask.occurrences.multipleProperties=Multiple different correlation properties exist for this result"})
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
AbstractContentNode<?> contentNode = weakNodeRef.get();
|
||||||
|
|
||||||
|
//Check for stale reference
|
||||||
|
if (contentNode == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the SCO column values
|
||||||
|
List<Tag> tags = contentNode.getAllTagsFromDatabase();
|
||||||
|
CorrelationAttributeInstance fileAttribute = contentNode.getCorrelationAttributeInstance();
|
||||||
|
|
||||||
|
SCOData scoData = new SCOData();
|
||||||
|
scoData.setScoreAndDescription(contentNode.getScorePropertyAndDescription(tags));
|
||||||
|
scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute));
|
||||||
|
if (!UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
|
||||||
|
CorrelationAttributeInstance occurrencesAttribute = null;
|
||||||
|
String description = Bundle.GetSCOTask_occurrences_defaultDescription();
|
||||||
|
if (contentNode instanceof BlackboardArtifactNode) {
|
||||||
|
BlackboardArtifact bbArtifact = ((BlackboardArtifactNode) contentNode).getArtifact();
|
||||||
|
//for specific artifact types we still want to display information for the file instance correlation attribute
|
||||||
|
if (bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()
|
||||||
|
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
||||||
|
occurrencesAttribute = fileAttribute;
|
||||||
|
} else {
|
||||||
|
List<CorrelationAttributeInstance> listOfPossibleAttributes = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false);
|
||||||
|
if (listOfPossibleAttributes.size() > 1) {
|
||||||
|
//Don't display anything if there is more than 1 correlation property for an artifact but let the user know
|
||||||
|
description = Bundle.GetSCOTask_occurrences_multipleProperties();
|
||||||
|
} else if (!listOfPossibleAttributes.isEmpty()) {
|
||||||
|
//there should only be one item in the list
|
||||||
|
occurrencesAttribute = listOfPossibleAttributes.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//use the file instance correlation attribute if the node is not a BlackboardArtifactNode
|
||||||
|
occurrencesAttribute = fileAttribute;
|
||||||
|
}
|
||||||
|
scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(occurrencesAttribute, description));
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal SCO data is available.
|
||||||
|
if (listener != null) {
|
||||||
|
listener.propertyChange(new PropertyChangeEvent(
|
||||||
|
AutopsyEvent.SourceType.LOCAL.toString(),
|
||||||
|
AbstractAbstractFileNode.NodeSpecificEvents.SCO_AVAILABLE.toString(),
|
||||||
|
null, scoData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,6 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -42,7 +41,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -65,7 +63,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
|
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final HashsetResults hashsetResults;
|
private final HashsetResults hashsetResults;
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,7 +85,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public HashsetHits(SleuthkitCase skCase, long objId) {
|
public HashsetHits(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
hashsetResults = new HashsetResults();
|
hashsetResults = new HashsetResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +140,8 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
+ "attribute_type_id=" + setNameId //NON-NLS
|
+ "attribute_type_id=" + setNameId //NON-NLS
|
||||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
||||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||||
|
@ -28,12 +28,15 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction;
|
import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
|
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
|
||||||
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
|
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
|
||||||
@ -47,6 +50,7 @@ import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
|||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
|
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
|
||||||
|
import org.sleuthkit.datamodel.Tag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to represent the "Node" for the image. The children of
|
* This class is used to represent the "Node" for the image. The children of
|
||||||
@ -250,4 +254,74 @@ public class ImageNode extends AbstractContentNode<Image> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and returns a list of all tags associated with this content node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @return list of tags associated with the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected List<Tag> getAllTagsFromDatabase() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns correlation attribute instance for the underlying content of the
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @return correlation attribute instance for the underlying content of the
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Score property for the node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @param tags list of tags.
|
||||||
|
*
|
||||||
|
* @return Score property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
|
||||||
|
return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns comment property for the node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @param tags list of tags
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
*
|
||||||
|
* @return Comment property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||||
|
return DataResultViewerTable.HasCommentStatus.NO_COMMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns occurrences/count property for the node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
* @param defaultDescription a description to use when none is determined by
|
||||||
|
* the getCountPropertyAndDescription method
|
||||||
|
*
|
||||||
|
* @return count property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) {
|
||||||
|
return Pair.of(-1L, NO_DESCR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -42,7 +41,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -61,7 +59,7 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
|
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final InterestingResults interestingResults = new InterestingResults();
|
private final InterestingResults interestingResults = new InterestingResults();
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -82,7 +80,7 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public InterestingHits(SleuthkitCase skCase, long objId) {
|
public InterestingHits(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
interestingResults.update();
|
interestingResults.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,8 +131,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
+ "attribute_type_id=" + setNameId //NON-NLS
|
+ "attribute_type_id=" + setNameId //NON-NLS
|
||||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
|
||||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||||
|
@ -31,7 +31,6 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -45,7 +44,6 @@ import org.openide.util.Lookup;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||||
@ -76,7 +74,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final KeywordResults keywordResults;
|
private final KeywordResults keywordResults;
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String used in the instance MAP so that exact matches and substring can
|
* String used in the instance MAP so that exact matches and substring can
|
||||||
@ -123,7 +121,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public KeywordHits(SleuthkitCase skCase, long objId) {
|
public KeywordHits(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
keywordResults = new KeywordResults();
|
keywordResults = new KeywordResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,8 +342,8 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY;
|
String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY;
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) {
|
try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) {
|
||||||
|
@ -29,6 +29,7 @@ import org.openide.util.Utilities;
|
|||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
@ -105,6 +106,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
|||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
@ -82,6 +83,7 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
|
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import org.openide.nodes.Children;
|
|||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitVisitableItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Children implementation for the root node of a ContentNode tree. Accepts a
|
* Children implementation for the root node of a ContentNode tree. Accepts a
|
||||||
@ -34,6 +35,7 @@ public class RootContentChildren extends Children.Keys<Object> {
|
|||||||
|
|
||||||
private final Collection<? extends Object> contentKeys;
|
private final Collection<? extends Object> contentKeys;
|
||||||
private final CreateAutopsyNodeVisitor createAutopsyNodeVisitor = new CreateAutopsyNodeVisitor();
|
private final CreateAutopsyNodeVisitor createAutopsyNodeVisitor = new CreateAutopsyNodeVisitor();
|
||||||
|
private final CreateSleuthkitNodeVisitor createSleuthkitNodeVisitor = new CreateSleuthkitNodeVisitor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param contentKeys root Content objects for the Node tree
|
* @param contentKeys root Content objects for the Node tree
|
||||||
@ -68,7 +70,7 @@ public class RootContentChildren extends Children.Keys<Object> {
|
|||||||
if (key instanceof AutopsyVisitableItem) {
|
if (key instanceof AutopsyVisitableItem) {
|
||||||
return new Node[] {((AutopsyVisitableItem)key).accept(createAutopsyNodeVisitor)};
|
return new Node[] {((AutopsyVisitableItem)key).accept(createAutopsyNodeVisitor)};
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return new Node[] {((SleuthkitVisitableItem)key).accept(createSleuthkitNodeVisitor)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java
Normal file
56
Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container to bag the S C & O data for an abstract file node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SCOData {
|
||||||
|
|
||||||
|
private Pair<DataResultViewerTable.Score, String> scoreAndDescription = null;
|
||||||
|
private DataResultViewerTable.HasCommentStatus comment = null;
|
||||||
|
private Pair<Long, String> countAndDescription = null;
|
||||||
|
|
||||||
|
Pair<DataResultViewerTable.Score, String> getScoreAndDescription() {
|
||||||
|
return scoreAndDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataResultViewerTable.HasCommentStatus getComment() {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair<Long, String> getCountAndDescription() {
|
||||||
|
return countAndDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setScoreAndDescription(Pair<DataResultViewerTable.Score, String> scoreAndDescription) {
|
||||||
|
this.scoreAndDescription = scoreAndDescription;
|
||||||
|
}
|
||||||
|
void setComment(DataResultViewerTable.HasCommentStatus comment) {
|
||||||
|
this.comment = comment;
|
||||||
|
}
|
||||||
|
void setCountAndDescription(Pair<Long, String> countAndDescription) {
|
||||||
|
this.countAndDescription = countAndDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,6 +28,7 @@ import org.openide.util.Utilities;
|
|||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
@ -85,6 +86,7 @@ public class SlackFileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
NbBundle.getMessage(this.getClass(), "SlackFileNode.getActions.viewInNewWin.text"), this));
|
NbBundle.getMessage(this.getClass(), "SlackFileNode.getActions.viewInNewWin.text"), this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import javax.swing.Action;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction;
|
import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
|
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
@ -61,6 +62,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<Spec
|
|||||||
Bundle.SpecialDirectoryNode_getActions_viewInNewWin_text(), this));
|
Bundle.SpecialDirectoryNode_getActions_viewInNewWin_text(), this));
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
|
actions.add(ExportCSVAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
|
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
|
||||||
if (content.isDataSource()) {
|
if (content.isDataSource()) {
|
||||||
|
@ -23,7 +23,6 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -35,7 +34,6 @@ import org.openide.nodes.Sheet;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
@ -61,14 +59,14 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS
|
private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS
|
||||||
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
|
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
|
||||||
|
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
Tags() {
|
Tags() {
|
||||||
this(0);
|
this(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tags(long dsObjId) {
|
Tags(long dsObjId) {
|
||||||
this.datasourceObjId = dsObjId;
|
this.filteringDSObjId = dsObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,7 +79,7 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long filteringDataSourceObjId() {
|
long filteringDataSourceObjId() {
|
||||||
return this.datasourceObjId;
|
return this.filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -156,7 +154,7 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
||||||
|
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
|
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
|
||||||
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
|
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
|
||||||
@ -219,7 +217,7 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
* @param objId data source object id
|
* @param objId data source object id
|
||||||
*/
|
*/
|
||||||
TagNameNodeFactory(long objId) {
|
TagNameNodeFactory(long objId) {
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,12 +244,12 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
List<TagName> tagNamesInUse;
|
List<TagName> tagNamesInUse;
|
||||||
if (UserPreferences.showOnlyCurrentUserTags()) {
|
if (UserPreferences.showOnlyCurrentUserTags()) {
|
||||||
String userName = System.getProperty(USER_NAME_PROPERTY);
|
String userName = System.getProperty(USER_NAME_PROPERTY);
|
||||||
tagNamesInUse = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
tagNamesInUse = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(datasourceObjId, userName)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(filteringDSObjId, userName)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName);
|
||||||
} else {
|
} else {
|
||||||
tagNamesInUse = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
tagNamesInUse = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(filteringDSObjId)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
|
||||||
}
|
}
|
||||||
Collections.sort(tagNamesInUse);
|
Collections.sort(tagNamesInUse);
|
||||||
@ -303,17 +301,17 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
|
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
|
||||||
if (UserPreferences.showOnlyCurrentUserTags()) {
|
if (UserPreferences.showOnlyCurrentUserTags()) {
|
||||||
String userName = System.getProperty(USER_NAME_PROPERTY);
|
String userName = System.getProperty(USER_NAME_PROPERTY);
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName);
|
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, filteringDSObjId, userName);
|
||||||
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName);
|
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, filteringDSObjId, userName);
|
||||||
} else {
|
} else {
|
||||||
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, userName);
|
tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, userName);
|
||||||
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
|
tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId);
|
tagsCount = tm.getContentTagsCountByTagName(tagName, filteringDSObjId);
|
||||||
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId);
|
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, filteringDSObjId);
|
||||||
} else {
|
} else {
|
||||||
tagsCount = tm.getContentTagsCountByTagName(tagName);
|
tagsCount = tm.getContentTagsCountByTagName(tagName);
|
||||||
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
|
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
|
||||||
@ -424,12 +422,12 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
if (UserPreferences.showOnlyCurrentUserTags()) {
|
if (UserPreferences.showOnlyCurrentUserTags()) {
|
||||||
String userName = System.getProperty(USER_NAME_PROPERTY);
|
String userName = System.getProperty(USER_NAME_PROPERTY);
|
||||||
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
tagsCount = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, filteringDSObjId, userName)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName);
|
||||||
} else {
|
} else {
|
||||||
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
tagsCount = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, filteringDSObjId)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
@ -486,8 +484,8 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
protected boolean createKeys(List<ContentTag> keys) {
|
protected boolean createKeys(List<ContentTag> keys) {
|
||||||
// Use the content tags bearing the specified tag name as the keys.
|
// Use the content tags bearing the specified tag name as the keys.
|
||||||
try {
|
try {
|
||||||
List<ContentTag> contentTags = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
List<ContentTag> contentTags = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, filteringDSObjId)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
|
||||||
if (UserPreferences.showOnlyCurrentUserTags()) {
|
if (UserPreferences.showOnlyCurrentUserTags()) {
|
||||||
String userName = System.getProperty(USER_NAME_PROPERTY);
|
String userName = System.getProperty(USER_NAME_PROPERTY);
|
||||||
@ -544,12 +542,12 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
try {
|
try {
|
||||||
if (UserPreferences.showOnlyCurrentUserTags()) {
|
if (UserPreferences.showOnlyCurrentUserTags()) {
|
||||||
String userName = System.getProperty(USER_NAME_PROPERTY);
|
String userName = System.getProperty(USER_NAME_PROPERTY);
|
||||||
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
tagsCount = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, filteringDSObjId, userName)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName);
|
||||||
} else {
|
} else {
|
||||||
tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
tagsCount = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, filteringDSObjId)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
@ -606,8 +604,8 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
|
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
|
||||||
try {
|
try {
|
||||||
// Use the blackboard artifact tags bearing the specified tag name as the keys.
|
// Use the blackboard artifact tags bearing the specified tag name as the keys.
|
||||||
List<BlackboardArtifactTag> artifactTags = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
|
List<BlackboardArtifactTag> artifactTags = (filteringDSObjId > 0)
|
||||||
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId)
|
? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, filteringDSObjId)
|
||||||
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
|
: Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
|
||||||
if (UserPreferences.showOnlyCurrentUserTags()) {
|
if (UserPreferences.showOnlyCurrentUserTags()) {
|
||||||
String userName = System.getProperty(USER_NAME_PROPERTY);
|
String userName = System.getProperty(USER_NAME_PROPERTY);
|
||||||
|
@ -25,10 +25,14 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
|
||||||
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
|
import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
|
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
@ -39,12 +43,14 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
import org.sleuthkit.datamodel.Volume;
|
import org.sleuthkit.datamodel.Volume;
|
||||||
import org.sleuthkit.autopsy.directorytree.FileSystemDetailsAction;
|
import org.sleuthkit.autopsy.directorytree.FileSystemDetailsAction;
|
||||||
|
import org.sleuthkit.datamodel.Tag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to represent the "Node" for the volume. Its child is the
|
* This class is used to represent the "Node" for the volume. Its child is the
|
||||||
* root directory of a file system
|
* root directory of a file system
|
||||||
*/
|
*/
|
||||||
public class VolumeNode extends AbstractContentNode<Volume> {
|
public class VolumeNode extends AbstractContentNode<Volume> {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(VolumeNode.class.getName());
|
private static final Logger logger = Logger.getLogger(VolumeNode.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,4 +218,75 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
|||||||
public String getItemType() {
|
public String getItemType() {
|
||||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and returns a list of all tags associated with this content node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @return list of tags associated with the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected List<Tag> getAllTagsFromDatabase() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns correlation attribute instance for the underlying content of the
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @return correlation attribute instance for the underlying content of the
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Score property for the node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @param tags list of tags.
|
||||||
|
*
|
||||||
|
* @return Score property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
|
||||||
|
return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns comment property for the node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @param tags list of tags
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
*
|
||||||
|
* @return Comment property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||||
|
return DataResultViewerTable.HasCommentStatus.NO_COMMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns occurrences/count property for the node.
|
||||||
|
*
|
||||||
|
* Null implementation of an abstract method.
|
||||||
|
*
|
||||||
|
* @param attribute correlation attribute instance
|
||||||
|
* @param defaultDescription a description to use when none is determined by
|
||||||
|
* the getCountPropertyAndDescription method
|
||||||
|
*
|
||||||
|
* @return count property for the underlying content of the node.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) {
|
||||||
|
return Pair.of(-1L, NO_DESCR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,9 +57,7 @@ import org.openide.util.NbBundle;
|
|||||||
import org.openide.util.Utilities;
|
import org.openide.util.Utilities;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
|
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
|
||||||
@ -96,7 +94,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
final public static String NAME = Bundle.AccountsRootNode_name();
|
final public static String NAME = Bundle.AccountsRootNode_name();
|
||||||
|
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final long datasourceObjId;
|
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
||||||
|
|
||||||
private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus");
|
private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus");
|
||||||
|
|
||||||
@ -123,7 +121,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public Accounts(SleuthkitCase skCase, long objId) {
|
public Accounts(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.datasourceObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
|
|
||||||
this.rejectActionInstance = new RejectAccounts();
|
this.rejectActionInstance = new RejectAccounts();
|
||||||
this.approveActionInstance = new ApproveAccounts();
|
this.approveActionInstance = new ApproveAccounts();
|
||||||
@ -153,8 +151,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
* based on the CasePreferences groupItemsInTreeByDataSource setting
|
* based on the CasePreferences groupItemsInTreeByDataSource setting
|
||||||
*/
|
*/
|
||||||
private String getFilterByDataSourceClause() {
|
private String getFilterByDataSourceClause() {
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (filteringDSObjId > 0) {
|
||||||
return " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " ";
|
return " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
return " ";
|
return " ";
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
CSVWriter.done.notifyMsg.error=Error exporting to CSV file
|
||||||
|
# {0} - Output file
|
||||||
|
CSVWriter.done.notifyMsg.success=Wrote to {0}
|
||||||
|
CSVWriter.progress.cancelling=Cancelling
|
||||||
|
CSVWriter.progress.extracting=Exporting to CSV file
|
||||||
CTL_DirectoryTreeTopComponent=Directory Tree
|
CTL_DirectoryTreeTopComponent=Directory Tree
|
||||||
DataResultFilterNode.viewSourceArtifact.text=View Source Result
|
DataResultFilterNode.viewSourceArtifact.text=View Source Result
|
||||||
# {0} - dataSourceCount
|
# {0} - dataSourceCount
|
||||||
@ -5,6 +10,11 @@ DirectoryTreeTopComponent.componentOpened.groupDataSources.text=This case contai
|
|||||||
DirectoryTreeTopComponent.componentOpened.groupDataSources.title=Group by data source?
|
DirectoryTreeTopComponent.componentOpened.groupDataSources.title=Group by data source?
|
||||||
DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.
|
DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.
|
||||||
DirectoryTreeTopComponent.resultsView.title=Listing
|
DirectoryTreeTopComponent.resultsView.title=Listing
|
||||||
|
ExportCSV.saveNodesToCSV.empty=No data to export
|
||||||
|
# {0} - Output file
|
||||||
|
ExportCSV.saveNodesToCSV.fileExists=File {0} already exists
|
||||||
|
ExportCSV.saveNodesToCSV.noCurrentCase=No open case available
|
||||||
|
ExportCSV.title.text=Export selected rows to CSV
|
||||||
ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened.
|
ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened.
|
||||||
ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.
|
ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.
|
||||||
ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.
|
ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.
|
||||||
|
@ -372,6 +372,7 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
}
|
}
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
@ -125,6 +125,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList;
|
return actionsList;
|
||||||
}
|
}
|
||||||
@ -142,6 +143,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList;
|
return actionsList;
|
||||||
}
|
}
|
||||||
@ -150,6 +152,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final DerivedFile d) {
|
public List<? extends Action> visit(final DerivedFile d) {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
final Collection<AbstractFile> selectedFilesList =
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
@ -166,6 +169,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final LocalFile d) {
|
public List<? extends Action> visit(final LocalFile d) {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
final Collection<AbstractFile> selectedFilesList =
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
@ -182,6 +186,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
final Collection<AbstractFile> selectedFilesList =
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
@ -0,0 +1,360 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this content 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.directorytree;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
|
import org.openide.util.Cancellable;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Node.PropertySet;
|
||||||
|
import org.openide.nodes.Node.Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports CSV version of result nodes to a location selected by the user.
|
||||||
|
*/
|
||||||
|
public final class ExportCSVAction extends AbstractAction {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ExportCSVAction.class.getName());
|
||||||
|
private final static String DEFAULT_FILENAME = "Results";
|
||||||
|
private final static List<String> columnsToSkip = Arrays.asList(AbstractFilePropertyType.SCORE.toString(),
|
||||||
|
AbstractFilePropertyType.COMMENT.toString(), AbstractFilePropertyType.OCCURRENCES.toString());
|
||||||
|
|
||||||
|
private static String userDefinedExportPath;
|
||||||
|
|
||||||
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
|
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||||
|
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||||
|
private static ExportCSVAction instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an instance of the Action. See above for why
|
||||||
|
* the class is a singleton.
|
||||||
|
*
|
||||||
|
* @return the instance
|
||||||
|
*/
|
||||||
|
public static synchronized ExportCSVAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new ExportCSVAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor for the action.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({"ExportCSV.title.text=Export selected rows to CSV"})
|
||||||
|
private ExportCSVAction() {
|
||||||
|
super(Bundle.ExportCSV_title_text());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks user to choose destination, then extracts content to destination
|
||||||
|
* (recursing on directories).
|
||||||
|
*
|
||||||
|
* @param e The action event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Collection<? extends Node> selectedNodes = Utilities.actionsGlobalContext().lookupAll(Node.class);
|
||||||
|
saveNodesToCSV(selectedNodes, (Component)e.getSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the selected nodes to a CSV file
|
||||||
|
*
|
||||||
|
* @param nodesToExport the nodes to save
|
||||||
|
* @param component
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"# {0} - Output file",
|
||||||
|
"ExportCSV.saveNodesToCSV.fileExists=File {0} already exists",
|
||||||
|
"ExportCSV.saveNodesToCSV.noCurrentCase=No open case available",
|
||||||
|
"ExportCSV.saveNodesToCSV.empty=No data to export"})
|
||||||
|
public static void saveNodesToCSV(Collection<? extends Node> nodesToExport, Component component) {
|
||||||
|
|
||||||
|
if (nodesToExport.isEmpty()) {
|
||||||
|
MessageNotifyUtil.Message.info(Bundle.ExportCSV_saveNodesToCSV_empty());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Set up the file chooser with a default name and either the Export
|
||||||
|
// folder or the last used folder.
|
||||||
|
String fileName = getDefaultOutputFileName(nodesToExport.iterator().next().getParentNode());
|
||||||
|
JFileChooser fileChooser = new JFileChooser();
|
||||||
|
fileChooser.setCurrentDirectory(new File(getExportDirectory(Case.getCurrentCaseThrows())));
|
||||||
|
fileChooser.setSelectedFile(new File(fileName));
|
||||||
|
fileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv"));
|
||||||
|
|
||||||
|
int returnVal = fileChooser.showSaveDialog(component);
|
||||||
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||||
|
|
||||||
|
// Get the file name, appending .csv if necessary
|
||||||
|
File selectedFile = fileChooser.getSelectedFile();
|
||||||
|
if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS
|
||||||
|
selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the directory used for next time
|
||||||
|
updateExportDirectory(selectedFile.getParent(), Case.getCurrentCaseThrows());
|
||||||
|
|
||||||
|
if (selectedFile.exists()) {
|
||||||
|
logger.log(Level.SEVERE, "File {0} already exists", selectedFile.getAbsolutePath()); //NON-NLS
|
||||||
|
MessageNotifyUtil.Message.info(Bundle.ExportCSV_saveNodesToCSV_fileExists(selectedFile));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWriter writer = new CSVWriter(nodesToExport, selectedFile);
|
||||||
|
writer.execute();
|
||||||
|
}
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
JOptionPane.showMessageDialog(component, Bundle.ExportCSV_saveNodesToCSV_noCurrentCase());
|
||||||
|
logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a default name for the CSV output.
|
||||||
|
*
|
||||||
|
* @param parent The parent node for the selected nodes
|
||||||
|
*
|
||||||
|
* @return the default name
|
||||||
|
*/
|
||||||
|
private static String getDefaultOutputFileName(Node parent) {
|
||||||
|
String dateStr = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS", Calendar.getInstance());
|
||||||
|
|
||||||
|
if (parent != null) {
|
||||||
|
// The first value in the property set is generally a reasonable name
|
||||||
|
for (PropertySet set : parent.getPropertySets()) {
|
||||||
|
for (Property<?> prop : set.getProperties()) {
|
||||||
|
try {
|
||||||
|
String parentName = prop.getValue().toString();
|
||||||
|
|
||||||
|
// Strip off the count (if present)
|
||||||
|
parentName = parentName.replaceAll("\\([0-9]+\\)$", "");
|
||||||
|
|
||||||
|
// Strip out any invalid characters
|
||||||
|
parentName = parentName.replaceAll("[\\\\/:*?\"<>|]", "_");
|
||||||
|
|
||||||
|
return parentName + " " + dateStr;
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to get property set value as string", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEFAULT_FILENAME + " " + dateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the export directory path.
|
||||||
|
*
|
||||||
|
* @param openCase The current case.
|
||||||
|
*
|
||||||
|
* @return The export directory path.
|
||||||
|
*/
|
||||||
|
private static String getExportDirectory(Case openCase) {
|
||||||
|
String caseExportPath = openCase.getExportDirectory();
|
||||||
|
|
||||||
|
if (userDefinedExportPath == null) {
|
||||||
|
return caseExportPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(userDefinedExportPath);
|
||||||
|
if (file.exists() == false || file.isDirectory() == false) {
|
||||||
|
return caseExportPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return userDefinedExportPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the default export directory. If the directory path matches the
|
||||||
|
* case export directory, then the directory used will always match the
|
||||||
|
* export directory of any given case. Otherwise, the path last used will be
|
||||||
|
* saved.
|
||||||
|
*
|
||||||
|
* @param exportPath The export path.
|
||||||
|
* @param openCase The current case.
|
||||||
|
*/
|
||||||
|
private static void updateExportDirectory(String exportPath, Case openCase) {
|
||||||
|
if (exportPath.equalsIgnoreCase(openCase.getExportDirectory())) {
|
||||||
|
userDefinedExportPath = null;
|
||||||
|
} else {
|
||||||
|
userDefinedExportPath = exportPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread that does the actual extraction work
|
||||||
|
*/
|
||||||
|
private static class CSVWriter extends SwingWorker<Object, Void> {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CSVWriter.class.getName());
|
||||||
|
private ProgressHandle progress;
|
||||||
|
|
||||||
|
private final Collection<? extends Node> nodesToExport;
|
||||||
|
private final File outputFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of the CSVWriter.
|
||||||
|
*
|
||||||
|
* @param extractionTasks List of file extraction tasks.
|
||||||
|
*/
|
||||||
|
CSVWriter(Collection<? extends Node> nodesToExport, File outputFile) {
|
||||||
|
this.nodesToExport = nodesToExport;
|
||||||
|
this.outputFile = outputFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"CSVWriter.progress.extracting=Exporting to CSV file",
|
||||||
|
"CSVWriter.progress.cancelling=Cancelling"})
|
||||||
|
@Override
|
||||||
|
protected Object doInBackground() throws Exception {
|
||||||
|
if (nodesToExport.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up progress bar.
|
||||||
|
final String displayName = Bundle.CSVWriter_progress_extracting();
|
||||||
|
progress = ProgressHandle.createHandle(displayName, new Cancellable() {
|
||||||
|
@Override
|
||||||
|
public boolean cancel() {
|
||||||
|
if (progress != null) {
|
||||||
|
progress.setDisplayName(Bundle.CSVWriter_progress_cancelling());
|
||||||
|
}
|
||||||
|
return ExportCSVAction.CSVWriter.this.cancel(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
progress.start();
|
||||||
|
progress.switchToIndeterminate();
|
||||||
|
|
||||||
|
try (BufferedWriter br = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
|
||||||
|
// Write BOM
|
||||||
|
br.write('\ufeff');
|
||||||
|
|
||||||
|
// Write the header
|
||||||
|
List<String> headers = new ArrayList<>();
|
||||||
|
PropertySet[] sets = nodesToExport.iterator().next().getPropertySets();
|
||||||
|
for(PropertySet set : sets) {
|
||||||
|
for (Property<?> prop : set.getProperties()) {
|
||||||
|
if ( ! columnsToSkip.contains(prop.getDisplayName())) {
|
||||||
|
headers.add(prop.getDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
br.write(listToCSV(headers));
|
||||||
|
|
||||||
|
// Write each line
|
||||||
|
Iterator<?> nodeIterator = nodesToExport.iterator();
|
||||||
|
while (nodeIterator.hasNext()) {
|
||||||
|
if (this.isCancelled()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node node = (Node)nodeIterator.next();
|
||||||
|
List<String> values = new ArrayList<>();
|
||||||
|
sets = node.getPropertySets();
|
||||||
|
for(PropertySet set : sets) {
|
||||||
|
for (Property<?> prop : set.getProperties()) {
|
||||||
|
if ( ! columnsToSkip.contains(prop.getDisplayName())) {
|
||||||
|
values.add(escapeQuotes(prop.getValue().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
br.write(listToCSV(values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape any quotes in the string
|
||||||
|
*
|
||||||
|
* @param original
|
||||||
|
*
|
||||||
|
* @return the string with quotes escaped
|
||||||
|
*/
|
||||||
|
private String escapeQuotes(String original) {
|
||||||
|
return original.replaceAll("\"", "\\\\\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert list of values to a comma separated string.
|
||||||
|
*
|
||||||
|
* @param values Values to convert
|
||||||
|
*
|
||||||
|
* @return values as CSV
|
||||||
|
*/
|
||||||
|
private String listToCSV(List<String> values) {
|
||||||
|
return "\"" + String.join("\",\"", values) + "\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"CSVWriter.done.notifyMsg.error=Error exporting to CSV file",
|
||||||
|
"# {0} - Output file",
|
||||||
|
"CSVWriter.done.notifyMsg.success=Wrote to {0}"})
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
boolean msgDisplayed = false;
|
||||||
|
try {
|
||||||
|
super.get();
|
||||||
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Fatal error during file extraction", ex); //NON-NLS
|
||||||
|
MessageNotifyUtil.Message.info(Bundle.CSVWriter_done_notifyMsg_error());
|
||||||
|
msgDisplayed = true;
|
||||||
|
} catch (java.util.concurrent.CancellationException ex) {
|
||||||
|
// catch and ignore if we were cancelled
|
||||||
|
} finally {
|
||||||
|
progress.finish();
|
||||||
|
if (!this.isCancelled() && !msgDisplayed) {
|
||||||
|
MessageNotifyUtil.Message.info(Bundle.CSVWriter_done_notifyMsg_success(outputFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ KnownStatusSearchPanel.knownCheckBox.text=Known Status:
|
|||||||
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable
|
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable
|
||||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
|
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
|
||||||
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
||||||
DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected\!
|
DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected!
|
||||||
DateSearchPanel.dateCheckBox.text=Date:
|
DateSearchPanel.dateCheckBox.text=Date:
|
||||||
DateSearchPanel.jLabel4.text=Timezone:
|
DateSearchPanel.jLabel4.text=Timezone:
|
||||||
DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy
|
DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy
|
||||||
@ -56,7 +56,7 @@ FileSearchPanel.search.results.details=Large number of matches may impact perfor
|
|||||||
FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected.
|
FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected.
|
||||||
FileSearchPanel.search.validationErr.msg=Validation Error: {0}
|
FileSearchPanel.search.validationErr.msg=Validation Error: {0}
|
||||||
FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show.
|
FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show.
|
||||||
KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected\!
|
KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected!
|
||||||
NameSearchFilter.emptyNameMsg.text=Must enter something for name search.
|
NameSearchFilter.emptyNameMsg.text=Must enter something for name search.
|
||||||
SearchNode.getName.text=Search Result
|
SearchNode.getName.text=Search Result
|
||||||
SizeSearchPanel.sizeCompareComboBox.equalTo=equal to
|
SizeSearchPanel.sizeCompareComboBox.equalTo=equal to
|
||||||
|
@ -140,7 +140,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space
|
|||||||
IngestJob.cancelReason.servicesDown.text=Services Down
|
IngestJob.cancelReason.servicesDown.text=Services Down
|
||||||
IngestJob.cancelReason.caseClosed.text=Case closed
|
IngestJob.cancelReason.caseClosed.text=Case closed
|
||||||
IngestJobSettingsPanel.globalSettingsButton.text=Global Settings
|
IngestJobSettingsPanel.globalSettingsButton.text=Global Settings
|
||||||
gest
|
gest=
|
||||||
IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced
|
IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced
|
||||||
IngestJobSettingsPanel.globalSettingsButton.text=Global Settings
|
IngestJobSettingsPanel.globalSettingsButton.text=Global Settings
|
||||||
IngestJobSettingsPanel.pastJobsButton.text=History
|
IngestJobSettingsPanel.pastJobsButton.text=History
|
||||||
|
@ -11,12 +11,7 @@ ExtractArchiveWithPasswordAction.progress.text=Unpacking contents of archive: {0
|
|||||||
ExtractArchiveWithPasswordAction.prompt.text=Enter Password
|
ExtractArchiveWithPasswordAction.prompt.text=Enter Password
|
||||||
ExtractArchiveWithPasswordAction.prompt.title=Enter Password
|
ExtractArchiveWithPasswordAction.prompt.title=Enter Password
|
||||||
OpenIDE-Module-Display-Category=Ingest Module
|
OpenIDE-Module-Display-Category=Ingest Module
|
||||||
OpenIDE-Module-Long-Description=\
|
OpenIDE-Module-Long-Description=Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\nContents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\nIf the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\nThe extracted files are navigable in the directory tree.\n\nThe module is supported on Windows, Linux and Mac operating systems.
|
||||||
Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\n\
|
|
||||||
Contents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\n\
|
|
||||||
If the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\n\
|
|
||||||
The extracted files are navigable in the directory tree.\n\n\
|
|
||||||
The module is supported on Windows, Linux and Mac operating systems.
|
|
||||||
OpenIDE-Module-Name=Embedded File Extraction
|
OpenIDE-Module-Name=Embedded File Extraction
|
||||||
OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module
|
OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module
|
||||||
EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0}
|
EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
CannotRunFileTypeDetection=Cannot run file type detection.
|
CannotRunFileTypeDetection=Cannot run file type detection.
|
||||||
ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search.
|
ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search.
|
||||||
OpenIDE-Module-Display-Category=Ingest Module
|
OpenIDE-Module-Display-Category=Ingest Module
|
||||||
OpenIDE-Module-Long-Description=\
|
OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results.
|
||||||
Exif metadata ingest module. \n\n\
|
|
||||||
The ingest module analyzes image files, extracts Exif information and posts the Exif data as results.
|
|
||||||
OpenIDE-Module-Name=ExifParser
|
OpenIDE-Module-Name=ExifParser
|
||||||
OpenIDE-Module-Short-Description=Exif metadata ingest module
|
OpenIDE-Module-Short-Description=Exif metadata ingest module
|
||||||
ExifParserFileIngestModule.moduleName.text=Exif Parser
|
ExifParserFileIngestModule.moduleName.text=Exif Parser
|
||||||
|
@ -36,27 +36,27 @@ FileExtMismatchSettingsPanel.jLabel1.text=File Types:
|
|||||||
FileExtMismatchSettingsPanel.newExtButton.text=New Extension
|
FileExtMismatchSettingsPanel.newExtButton.text=New Extension
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type:
|
FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type:
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME
|
FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty\!
|
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty!
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type
|
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported\!
|
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported!
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported
|
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists\!
|
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists!
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists
|
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module.
|
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module.
|
||||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable
|
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable
|
||||||
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected\!
|
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected!
|
||||||
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected
|
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension:
|
FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension:
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension
|
FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty\!
|
FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty!
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty
|
FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected\!
|
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected!
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected
|
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists\!
|
FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists!
|
||||||
FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists
|
FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists
|
||||||
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected\!
|
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected!
|
||||||
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected
|
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected
|
||||||
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected\!
|
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected!
|
||||||
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected
|
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected
|
||||||
FileExtMismatchSettingsPanel.removeTypeButton.toolTipText=
|
FileExtMismatchSettingsPanel.removeTypeButton.toolTipText=
|
||||||
FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types
|
FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types
|
||||||
|
@ -40,10 +40,7 @@ ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash se
|
|||||||
ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed
|
ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed
|
||||||
ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress
|
ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress
|
||||||
OpenIDE-Module-Display-Category=Ingest Module
|
OpenIDE-Module-Display-Category=Ingest Module
|
||||||
OpenIDE-Module-Long-Description=\
|
OpenIDE-Module-Long-Description=Hash Set ingest module. \n\nThe ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\nThe module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration.
|
||||||
Hash Set ingest module. \n\n\
|
|
||||||
The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\n\
|
|
||||||
The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration.
|
|
||||||
OpenIDE-Module-Name=HashDatabases
|
OpenIDE-Module-Name=HashDatabases
|
||||||
OptionsCategory_Name_HashDatabase=Hash Sets
|
OptionsCategory_Name_HashDatabase=Hash Sets
|
||||||
OptionsCategory_Keywords_HashDatabase=Hash Sets
|
OptionsCategory_Keywords_HashDatabase=Hash Sets
|
||||||
@ -172,10 +169,7 @@ HashDbSearchThread.name.searching=Searching
|
|||||||
HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found.
|
HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found.
|
||||||
ModalNoButtons.indexingDbsTitle=Indexing hash sets
|
ModalNoButtons.indexingDbsTitle=Indexing hash sets
|
||||||
ModalNoButtons.indexingDbTitle=Indexing hash set
|
ModalNoButtons.indexingDbTitle=Indexing hash set
|
||||||
ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \n\
|
ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \nThe generated index will be left unusable. If you choose to continue,\nplease delete the corresponding -md5.idx file in the hash folder.\nExit indexing?
|
||||||
The generated index will be left unusable. If you choose to continue,\n\
|
|
||||||
please delete the corresponding -md5.idx file in the hash folder.\n\
|
|
||||||
Exit indexing?
|
|
||||||
ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing
|
ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing
|
||||||
ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set
|
ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set
|
||||||
ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0}
|
ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0}
|
||||||
|
@ -2,7 +2,6 @@ FilesIdentifierIngestJobSettingsPanel.getError=Error getting interesting files s
|
|||||||
FilesIdentifierIngestJobSettingsPanel.updateError=Error updating interesting files sets settings file.
|
FilesIdentifierIngestJobSettingsPanel.updateError=Error updating interesting files sets settings file.
|
||||||
FilesIdentifierIngestModule.getFilesError=Error getting interesting files sets from file.
|
FilesIdentifierIngestModule.getFilesError=Error getting interesting files sets from file.
|
||||||
FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search.
|
FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search.
|
||||||
# {0} - daysIncluded
|
|
||||||
FilesSet.rule.dateRule.toString=(modified within {0} day(s))
|
FilesSet.rule.dateRule.toString=(modified within {0} day(s))
|
||||||
FilesSetDefsPanel.bytes=Bytes
|
FilesSetDefsPanel.bytes=Bytes
|
||||||
FilesSetDefsPanel.cancelImportMsg=Cancel import
|
FilesSetDefsPanel.cancelImportMsg=Cancel import
|
||||||
@ -81,8 +80,8 @@ FilesSetRulePanel.nameTextField.text=
|
|||||||
FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional):
|
FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional):
|
||||||
FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule.
|
FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule.
|
||||||
FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0}
|
FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0}
|
||||||
FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression.
|
FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, ", <, or > unless it is a regular expression.
|
||||||
FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression.
|
FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, ", <, or > unless it is a regular expression.
|
||||||
FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0}
|
FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0}
|
||||||
FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists.
|
FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists.
|
||||||
FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator
|
FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user