Merge branch 'develop' of github.com:sleuthkit/autopsy into cl_reports

This commit is contained in:
Eugene Livis 2019-07-12 13:29:23 -04:00
commit a8a2e13731
397 changed files with 20555 additions and 5240 deletions

2
.gitignore vendored
View File

@ -82,6 +82,8 @@ hs_err_pid*.log
/RecentActivity/release/
/CentralRepository/release/
/.idea/
*.img
*.vhd
*.E01

View File

@ -109,27 +109,27 @@
<target name="getTestDataFiles">
<mkdir dir="${basedir}/test/qa-functional/data"/>
<get src="https://drive.google.com/uc?id=1FkinvA7EFqP4nOSOyTAOli5KefM67ufA" dest="${test-input}/EmbeddedIM_img1_v2.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1zPlIn1xmOeC1VYKmV3fJHl5qE6E_M7K-" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1brQqmX8MJnBPUFEbsdUvZ1X81PmQNVCY" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/IngestFilters_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/IngestFilters_local1_v1.zip" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1Ovyv_xVty8xMYgsc3C45pvphfhbdKg1x" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/VeracryptDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1mr9waEDG5H8GBBn_yXwMUQ6senwC1goL" dest="${test-input}/CommonFiles_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1ghDjm0NhI3ShMQ38E-4o7XrGeexpjdJb" dest="${test-input}/CommonFiles_img3_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1SJYJFjiumKEtQmeMPsQ6G3xmABarbKm_" dest="${test-input}/CommonFiles_img4_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1HwpDlMa1J7h9AmEd1JhLYGnzihslZJUj" dest="${test-input}/c1ds1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1Z7mWChlLIpIlScD-DVNGFik5A_rnwS_9" dest="${test-input}/c1ds2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=14ZxYGyng_eKPe2yaiKDkJLoNcKHIHhW5" dest="${test-input}/c2ds1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1xv3Lz9m2QLq35ofDfHQNe9aHVtVzHUsj" dest="${test-input}/c2ds2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1sg-znklB9yJAWq8i1cF2W-QLOM4FjZyv" dest="${test-input}/c3ds1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1qXyaSlm3hMhv0jl6JkZEficknKjYNOlt" dest="${test-input}/c3ds2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1gW-SvduRwwoHmOheQypaRZ3ig-bezRre" dest="${test-input}/CommonFilesAttrs_img4_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=14vx83MZcd5PJadOesQz7tja-4a-Hz7eD" dest="${test-input}/CommonFilesAttrs_img3_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1ZIYca4CWxyDcfF5Vf2uWkXeI83mR8L9B" dest="${test-input}/CommonFilesAttrs_img2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1RvLNhuKzqHURqeVml_o4lpv6jPCJJ9sv" dest="${test-input}/CommonFilesAttrs_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1gyKzqJHtaBjFBqeB29N5vSpf1oH9N0bV" dest="${test-input}/EmbeddedIM_img1_v2.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1gvvV797dKczkwpWII4hIryBXCc0w5zL-" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1lYzd--9YUB7yDccM7NPOo8PC1xxuOiKs" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1QRNKs824kksiJLZ4qcs59Nytw0fJKEjb" dest="${test-input}/IngestFilters_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1OMTB5gD4_VuaFkLWu2I33FN8VAHoRQbW" dest="${test-input}/IngestFilters_local1_v1.zip" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1WGMkivlDi_I_vB1aYY6puAPktbmlNSL-" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1X2DzJOJ1SjUkAtZXJ3oQHXkjF0NX_jOz" dest="${test-input}/VeracryptDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=19gRepVVvLsDHtBwIkX2VVjsBWIub7aIV" dest="${test-input}/CommonFiles_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1chUMtA0CNyPBZ0yuTl9F_O103R21Ox0p" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1TmdjSjV7MLwVEmgWGJLOYnWDiZeqOgmd" dest="${test-input}/CommonFiles_img3_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=10u8ocYv6KKDVox6SRv_0fQeVqJjWAFJr" dest="${test-input}/CommonFiles_img4_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1pcYsYB1tTzg63kgTG52u40osbZ-rUHwr" dest="${test-input}/c1ds1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=11F_Kjht23aFfbdHN1Ryl2fLFv3A76E6O" dest="${test-input}/c1ds2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1gVnHJEzUmCGVVqhcpI9UHB9zHY2zY5VL" dest="${test-input}/c2ds1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1RodtAXWXrDvwuMVQYBM_QaOi3XR2B41F" dest="${test-input}/c2ds2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1t4RKK375nKFAh2iGuu5Nttdy4EFyUqlv" dest="${test-input}/c3ds1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1be6Szhb57duDkfCc_EGeyHCrAzrIDjs3" dest="${test-input}/c3ds2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=13YJ6nNXiAxRjNKwzcN9ohwvnVupxPvXc" dest="${test-input}/CommonFilesAttrs_img4_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1UczQeY5ZZiQaql_ErnPRxVyX6qMgbvil" dest="${test-input}/CommonFilesAttrs_img3_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1c2egfrKDQqFD04EqhGIDfs82Uub-fGlx" dest="${test-input}/CommonFilesAttrs_img2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1ns2olaWsBu_c4EoE4Seh8t_B3U5RnLKd" dest="${test-input}/CommonFilesAttrs_img1_v1.vhd" skipexisting="true"/>
</target>

View File

@ -45,6 +45,9 @@
<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 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"/>
</dependencies>
</ivy-module>

View File

@ -75,7 +75,7 @@ file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar
file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar
file.reference.sleuthkit-postgresql-4.6.6.jar=release/modules/ext/sleuthkit-postgresql-4.6.6.jar
file.reference.sleuthkit-postgresql-4.6.7.jar=release/modules/ext/sleuthkit-postgresql-4.6.7.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar
file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar
@ -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-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.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.compilerargs=-Xlint -Xlint:-serial
license.file=../LICENSE-2.0.txt

View File

@ -482,8 +482,8 @@
<binary-origin>release\modules\ext\jmatio-1.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.6.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.7.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.7.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-parsers-1.20.jar</runtime-relative-path>
@ -773,6 +773,14 @@
<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>
</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>
</configuration>
</project>

View File

@ -36,10 +36,10 @@ GetTagNameDialog.tagNameExistsTskCore.msg=The {0} tag name already exists in the
OpenLogFolder.error1=Log File Not Found: {0}
OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder
CTL_OpenLogFolder=Open Log Folder
CTL_OpenOutputFolder=Open Output Folder
OpenOutputFolder.error1=Output Folder Not Found: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
CTL_OpenOutputFolder=Open Case Folder
OpenOutputFolder.error1=Case Folder Not Found: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current case folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open case folder
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
OpenPythonModulesFolderAction.actionName.text=Python Plugins
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}

View File

@ -79,10 +79,10 @@ GetTagNameDialog.tagNameExistsTskCore.msg=The {0} tag name already exists in the
OpenLogFolder.error1=Log File Not Found: {0}
OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder
CTL_OpenLogFolder=Open Log Folder
CTL_OpenOutputFolder=Open Output Folder
OpenOutputFolder.error1=Output Folder Not Found: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
CTL_OpenOutputFolder=Open Case Folder
OpenOutputFolder.error1=Case Folder Not Found: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current case folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open case folder
# {0} - old tag name
# {1} - artifactID
ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}.

View File

@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
@ -40,8 +39,9 @@ import javax.swing.SwingUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
import org.sleuthkit.autopsy.logicalimager.dsp.LogicalImagerDSProcessor;
/**
* Panel which displays the available DataSourceProcessors and allows selection

View File

@ -238,13 +238,6 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
LogicalImagerPanel.jLabel1.text=Insert external drive
LogicalImagerPanel.scanButton.text=Scan
LogicalImagerPanel.jLabel6.text=Or, pick a Logical Imager folder
LogicalImagerPanel.browseButton.text=Browse
LogicalImagerPanel.topLabel.text=Import Autopsy Imager Results
LogicalImagerPanel.selectDriveLabel.text=Select Drive
LogicalImagerPanel.messageLabel.text=Error/Status message
UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module.
UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the
UnpackagePortableCaseDialog.exitButton.text=Exit
@ -259,4 +252,4 @@ UnpackagePortableCaseProgressDialog.cancelButton.text=Cancel
UnpackagePortableCaseProgressDialog.okButton.text=OK
UnpackagePortableCaseProgressDialog.resultLabel.text=resultLabel
UnpackagePortableCaseDialog.extractLabel.text=Folder to extract to:
UnpackagePortableCaseDialog.caseLabel.text=Portable Case:
UnpackagePortableCaseDialog.caseLabel.text=Portable Case:

View File

@ -1,19 +1,5 @@
AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules
AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode
# {0} - file
AddLogicalImageTask.addingToReport=Adding {0} to report
# {0} - src
# {1} - dest
AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1}
# {0} - file
AddLogicalImageTask.doneAddingToReport=Done adding {0} to report
AddLogicalImageTask.doneCopying=Done copying
# {0} - file
# {1} - exception message
AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
# {0} - src
# {1} - dest
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
# {0} - exception message
Case.closeException.couldNotCloseCase=Error closing case: {0}
Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory
@ -182,27 +168,6 @@ LogicalEvidenceFilePanel.pathValidation.getOpenCase.Error=Warning: Exception whi
LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.
LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)
LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders
LogicalImagerDSProcessor.dataSourceType=Autopsy Imager
# {0} - directory
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
# {0} - directory
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
# {0} - imageDirPath
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
LogicalImagerPanel.imageTable.columnModel.title0=Hostname
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images
# {0} - sparseImageDirectory
# {1} - image
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.driveHasNoImages=Drive has no images
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
LogicalImagerPanel.messageLabel.noImageSelected=No image selected
LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...
LogicalImagerPanel.messageLabel.selectedImage=Selected folder
LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive
Menu/Case/OpenRecentCase=Open Recent Case
CTL_CaseDeleteAction=Delete Case
OpenIDE-Module-Name=Case
@ -475,13 +440,6 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
LogicalImagerPanel.jLabel1.text=Insert external drive
LogicalImagerPanel.scanButton.text=Scan
LogicalImagerPanel.jLabel6.text=Or, pick a Logical Imager folder
LogicalImagerPanel.browseButton.text=Browse
LogicalImagerPanel.topLabel.text=Import Autopsy Imager Results
LogicalImagerPanel.selectDriveLabel.text=Select Drive
LogicalImagerPanel.messageLabel.text=Error/Status message
UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module.
UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the
UnpackagePortableCaseDialog.exitButton.text=Exit

View File

@ -1,236 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 65]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[403, 65]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="238" max="-2" attributes="0"/>
<Component id="topLabel" min="-2" pref="163" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="messageLabel" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="selectDriveLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="289" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="scanButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="126" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="driveListScrollPane" min="-2" pref="211" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="selectAcquisitionFromDriveLabel" min="-2" pref="305" max="-2" attributes="0"/>
<Component id="imageScrollPane" min="-2" pref="346" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="346" max="-2" attributes="0"/>
<Component id="jLabel6" min="-2" pref="154" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="144" max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" pref="116" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace pref="48" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="topLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="scanButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" pref="4" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="selectDriveLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="selectAcquisitionFromDriveLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="imageScrollPane" pref="0" max="32767" attributes="0"/>
<Component id="driveListScrollPane" pref="194" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
<Component id="messageLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="154" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="topLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.topLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="scanButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.scanButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="scanButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="messageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.messageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="selectDriveLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.selectDriveLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="driveListScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="driveList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="0"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="driveListMouseClicked"/>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="driveListKeyReleased"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="selectAcquisitionFromDriveLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.selectAcquisitionFromDriveLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel6">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.jLabel6.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="imageScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[346, 402]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="imageTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
<Table columnCount="0" rowCount="0"/>
</Property>
<Property name="autoResizeMode" type="int" value="0"/>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="1"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="showHorizontalLines" type="boolean" value="false"/>
<Property name="showVerticalLines" type="boolean" value="false"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
<Property name="updateSelectionOnSort" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="imageTableMouseClicked"/>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="imageTableKeyReleased"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
</SubComponents>
</Form>

View File

@ -88,7 +88,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
* @return caseName the case name from the case name text field
*/
String getCaseName() {
return this.caseNameTextField.getText();
return this.caseNameTextField.getText().trim();
}
/**
@ -109,7 +109,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
* @return baseDirectory the base directory from the case dir text field
*/
String getCaseParentDir() {
String parentDir = this.caseParentDirTextField.getText();
String parentDir = this.caseParentDirTextField.getText().trim();
if (parentDir.endsWith(File.separator) == false) {
parentDir = parentDir + File.separator;
}

View File

@ -76,6 +76,7 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="OpenRecentCasePanel.openButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButtonActionPerformed"/>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,7 +24,10 @@ import java.io.File;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
@ -51,6 +54,16 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
*/
private OpenRecentCasePanel() {
initComponents();
imagesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imagesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
//enable the ok button when something is selected
if (!e.getValueIsAdjusting()){
openButton.setEnabled(imagesTable.getSelectedRowCount() > 0);
}
}
});
}
/*
@ -90,9 +103,6 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
// If there are any images, let's select the first one
if (imagesTable.getRowCount() > 0) {
imagesTable.setRowSelectionInterval(0, 0);
openButton.setEnabled(true);
} else {
openButton.setEnabled(false);
}
}
@ -251,6 +261,7 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
cancelButton.setText(org.openide.util.NbBundle.getMessage(OpenRecentCasePanel.class, "OpenRecentCasePanel.cancelButton.text")); // NOI18N
openButton.setText(org.openide.util.NbBundle.getMessage(OpenRecentCasePanel.class, "OpenRecentCasePanel.openButton.text")); // NOI18N
openButton.setEnabled(false);
openButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openButtonActionPerformed(evt);

View File

@ -351,7 +351,11 @@ class UnpackagePortableCaseDialog extends javax.swing.JDialog {
private void unpackageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unpackageButtonActionPerformed
UnpackagePortableCaseProgressDialog dialog = new UnpackagePortableCaseProgressDialog();
dialog.unpackageCase(caseTextField.getText(), outputTextField.getText());
validatePaths(); // The output folder now exists so we need to disable the unpackage button
if (dialog.isSuccess()) {
dispose();
} else {
validatePaths(); // The output folder now exists so we need to disable the unpackage button
}
}//GEN-LAST:event_unpackageButtonActionPerformed

View File

@ -44,11 +44,11 @@ import org.sleuthkit.datamodel.TskCoreException;
class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements PropertyChangeListener {
private UnpackageWorker worker;
/**
* Creates new form UnpackagePortableCaseProgressDialog
*/
@NbBundle.Messages({"UnpackagePortableCaseProgressDialog.title.text=Unpackage Portable Case Progress",})
@NbBundle.Messages({"UnpackagePortableCaseProgressDialog.title.text=Unpackage Portable Case Progress",})
UnpackagePortableCaseProgressDialog() {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.UnpackagePortableCaseProgressDialog_title_text(),
@ -56,32 +56,45 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements
initComponents();
customizeComponents();
}
private void customizeComponents() {
cancelButton.setEnabled(true);
okButton.setEnabled(false);
progressBar.setIndeterminate(true);
resultLabel.setText(""); // NON-NLS
}
/**
* Unpackage the case
*
* @param packagedCase The compressed case
* @param outputFolder The output folder
*
* @param packagedCase The compressed case
* @param outputFolder The output folder
*/
void unpackageCase(String packagedCase, String outputFolder) {
worker = new UnpackageWorker(packagedCase, outputFolder);
worker.addPropertyChangeListener(this);
worker.execute();
setLocationRelativeTo((JFrame) WindowManager.getDefault().getMainWindow());
this.setVisible(true);
}
@NbBundle.Messages({"UnpackagePortableCaseProgressDialog.propertyChange.success=Successfully unpacked case",})
/**
* Returns whether the unpackaging was completed successfully.
*
* @return True if unpackaging was completed successfully, false otherwise
*/
boolean isSuccess() {
if (worker == null) {
return false;
} else {
return worker.isSuccess();
}
}
@NbBundle.Messages({"UnpackagePortableCaseProgressDialog.propertyChange.success=Successfully unpacked case",})
@Override
public void propertyChange(PropertyChangeEvent evt) {
@ -92,7 +105,7 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements
// Disable cancel button and enable ok
cancelButton.setEnabled(false);
okButton.setEnabled(true);
if (worker.isSuccess()) {
progressBar.setIndeterminate(false);
progressBar.setValue(progressBar.getMaximum());
@ -106,48 +119,47 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements
}
}
}
/**
* Swing worker to do the decompression.
*/
private class UnpackageWorker extends SwingWorker<Void, Void> {
private final String packagedCase;
private final String outputFolder;
private final AtomicBoolean success = new AtomicBoolean();
private String lastError = "";
UnpackageWorker(String packagedCase, String outputFolder) {
this.packagedCase = packagedCase;
this.outputFolder = outputFolder;
this.success.set(false);
}
@NbBundle.Messages({
"UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable",
"UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case",
"UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user",
})
"UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable",
"UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case",
"UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user",})
@Override
protected Void doInBackground() throws Exception {
// Find 7-Zip
File sevenZipExe = locate7ZipExecutable();
if (sevenZipExe == null) {
setDisplayError(Bundle.UnpackageWorker_doInBackground_errorFinding7zip());
throw new TskCoreException("Error finding 7-Zip executable"); // NON-NLS
}
String outputFolderSwitch = "-o" + outputFolder; // NON-NLS
ProcessBuilder procBuilder = new ProcessBuilder();
procBuilder.command(
sevenZipExe.getAbsolutePath(),
"x", // Extract
"x", // Extract
packagedCase,
outputFolderSwitch
);
try {
Process process = procBuilder.start();
@ -158,7 +170,7 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements
}
Thread.sleep(200);
}
int exitCode = process.exitValue();
if (exitCode != 0) {
// Save any errors so they can be logged
@ -181,63 +193,64 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements
success.set(true);
return null;
}
@Override
synchronized protected void done() {
if (this.isCancelled()) {
return;
}
try {
get();
} catch (Exception ex) {
Logger.getLogger(UnpackagePortableCaseProgressDialog.class.getName()).log(Level.SEVERE, "Error unpackaging portable case", ex); // NON-NLS
}
}
/**
* Save the error that should be displayed to the user
*
*
* @param errorStr Error to be displayed in the UI
*/
private synchronized void setDisplayError(String errorStr) {
lastError = errorStr;
}
/**
* Gets the error to display to the user
*
* @return Error to be displayed in the UI
*/
private synchronized String getDisplayError() {
return lastError;
}
private boolean isSuccess() {
protected boolean isSuccess() {
return success.get();
}
/**
* Locate the 7-Zip executable from the release folder.
*
* @return 7-Zip executable
*/
private File locate7ZipExecutable() {
if (!PlatformUtil.isWindowsOS()) {
return null;
}
* Locate the 7-Zip executable from the release folder.
*
* @return 7-Zip executable
*/
private File locate7ZipExecutable() {
if (!PlatformUtil.isWindowsOS()) {
return null;
}
String executableToFindName = Paths.get("7-Zip", "7z.exe").toString(); // NON-NLS
File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, UnpackagePortableCaseProgressDialog.class.getPackage().getName(), false);
if (null == exeFile) {
return null;
}
String executableToFindName = Paths.get("7-Zip", "7z.exe").toString(); // NON-NLS
File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, UnpackagePortableCaseProgressDialog.class.getPackage().getName(), false);
if (null == exeFile) {
return null;
}
if (!exeFile.canExecute()) {
return null;
}
if (!exeFile.canExecute()) {
return null;
}
return exeFile;
}
return exeFile;
}
}
/**

View File

@ -66,6 +66,7 @@ DataSourceSummaryDialog.window.title=Data Sources Summary
DataSourceSummaryNode.column.dataSourceName.header=Data Source Name
DataSourceSummaryNode.column.files.header=Files
DataSourceSummaryNode.column.results.header=Results
DataSourceSummaryNode.column.status.header=Ingest Status
DataSourceSummaryNode.column.tags.header=Tags
DataSourceSummaryNode.column.type.header=Type
DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source

View File

@ -37,8 +37,10 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryNode.DataSourceSummaryEntryNode;
import static javax.swing.SwingConstants.RIGHT;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.IngestJobInfo;
import org.sleuthkit.datamodel.SleuthkitCase;
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 Logger logger = Logger.getLogger(DataSourceBrowser.class.getName());
private static final int COUNT_COLUMN_WIDTH = 25;
private static final int USAGE_COLUMN_WIDTH = 120;
private static final int DATA_SOURCE_COLUMN_WIDTH = 325;
private static final int COUNT_COLUMN_WIDTH = 20;
private static final int INGEST_STATUS_WIDTH = 50;
private static final int USAGE_COLUMN_WIDTH = 110;
private static final int DATA_SOURCE_COLUMN_WIDTH = 280;
private final Outline outline;
private final org.openide.explorer.view.OutlineView outlineView;
private final ExplorerManager explorerManager;
@ -69,6 +72,7 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana
outlineView = new org.openide.explorer.view.OutlineView();
this.setVisible(true);
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_files_header(), Bundle.DataSourceSummaryNode_column_files_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);
} else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_type_header())) {
column.setPreferredWidth(USAGE_COLUMN_WIDTH);
} else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_status_header())) {
column.setPreferredWidth(INGEST_STATUS_WIDTH);
} else {
column.setPreferredWidth(DATA_SOURCE_COLUMN_WIDTH);
}
@ -182,6 +188,47 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana
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.
* WARNING: Do NOT modify this code. The content of this method is always

View File

@ -18,15 +18,27 @@
*/
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.IngestJobInfo.IngestJobStatusType;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Wrapper object for a DataSource and the information associated with it.
*
*/
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 IngestJobStatusType status = null;
private final String type;
private final long filesCount;
private final long resultsCount;
@ -45,12 +57,26 @@ class DataSourceSummary {
*/
DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) {
dataSource = dSource;
getStatusFromDatabase();
type = typeValue == null ? "" : typeValue;
filesCount = numberOfFiles == null ? 0 : numberOfFiles;
resultsCount = numberOfResults == null ? 0 : numberOfResults;
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
*
@ -60,6 +86,16 @@ class DataSourceSummary {
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
*
@ -87,6 +123,16 @@ class DataSourceSummary {
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
*
@ -95,4 +141,40 @@ class DataSourceSummary {
long getTagsCount() {
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;
}
}
}

View File

@ -19,14 +19,18 @@
package org.sleuthkit.autopsy.casemodule.datasourcesummary;
import java.awt.Frame;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Logger;
import javax.swing.event.ListSelectionEvent;
import org.openide.util.NbBundle.Messages;
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.IngestJobInfo;
/**
* 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 DataSourceBrowser dataSourcesPanel;
private final IngestJobInfoPanel ingestHistoryPanel;
private static final Logger logger = Logger.getLogger(DataSourceSummaryDialog.class.getName());
/**
* 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();
}
});
//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();
}

View File

@ -109,6 +109,7 @@ final class DataSourceSummaryNode extends AbstractNode {
static final class DataSourceSummaryEntryNode extends AbstractNode {
private final DataSource dataSource;
private final String status;
private final String type;
private final long filesCount;
private final long resultsCount;
@ -124,6 +125,7 @@ final class DataSourceSummaryNode extends AbstractNode {
DataSourceSummaryEntryNode(DataSourceSummary dataSourceSummary) {
super(Children.LEAF);
dataSource = dataSourceSummary.getDataSource();
status = dataSourceSummary.getIngestStatus() == null ? "" : dataSourceSummary.getIngestStatus().getDisplayName();
type = dataSourceSummary.getType();
filesCount = dataSourceSummary.getFilesCount();
resultsCount = dataSourceSummary.getResultsCount();
@ -143,6 +145,7 @@ final class DataSourceSummaryNode extends AbstractNode {
}
@Messages({"DataSourceSummaryNode.column.dataSourceName.header=Data Source Name",
"DataSourceSummaryNode.column.status.header=Ingest Status",
"DataSourceSummaryNode.column.type.header=Type",
"DataSourceSummaryNode.column.files.header=Files",
"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(),
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(),
type));
sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(),

View File

@ -754,9 +754,8 @@ public class FileManager implements Closeable {
* the parent local directory.
* @param localFile The local/logical file or directory.
* @param progressUpdater notifier to receive progress notifications on
* folders added, or null if not used
* @param progressUpdater Called after each file/directory is added to the
* case database.
* folders added, or null if not used. Called after
* each file/directory is added to the case database.
*
* @return An AbstractFile representation of the local/logical file.
*

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.services;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -30,15 +31,18 @@ import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.CaseDbAccessManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.DbType;
/**
* A per case Autopsy service that manages the addition of content and artifact
@ -48,6 +52,32 @@ public class TagsManager implements Closeable {
private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName());
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

View File

@ -0,0 +1,270 @@
/*
* 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 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 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 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() {
}
}

View File

@ -1,7 +1,6 @@
DataContentViewerOtherCases.selectAllMenuItem.text=Select All
DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details
DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options.
DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV
DataContentViewerOtherCases.exportToCSVMenuItem.text=Export all Other Occurrences to CSV
DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency
DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date
DataContentViewerOtherCases.earliestCaseLabel.toolTipText=

View File

@ -13,12 +13,11 @@ DataContentViewerOtherCases.dataSources.header.text=Data Source Name
DataContentViewerOtherCases.earliestCaseNotAvailable=\ Not Enabled.
DataContentViewerOtherCases.foundIn.text=Found %d instances in %d cases and %d data sources.
DataContentViewerOtherCases.noOpenCase.errMsg=No open case available.
DataContentViewerOtherCases.selectAllMenuItem.text=Select All
DataContentViewerOtherCases.showCaseDetailsMenuItem.text=Show Case Details
DataContentViewerOtherCases.table.noArtifacts=Item has no attributes with which to search.
DataContentViewerOtherCases.table.noResultsFound=No results found.
DataContentViewerOtherCases.table.toolTip.text=Click column name to sort. Right-click on the table for more options.
DataContentViewerOtherCases.exportToCSVMenuItem.text=Export Selected Rows to CSV
DataContentViewerOtherCases.exportToCSVMenuItem.text=Export all Other Occurrences to CSV
DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency
DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date
DataContentViewerOtherCases.earliestCaseLabel.toolTipText=

View File

@ -11,13 +11,6 @@
<Property name="useNullLayout" type="boolean" value="true"/>
</Layout>
<SubComponents>
<MenuItem class="javax.swing.JMenuItem" name="selectAllMenuItem">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.selectAllMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</MenuItem>
<MenuItem class="javax.swing.JMenuItem" name="exportToCSVMenuItem">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@ -46,11 +39,11 @@
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[600, 10]"/>
<Dimension value="[1000, 10]"/>
</Property>
<Property name="opaque" type="boolean" value="false"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[600, 63]"/>
<Dimension value="[1000, 63]"/>
</Property>
</Properties>
<AuxValues>
@ -68,7 +61,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tableContainerPanel" alignment="0" pref="775" max="32767" attributes="0"/>
<Component id="tableContainerPanel" alignment="0" pref="1000" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -101,7 +94,7 @@
<EmptySpace max="32767" attributes="0"/>
<Component id="foundInLabel" max="32767" attributes="0"/>
</Group>
<Component id="tablesViewerSplitPane" pref="765" max="32767" attributes="0"/>
<Component id="tablesViewerSplitPane" pref="990" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>

View File

@ -89,11 +89,10 @@ import org.sleuthkit.datamodel.TskData;
public class DataContentViewerOtherCases extends JPanel implements DataContentViewer {
private static final long serialVersionUID = -1L;
private static final String UUID_PLACEHOLDER_STRING = "NoCorrelationAttributeInstance";
private static final Logger LOGGER = Logger.getLogger(DataContentViewerOtherCases.class.getName());
private static final CorrelationCaseWrapper NO_ARTIFACTS_CASE = new CorrelationCaseWrapper(Bundle.DataContentViewerOtherCases_table_noArtifacts());
private static final CorrelationCaseWrapper NO_RESULTS_CASE = new CorrelationCaseWrapper(Bundle.DataContentViewerOtherCases_table_noResultsFound());
private final OtherOccurrencesFilesTableModel filesTableModel;
private final OtherOccurrencesCasesTableModel casesTableModel;
private final OtherOccurrencesDataSourcesTableModel dataSourcesTableModel;
@ -129,12 +128,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
reset();
}
/**
* Get a placeholder string to use in place of case uuid when it isn't
* available
*
* @return UUID_PLACEHOLDER_STRING
*/
static String getPlaceholderUUID() {
return UUID_PLACEHOLDER_STRING;
}
private void customizeComponents() {
ActionListener actList = (ActionEvent e) -> {
JMenuItem jmi = (JMenuItem) e.getSource();
if (jmi.equals(selectAllMenuItem)) {
filesTable.selectAll();
} else if (jmi.equals(showCaseDetailsMenuItem)) {
if (jmi.equals(showCaseDetailsMenuItem)) {
showCaseDetails(filesTable.getSelectedRow());
} else if (jmi.equals(exportToCSVMenuItem)) {
try {
@ -148,7 +155,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
};
exportToCSVMenuItem.addActionListener(actList);
selectAllMenuItem.addActionListener(actList);
showCaseDetailsMenuItem.addActionListener(actList);
showCommonalityMenuItem.addActionListener(actList);
@ -804,6 +810,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
occurrencePanel.getPreferredSize();
detailsPanelScrollPane.setViewportView(occurrencePanel);
} else {
String currentCaseName;
try {
currentCaseName = Case.getCurrentCaseThrows().getName();
} catch (NoCurrentCaseException ex) {
currentCaseName = null;
LOGGER.log(Level.WARNING, "Unable to get current case for other occurrences content viewer", ex);
}
for (CorrelationAttributeInstance corAttr : correlationAttributes) {
Map<UniquePathKey, OtherOccurrenceNodeInstanceData> correlatedNodeDataMap = new HashMap<>(0);
@ -817,7 +830,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
&& casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())) {
dataSourcesTableModel.addNodeData(nodeData);
}
} else {
} else if (currentCaseName != null && (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(currentCaseName))) {
dataSourcesTableModel.addNodeData(nodeData);
}
} catch (EamDbException ex) {
@ -837,7 +850,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* selection
*/
private void updateOnDataSourceSelection() {
int[] selectedCaseIndexes = casesTable.getSelectedRows();
int[] selectedDataSources = dataSourcesTable.getSelectedRows();
filesTableModel.clearTable();
for (CorrelationAttributeInstance corAttr : correlationAttributes) {
@ -846,23 +858,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// get correlation and reference set instances from DB
correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
for (OtherOccurrenceNodeInstanceData nodeData : correlatedNodeDataMap.values()) {
for (int selectedCaseRow : selectedCaseIndexes) {
for (int selectedDataSourceRow : selectedDataSources) {
try {
if (nodeData.isCentralRepoNode()) {
if (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedCaseRow)) != null
&& casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedCaseRow)).getCaseUUID().equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())
&& dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
filesTableModel.addNodeData(nodeData);
}
} else {
if (dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
filesTableModel.addNodeData(nodeData);
}
for (int selectedDataSourceRow : selectedDataSources) {
try {
if (nodeData.isCentralRepoNode()) {
if (dataSourcesTableModel.getCaseUUIDForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())
&& dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
filesTableModel.addNodeData(nodeData);
}
} else {
if (dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
filesTableModel.addNodeData(nodeData);
}
} catch (EamDbException ex) {
LOGGER.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex);
}
} catch (EamDbException ex) {
LOGGER.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex);
}
}
}
@ -928,7 +937,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
if (EamDb.isEnabled()) {
CorrelationCase partialCase;
partialCase = casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(caseTableRowIdx));
if (partialCase == null){
if (partialCase == null) {
return "";
}
return EamDb.getInstance().getCaseByUUID(partialCase.getCaseUUID()).getCreationDate();
@ -951,7 +960,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private void initComponents() {
rightClickPopupMenu = new javax.swing.JPopupMenu();
selectAllMenuItem = new javax.swing.JMenuItem();
exportToCSVMenuItem = new javax.swing.JMenuItem();
showCaseDetailsMenuItem = new javax.swing.JMenuItem();
showCommonalityMenuItem = new javax.swing.JMenuItem();
@ -981,9 +989,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}
});
org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N
rightClickPopupMenu.add(selectAllMenuItem);
org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N
rightClickPopupMenu.add(exportToCSVMenuItem);
@ -993,9 +998,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N
rightClickPopupMenu.add(showCommonalityMenuItem);
setMinimumSize(new java.awt.Dimension(600, 10));
setMinimumSize(new java.awt.Dimension(1000, 10));
setOpaque(false);
setPreferredSize(new java.awt.Dimension(600, 63));
setPreferredSize(new java.awt.Dimension(1000, 63));
tableContainerPanel.setPreferredSize(new java.awt.Dimension(600, 63));
tableContainerPanel.setRequestFocusEnabled(false);
@ -1064,7 +1069,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
.addComponent(earliestCaseDate, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(foundInLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(tablesViewerSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 765, Short.MAX_VALUE))
.addComponent(tablesViewerSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 990, Short.MAX_VALUE))
.addContainerGap())
);
tableContainerPanelLayout.setVerticalGroup(
@ -1085,7 +1090,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 775, Short.MAX_VALUE)
.addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1000, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -1125,7 +1130,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private javax.swing.JScrollPane filesTableScrollPane;
private javax.swing.JLabel foundInLabel;
private javax.swing.JPopupMenu rightClickPopupMenu;
private javax.swing.JMenuItem selectAllMenuItem;
private javax.swing.JMenuItem showCaseDetailsMenuItem;
private javax.swing.JMenuItem showCommonalityMenuItem;
private javax.swing.JPanel tableContainerPanel;
@ -1141,6 +1145,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private final String dataSourceID;
private final String filePath;
private final String type;
private final String caseUUID;
UniquePathKey(OtherOccurrenceNodeInstanceData nodeData) {
super();
@ -1151,6 +1156,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
filePath = null;
}
type = nodeData.getType();
String tempCaseUUID;
try {
tempCaseUUID = nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID();
} catch (EamDbException ignored) {
//non central repo nodeData won't have a correlation case
try {
tempCaseUUID = Case.getCurrentCaseThrows().getName();
//place holder value will be used since correlation attribute was unavailble
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.WARNING, "Unable to get current case", ex);
tempCaseUUID = UUID_PLACEHOLDER_STRING;
}
}
caseUUID = tempCaseUUID;
}
@Override
@ -1159,14 +1178,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
UniquePathKey otherKey = (UniquePathKey) (other);
return (Objects.equals(otherKey.getDataSourceID(), this.getDataSourceID())
&& Objects.equals(otherKey.getFilePath(), this.getFilePath())
&& Objects.equals(otherKey.getType(), this.getType()));
&& Objects.equals(otherKey.getType(), this.getType())
&& Objects.equals(otherKey.getCaseUUID(), this.getCaseUUID()));
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(getDataSourceID(), getFilePath(), getType());
return Objects.hash(getDataSourceID(), getFilePath(), getType(), getCaseUUID());
}
/**
@ -1195,5 +1215,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
String getDataSourceID() {
return dataSourceID;
}
/**
* Get the case uuid for the UniquePathKey
*
* @return the case UUID
*/
String getCaseUUID() {
return caseUUID;
}
}
}

View File

@ -175,7 +175,7 @@ final class OccurrencePanel extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(knownStatusLabel, Bundle.OccurrencePanel_commonPropertyKnownStatusLabel_text());
addItemToBag(gridY, 0, 0, 0, knownStatusLabel);
javax.swing.JLabel knownStatusValue = new javax.swing.JLabel();
knownStatusValue.setText(knownStatus.toString());
knownStatusValue.setText(knownStatus.getName());
if (knownStatus == TskData.FileKnown.BAD) {
knownStatusValue.setForeground(Color.RED);
}

View File

@ -21,8 +21,13 @@ package org.sleuthkit.autopsy.centralrepository.contentviewer;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Model for cells in the data sources section of the other occurrences data
@ -31,6 +36,7 @@ import org.openide.util.NbBundle;
final class OtherOccurrencesDataSourcesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(OtherOccurrencesDataSourcesTableModel.class.getName());
private final Set<DataSourceColumnItem> dataSourceSet = new LinkedHashSet<>();
/**
@ -86,6 +92,25 @@ final class OtherOccurrencesDataSourcesTableModel extends AbstractTableModel {
return ((DataSourceColumnItem) dataSourceSet.toArray()[rowIdx]).getDeviceId();
}
/**
* Get the case uuid of the case the data source shown at the specified row
* index exists in
*
* @param rowIdx the row index of the data source you want the case uuid for
*
* @return the case uuid of the case the specified data source exists in or
* an empty string if a device id could not be retrieved
*/
String getCaseUUIDForRow(int rowIdx) {
//if anything would prevent this from working we will return an empty string
if (dataSourceSet.isEmpty() || rowIdx < 0
|| rowIdx >= dataSourceSet.size()
|| !(dataSourceSet.toArray()[rowIdx] instanceof DataSourceColumnItem)) {
return "";
}
return ((DataSourceColumnItem) dataSourceSet.toArray()[rowIdx]).getCaseUUID();
}
/**
* Get the case name of the data source shown at the specified row index
*
@ -115,7 +140,21 @@ final class OtherOccurrencesDataSourcesTableModel extends AbstractTableModel {
* @param newNodeData data to add to the table
*/
void addNodeData(OtherOccurrenceNodeData newNodeData) {
dataSourceSet.add(new DataSourceColumnItem((OtherOccurrenceNodeInstanceData) newNodeData));
OtherOccurrenceNodeInstanceData nodeData = (OtherOccurrenceNodeInstanceData) newNodeData;
String caseUUID;
try {
caseUUID = nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID();
} catch (EamDbException ignored) {
//non central repo nodeData won't have a correlation case
try {
caseUUID = Case.getCurrentCaseThrows().getName();
//place holder value will be used since correlation attribute was unavailble
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to get current case", ex);
caseUUID = DataContentViewerOtherCases.getPlaceholderUUID();
}
}
dataSourceSet.add(new DataSourceColumnItem(nodeData.getCaseName(), nodeData.getDeviceID(), nodeData.getDataSourceName(), caseUUID));
fireTableDataChanged();
}
@ -136,30 +175,23 @@ final class OtherOccurrencesDataSourcesTableModel extends AbstractTableModel {
private final String caseName;
private final String deviceId;
private final String dataSourceName;
/**
* Create a DataSourceColumnItem given an
* OtherOccurrenceNodeInstanceData object
*
* @param nodeData the OtherOccurrenceNodeInstanceData which contains
* the data source information
*/
private DataSourceColumnItem(OtherOccurrenceNodeInstanceData nodeData) {
this(nodeData.getCaseName(), nodeData.getDeviceID(), nodeData.getDataSourceName());
}
private final String caseUUID;
/**
* Create a DataSourceColumnItem given a case name, device id, and data
* source name
*
* @param caseName the name of the case the data source exists in
* @param deviceId the name of the device id for the data source
* @param deviceId the device id for the data source
* @param dataSourceName the name of the data source
* @param caseUUID the case uuid for the case the data source
* exists in
*/
private DataSourceColumnItem(String caseName, String deviceId, String dataSourceName) {
private DataSourceColumnItem(String caseName, String deviceId, String dataSourceName, String caseUUID) {
this.caseName = caseName;
this.deviceId = deviceId;
this.dataSourceName = dataSourceName;
this.caseUUID = caseUUID;
}
/**
@ -189,17 +221,27 @@ final class OtherOccurrencesDataSourcesTableModel extends AbstractTableModel {
return caseName;
}
/**
* Get the case uuid of the case the data source exists in
*
* @return the case UUID
*/
private String getCaseUUID() {
return caseUUID;
}
@Override
public boolean equals(Object other) {
return other instanceof DataSourceColumnItem
&& caseName.equals(((DataSourceColumnItem) other).getCaseName())
&& dataSourceName.equals(((DataSourceColumnItem) other).getDataSourceName())
&& deviceId.equals(((DataSourceColumnItem) other).getDeviceId());
&& deviceId.equals(((DataSourceColumnItem) other).getDeviceId())
&& caseUUID.equals(((DataSourceColumnItem) other).getCaseUUID());
}
@Override
public int hashCode() {
return Objects.hash(caseName, deviceId, dataSourceName);
return Objects.hash(caseName, deviceId, dataSourceName, caseUUID);
}
}

View File

@ -22,9 +22,14 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.apache.commons.io.FilenameUtils;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Model for cells in the files section of the other occurrences data content
@ -33,6 +38,7 @@ import org.apache.commons.io.FilenameUtils;
public class OtherOccurrencesFilesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(OtherOccurrencesFilesTableModel.class.getName());
private final List<String> nodeKeys = new ArrayList<>();
private final Map<String, List<OtherOccurrenceNodeData>> nodeMap = new HashMap<>();
@ -114,7 +120,20 @@ public class OtherOccurrencesFilesTableModel extends AbstractTableModel {
}
private String createNodeKey(OtherOccurrenceNodeInstanceData nodeData) {
return nodeData.getCaseName() + nodeData.getDataSourceName() + nodeData.getDeviceID() + nodeData.getFilePath();
String caseUUID;
try {
caseUUID = nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID();
} catch (EamDbException ignored) {
//non central repo nodeData won't have a correlation case
try {
caseUUID = Case.getCurrentCaseThrows().getName();
//place holder value will be used since correlation attribute was unavailble
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to get current case", ex);
caseUUID = DataContentViewerOtherCases.getPlaceholderUUID();
}
}
return nodeData.getCaseName() + nodeData.getDataSourceName() + nodeData.getDeviceID() + nodeData.getFilePath() + caseUUID;
}
/**

View File

@ -123,7 +123,7 @@ final public class CorrelationAttributeNormalizer {
/**
* Verify there are no slashes or invalid domain name characters (such as
* '?' or \: ). Normalize to lower case.
* '?'). Normalize to lower case.
*/
private static String normalizeDomain(String data) throws CorrelationAttributeNormalizationException {
DomainValidator validator = DomainValidator.getInstance(true);

View File

@ -29,7 +29,7 @@
</Group>
</Group>
</Group>
<EmptySpace pref="65" max="32767" attributes="0"/>
<EmptySpace pref="47" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -44,7 +44,7 @@
<Component id="flagTaggedNotableItemsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="flagPreviouslySeenDevicesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="197" max="32767" attributes="0"/>
<EmptySpace pref="47" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -88,7 +88,7 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
.addComponent(flagTaggedNotableItemsCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(flagPreviouslySeenDevicesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(createCorrelationPropertiesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap(65, Short.MAX_VALUE))
.addContainerGap(47, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -101,7 +101,7 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
.addComponent(flagTaggedNotableItemsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(flagPreviouslySeenDevicesCheckbox)
.addContainerGap(197, Short.MAX_VALUE))
.addContainerGap(47, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents

View File

@ -57,7 +57,6 @@ ManageCorrelationPropertiesDialog.cancelButton.text=Cancel
ManageCorrelationPropertiesDialog.okButton.text=OK
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
EamDbSettingsDialog.lbFullDbPath.text=
GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository
GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the Central Repository.
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
@ -84,4 +83,4 @@ ManageCasesDialog.orgLabel.text=Organization:
ManageCasesDialog.closeButton.text=Close
ManageCasesDialog.notesLabel.text=Notes:
ManageCasesDialog.dataSourcesLabel.text=Data Sources:
ManageCasesDialog.caseInfoLabel.text=Case Info:
ManageCasesDialog.caseInfoLabel.text=Case Info:

View File

@ -115,7 +115,6 @@ ManageCorrelationPropertiesDialog.cancelButton.text=Cancel
ManageCorrelationPropertiesDialog.okButton.text=OK
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
EamDbSettingsDialog.lbFullDbPath.text=
GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository
GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the Central Repository.
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations

View File

@ -9,6 +9,7 @@
</NonVisualComponents>
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
@ -35,18 +36,18 @@
<Component id="pnButtons" max="32767" attributes="0"/>
<Component id="pnSQLiteSettings" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" 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="10" max="-2" attributes="0"/>
<Component id="pnSQLiteSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="11" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="pnSQLiteSettings" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="pnButtons" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -59,9 +60,9 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="bnOk" min="-2" max="-2" attributes="0"/>
<Component id="bnOk" linkSize="2" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
<Component id="bnCancel" min="-2" max="-2" attributes="0"/>
<Component id="bnCancel" linkSize="2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -85,6 +86,15 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.bnCancel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[79, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[79, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[79, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnCancelActionPerformed"/>
@ -115,43 +125,37 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lbHostName" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbPort" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbUserName" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbDatabaseType" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbDatabasePath" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbUserName" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbPort" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="lbDatabasePath" alignment="0" max="32767" attributes="0"/>
<Component id="lbDatabaseDesc" alignment="0" max="32767" attributes="0"/>
<Component id="lbUserPassword" alignment="0" max="32767" attributes="0"/>
</Group>
<Component id="lbDatabaseDesc" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lbFullDbPath" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="cbDatabaseType" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lbSingleUserSqLite" pref="467" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="tfDatabasePath" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="tfDatabasePath" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="tbDbHostname" alignment="0" max="32767" attributes="0"/>
<Component id="jpDbPassword" alignment="0" max="32767" attributes="0"/>
<Component id="tbDbUsername" alignment="1" max="32767" attributes="0"/>
<Component id="tbDbPort" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="cbDatabaseType" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="lbSingleUserSqLite" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jpDbPassword" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="tbDbUsername" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="tbDbPort" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="tbDbHostname" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="dataBaseFileScrollPane" alignment="0" min="-2" pref="509" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="55" max="-2" attributes="0"/>
@ -171,40 +175,42 @@
</Group>
<Component id="lbDatabaseType" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lbDatabasePath" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="tfDatabasePath" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
<Component id="tfDatabasePath" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnDatabasePathFileOpen" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="tbDbHostname" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lbHostName" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="tbDbPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lbPort" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="tbDbUsername" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lbUserName" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jpDbPassword" min="-2" max="-2" attributes="0"/>
<Component id="lbUserPassword" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lbFullDbPath" alignment="3" max="32767" attributes="0"/>
<Component id="lbDatabaseDesc" alignment="3" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="lbDatabaseDesc" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="filler1" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="dataBaseFileScrollPane" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="filler1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -215,6 +221,9 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tfDatabasePath">
@ -225,6 +234,9 @@
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[420, 23]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnDatabasePathFileOpen">
@ -242,42 +254,77 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbHostName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbDbHostname">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[509, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbPort">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbPort.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbDbPort">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[509, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbUserName">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbUserName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbDbUsername">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[509, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbUserPassword">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbUserPassword.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="jpDbPassword">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[509, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cbDatabaseType">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new javax.swing.DefaultComboBoxModel&lt;&gt;(new EamDbPlatformEnum[]{EamDbPlatformEnum.POSTGRESQL, EamDbPlatformEnum.SQLITE})" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[120, 20]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbDatabaseTypeActionPerformed"/>
@ -291,6 +338,9 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbSingleUserSqLite.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[381, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbDatabaseType">
@ -298,6 +348,15 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabaseType.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbDatabaseDesc">
@ -305,12 +364,8 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabaseDesc.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbFullDbPath">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbFullDbPath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 14]"/>
</Property>
</Properties>
</Component>
@ -324,6 +379,34 @@
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
</AuxValues>
</Component>
<Container class="javax.swing.JScrollPane" name="dataBaseFileScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="dataBaseFileTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="3"/>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>

View File

@ -142,12 +142,17 @@ public class EamDbSettingsDialog extends JDialog {
lbSingleUserSqLite = new javax.swing.JLabel();
lbDatabaseType = new javax.swing.JLabel();
lbDatabaseDesc = new javax.swing.JLabel();
lbFullDbPath = new javax.swing.JLabel();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
dataBaseFileScrollPane = new javax.swing.JScrollPane();
dataBaseFileTextArea = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setResizable(false);
org.openide.awt.Mnemonics.setLocalizedText(bnCancel, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.bnCancel.text")); // NOI18N
bnCancel.setMaximumSize(new java.awt.Dimension(79, 23));
bnCancel.setMinimumSize(new java.awt.Dimension(79, 23));
bnCancel.setPreferredSize(new java.awt.Dimension(79, 23));
bnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnCancelActionPerformed(evt);
@ -169,25 +174,30 @@ public class EamDbSettingsDialog extends JDialog {
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bnOk)
.addGap(11, 11, 11)
.addComponent(bnCancel)
.addComponent(bnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
pnButtonsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancel, bnOk});
pnButtonsLayout.setVerticalGroup(
pnButtonsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnButtonsLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(pnButtonsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(bnOk)
.addComponent(bnCancel))
.addComponent(bnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, 0))
);
pnSQLiteSettings.setBorder(javax.swing.BorderFactory.createEtchedBorder());
org.openide.awt.Mnemonics.setLocalizedText(lbDatabasePath, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbDatabasePath.text")); // NOI18N
lbDatabasePath.setPreferredSize(new java.awt.Dimension(80, 14));
tfDatabasePath.setText(org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.tfDatabasePath.text")); // NOI18N
tfDatabasePath.setToolTipText(org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.tfDatabasePath.toolTipText")); // NOI18N
tfDatabasePath.setPreferredSize(new java.awt.Dimension(420, 23));
org.openide.awt.Mnemonics.setLocalizedText(bnDatabasePathFileOpen, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.bnDatabasePathFileOpen.text")); // NOI18N
bnDatabasePathFileOpen.addActionListener(new java.awt.event.ActionListener() {
@ -197,14 +207,27 @@ public class EamDbSettingsDialog extends JDialog {
});
org.openide.awt.Mnemonics.setLocalizedText(lbHostName, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbHostName.text")); // NOI18N
lbHostName.setPreferredSize(new java.awt.Dimension(80, 14));
tbDbHostname.setPreferredSize(new java.awt.Dimension(509, 20));
org.openide.awt.Mnemonics.setLocalizedText(lbPort, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbPort.text")); // NOI18N
lbPort.setPreferredSize(new java.awt.Dimension(80, 14));
tbDbPort.setPreferredSize(new java.awt.Dimension(509, 20));
org.openide.awt.Mnemonics.setLocalizedText(lbUserName, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbUserName.text")); // NOI18N
lbUserName.setPreferredSize(new java.awt.Dimension(80, 14));
tbDbUsername.setPreferredSize(new java.awt.Dimension(509, 20));
org.openide.awt.Mnemonics.setLocalizedText(lbUserPassword, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbUserPassword.text")); // NOI18N
lbUserPassword.setPreferredSize(new java.awt.Dimension(80, 14));
jpDbPassword.setPreferredSize(new java.awt.Dimension(509, 20));
cbDatabaseType.setModel(new javax.swing.DefaultComboBoxModel<>(new EamDbPlatformEnum[]{EamDbPlatformEnum.POSTGRESQL, EamDbPlatformEnum.SQLITE}));
cbDatabaseType.setPreferredSize(new java.awt.Dimension(120, 20));
cbDatabaseType.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbDatabaseTypeActionPerformed(evt);
@ -212,12 +235,25 @@ public class EamDbSettingsDialog extends JDialog {
});
org.openide.awt.Mnemonics.setLocalizedText(lbSingleUserSqLite, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbSingleUserSqLite.text")); // NOI18N
lbSingleUserSqLite.setPreferredSize(new java.awt.Dimension(381, 14));
org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseType, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbDatabaseType.text")); // NOI18N
lbDatabaseType.setMaximumSize(new java.awt.Dimension(80, 14));
lbDatabaseType.setMinimumSize(new java.awt.Dimension(80, 14));
lbDatabaseType.setPreferredSize(new java.awt.Dimension(80, 14));
org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseDesc, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbDatabaseDesc.text")); // NOI18N
lbDatabaseDesc.setPreferredSize(new java.awt.Dimension(80, 14));
org.openide.awt.Mnemonics.setLocalizedText(lbFullDbPath, org.openide.util.NbBundle.getMessage(EamDbSettingsDialog.class, "EamDbSettingsDialog.lbFullDbPath.text")); // NOI18N
dataBaseFileScrollPane.setBorder(null);
dataBaseFileTextArea.setEditable(false);
dataBaseFileTextArea.setBackground(new java.awt.Color(240, 240, 240));
dataBaseFileTextArea.setColumns(20);
dataBaseFileTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
dataBaseFileTextArea.setLineWrap(true);
dataBaseFileTextArea.setRows(3);
dataBaseFileScrollPane.setViewportView(dataBaseFileTextArea);
javax.swing.GroupLayout pnSQLiteSettingsLayout = new javax.swing.GroupLayout(pnSQLiteSettings);
pnSQLiteSettings.setLayout(pnSQLiteSettingsLayout);
@ -226,34 +262,30 @@ public class EamDbSettingsDialog extends JDialog {
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lbHostName)
.addComponent(lbPort)
.addComponent(lbUserName)
.addComponent(lbDatabaseType)
.addComponent(lbHostName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbDatabaseType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(lbDatabasePath, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbUserPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(lbDatabaseDesc))
.addComponent(lbDatabaseDesc, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbUserPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGap(10, 10, 10)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lbFullDbPath, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
.addComponent(tfDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(bnDatabasePathFileOpen))
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
.addComponent(cbDatabaseType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lbSingleUserSqLite, javax.swing.GroupLayout.DEFAULT_SIZE, 467, Short.MAX_VALUE)
.addGap(9, 9, 9))
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
.addComponent(tfDatabasePath)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnDatabasePathFileOpen)
.addGap(11, 11, 11))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnSQLiteSettingsLayout.createSequentialGroup()
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(tbDbHostname, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jpDbPassword, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tbDbUsername)
.addComponent(tbDbPort, javax.swing.GroupLayout.Alignment.LEADING))
.addGap(10, 10, 10))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbSingleUserSqLite, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jpDbPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(tbDbUsername, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(tbDbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(tbDbHostname, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(dataBaseFileScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 509, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
.addGap(55, 55, 55)
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
@ -266,35 +298,36 @@ public class EamDbSettingsDialog extends JDialog {
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cbDatabaseType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbSingleUserSqLite))
.addComponent(lbDatabaseType, javax.swing.GroupLayout.Alignment.TRAILING))
.addComponent(lbSingleUserSqLite, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lbDatabaseType, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lbDatabasePath)
.addComponent(tfDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(tfDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bnDatabasePathFileOpen))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(tbDbHostname, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbHostName))
.addComponent(lbHostName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(tbDbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbPort))
.addComponent(lbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(tbDbUsername, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbUserName))
.addComponent(lbUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jpDbPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbUserPassword))
.addComponent(lbUserPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lbFullDbPath, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbDatabaseDesc, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
.addComponent(lbDatabaseDesc, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(dataBaseFileScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
@ -312,11 +345,11 @@ public class EamDbSettingsDialog extends JDialog {
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(pnSQLiteSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE)
.addContainerGap()
.addComponent(pnSQLiteSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnButtons, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(10, 10, 10))
.addContainerGap())
);
pack();
@ -357,6 +390,7 @@ public class EamDbSettingsDialog extends JDialog {
}
try {
tfDatabasePath.setText(databaseFile.getCanonicalPath());
tfDatabasePath.setCaretPosition(tfDatabasePath.getText().length());
valid();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to get path of selected database file", ex); // NON-NLS
@ -584,14 +618,15 @@ public class EamDbSettingsDialog extends JDialog {
}//GEN-LAST:event_cbDatabaseTypeActionPerformed
private void updateFullDbPath() {
lbFullDbPath.setText(tfDatabasePath.getText() + File.separator + CENTRAL_REPO_DB_NAME + CENTRAL_REPO_SQLITE_EXT);
dataBaseFileTextArea.setText(tfDatabasePath.getText() + File.separator + CENTRAL_REPO_DB_NAME + CENTRAL_REPO_SQLITE_EXT);
dataBaseFileTextArea.setCaretPosition(dataBaseFileTextArea.getText().length());
}
private void displayDatabaseSettings(boolean isPostgres) {
lbDatabasePath.setVisible(!isPostgres);
tfDatabasePath.setVisible(!isPostgres);
lbDatabaseDesc.setVisible(!isPostgres);
lbFullDbPath.setVisible(!isPostgres);
dataBaseFileTextArea.setVisible(!isPostgres);
lbSingleUserSqLite.setVisible(!isPostgres);
bnDatabasePathFileOpen.setVisible(!isPostgres);
lbHostName.setVisible(isPostgres);
@ -855,13 +890,14 @@ public class EamDbSettingsDialog extends JDialog {
private javax.swing.ButtonGroup bnGrpDatabasePlatforms;
private javax.swing.JButton bnOk;
private javax.swing.JComboBox<EamDbPlatformEnum> cbDatabaseType;
private javax.swing.JScrollPane dataBaseFileScrollPane;
private javax.swing.JTextArea dataBaseFileTextArea;
private javax.swing.JFileChooser fcDatabasePath;
private javax.swing.Box.Filler filler1;
private javax.swing.JPasswordField jpDbPassword;
private javax.swing.JLabel lbDatabaseDesc;
private javax.swing.JLabel lbDatabasePath;
private javax.swing.JLabel lbDatabaseType;
private javax.swing.JLabel lbFullDbPath;
private javax.swing.JLabel lbHostName;
private javax.swing.JLabel lbPort;
private javax.swing.JLabel lbSingleUserSqLite;

View File

@ -7,6 +7,7 @@
</NonVisualComponents>
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
@ -49,16 +50,16 @@
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
<Component id="taInstructions" min="-2" pref="34" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="180" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="254" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="lbWarningMsg" min="-2" pref="25" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -132,6 +132,7 @@ final class ManageCorrelationPropertiesDialog extends javax.swing.JDialog {
taInstructions = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setResizable(false);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(ManageCorrelationPropertiesDialog.class, "ManageCorrelationPropertiesDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
@ -220,14 +221,14 @@ final class ManageCorrelationPropertiesDialog extends javax.swing.JDialog {
.addGap(20, 20, 20)
.addComponent(taInstructions, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 180, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lbWarningMsg, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(okButton)
.addComponent(cancelButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
pack();

View File

@ -3,7 +3,10 @@
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[545, 415]"/>
<Dimension value="[600, 450]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[600, 450]"/>
</Property>
</Properties>
<SyntheticProperties>
@ -27,7 +30,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="manageOrganizationsScrollPane" max="32767" attributes="0"/>
<Component id="manageOrganizationsScrollPane" pref="603" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -35,7 +38,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="manageOrganizationsScrollPane" max="32767" attributes="0"/>
<Component id="manageOrganizationsScrollPane" pref="443" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -159,7 +159,8 @@ public final class ManageOrganizationsDialog extends JDialog {
editButton = new javax.swing.JButton();
orgDetailsLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(545, 415));
setMinimumSize(new java.awt.Dimension(600, 450));
setPreferredSize(new java.awt.Dimension(600, 450));
manageOrganizationsScrollPane.setMinimumSize(null);
manageOrganizationsScrollPane.setPreferredSize(new java.awt.Dimension(535, 415));
@ -331,13 +332,13 @@ public final class ManageOrganizationsDialog extends JDialog {
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(manageOrganizationsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(manageOrganizationsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 603, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(manageOrganizationsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(manageOrganizationsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 443, Short.MAX_VALUE))
);
pack();

View File

@ -123,9 +123,9 @@ public final class InstanceCountNode extends DisplayableItemNode {
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NO_DESCR, ""));
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
if (UserPreferences.getHideSCOColumns() == false) {
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), NO_DESCR, ""));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"), NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"), NO_DESCR, ""));
}
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount()));

View File

@ -72,7 +72,7 @@ final class AccountDeviceInstanceNode extends AbstractNode {
}
@Override
@NbBundle.Messages(value = {"AccountNode.device=Device", "AccountNode.accountName=Account", "AccountNode.accountType=Type", "AccountNode.messageCount=Messages"})
@NbBundle.Messages(value = {"AccountNode.device=Device", "AccountNode.accountName=Account", "AccountNode.accountType=Type", "AccountNode.messageCount=Items"})
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set properties = sheet.get(Sheet.PROPERTIES);

View File

@ -54,11 +54,9 @@ final class AccountDeviceInstanceNodeFactory extends ChildFactory<AccountDeviceI
final List<AccountDeviceInstance> accountDeviceInstancesWithRelationships =
commsManager.getAccountDeviceInstancesWithRelationships(commsFilter);
for (AccountDeviceInstance accountDeviceInstance : accountDeviceInstancesWithRelationships) {
//Filter out device accounts, in the table.
if (Account.Type.DEVICE.equals(accountDeviceInstance.getAccount().getAccountType()) ==false) {
long communicationsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, commsFilter);
accountDeviceInstanceKeys.add(new AccountDeviceInstanceKey(accountDeviceInstance, commsFilter, communicationsCount));
}
long communicationsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, commsFilter);
accountDeviceInstanceKeys.add(new AccountDeviceInstanceKey(accountDeviceInstance, commsFilter, communicationsCount));
}
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "Error getting filtered account device instances", tskCoreException);

View File

@ -75,6 +75,10 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
public AccountsBrowser() {
initComponents();
jSplitPane1.setResizeWeight(0.5);
jSplitPane1.setDividerLocation(0.75);
outline = outlineView.getOutline();
outlineView.setPropertyColumns(
"device", Bundle.AccountNode_device(),
@ -104,7 +108,7 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
accountDeviceInstances.add(((AccountDeviceInstanceNode) node).getAccountDeviceInstance());
filter = ((AccountDeviceInstanceNode)node).getFilter();
}
relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, filter));
relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, new HashSet<>(), filter));
}
});
@ -118,7 +122,7 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
final int rows = Math.min(100, outline.getRowCount());
for (int column = 0; column < outline.getModel().getColumnCount(); column++) {
for (int column = 0; column < outline.getColumnCount(); column++) {
int columnWidthLimit = 500;
int columnWidth = 0;

View File

@ -1,7 +1,7 @@
AccountNode.accountName=Account
AccountNode.accountType=Type
AccountNode.device=Device
AccountNode.messageCount=Messages
AccountNode.messageCount=Items
applyText=Apply
CTL_OpenCVTAction=Communications
CVTTopComponent.name=\ Communications Visualization

View File

@ -11,34 +11,10 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane">
<Properties>
@ -51,6 +27,11 @@
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</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="0.75" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents>
@ -85,11 +66,11 @@
</SubComponents>
</Container>
<Component class="org.sleuthkit.autopsy.communications.FiltersPanel" name="filtersPane">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[256, 495]"/>
</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="1" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="15" insetsBottom="15" insetsRight="5" anchor="18" weightX="0.25" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -22,12 +22,13 @@ import com.google.common.eventbus.Subscribe;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JTabbedPane;
import javax.swing.LayoutStyle;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.windows.Mode;
@ -67,7 +68,6 @@ public final class CVTTopComponent extends TopComponent {
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
proxyLookup.setNewLookups(lookup);
}
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
});
@ -93,39 +93,39 @@ public final class CVTTopComponent extends TopComponent {
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
GridBagConstraints gridBagConstraints;
browseVisualizeTabPane = new JTabbedPane();
accountsBrowser = new AccountsBrowser();
vizPanel = new VisualizationPanel();
filtersPane = new FiltersPanel();
setLayout(new GridBagLayout());
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.vizPanel.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), vizPanel); // NOI18N
filtersPane.setMinimumSize(new Dimension(256, 495));
GroupLayout layout = new GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(filtersPane, GroupLayout.PREFERRED_SIZE, 265, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.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())
);
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 0.75;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new Insets(15, 0, 15, 15);
add(browseVisualizeTabPane, gridBagConstraints);
browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 0.25;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new Insets(15, 15, 15, 5);
add(filtersPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents

View File

@ -11,493 +11,487 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="18"/>
<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,2,-54,0,0,1,-40"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="devicesPane" max="32767" attributes="0"/>
<Component id="accountTypesPane" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="filtersTitleLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="applyFiltersButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="refreshButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="dateRangePane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="needsRefreshLabel" max="32767" attributes="0"/>
</Group>
<Component id="limitPane" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="filtersTitleLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="applyFiltersButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="refreshButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="needsRefreshLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
<Component id="devicesPane" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="accountTypesPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dateRangePane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="limitPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="applyFiltersButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/tick.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.applyFiltersButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="filtersTitleLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/funnel.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.filtersTitleLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="accountTypesPane">
<Container class="javax.swing.JPanel" name="topPane">
<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="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="24" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0">
<Component id="accountTypesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="accountTypeRequiredLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="unCheckAllAccountTypesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="checkAllAccountTypesButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="accountTypesScrollPane" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" 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="3" attributes="0">
<Component id="accountTypesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="accountTypeRequiredLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="accountTypesScrollPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="checkAllAccountTypesButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="unCheckAllAccountTypesButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="unCheckAllAccountTypesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.unCheckAllAccountTypesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="unCheckAllAccountTypesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="accountTypesLabel">
<Component class="javax.swing.JLabel" name="filtersTitleLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/accounts.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/funnel.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.accountTypesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.filtersTitleLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="checkAllAccountTypesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.checkAllAccountTypesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkAllAccountTypesButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="accountTypesScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[2, 200]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="accountTypeListPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
</Layout>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="accountTypeRequiredLabel">
<Component class="javax.swing.JButton" name="refreshButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/error-icon-16.png"/>
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.accountTypeRequiredLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="applyFiltersButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/tick.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.applyFiltersButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="needsRefreshLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.needsRefreshLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="2"/>
</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="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="devicesPane">
<Container class="javax.swing.JScrollPane" name="scrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</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="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="devicesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="deviceRequiredLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="unCheckAllDevicesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="checkAllDevicesButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="devicesScrollPane" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="devicesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deviceRequiredLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="devicesScrollPane" pref="94" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="checkAllDevicesButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="unCheckAllDevicesButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="5" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="unCheckAllDevicesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.unCheckAllDevicesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="unCheckAllDevicesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="devicesLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/image.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.devicesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="checkAllDevicesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.checkAllDevicesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkAllDevicesButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="devicesScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 75]"/>
</Property>
</Properties>
<Container class="javax.swing.JPanel" name="mainPanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="devicesListPane">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[4, 100]"/>
</Property>
</Properties>
<Container class="javax.swing.JPanel" name="limitPane">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="0" insetsBottom="15" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="mostRecentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.mostRecentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="9" insetsBottom="0" insetsRight="9" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JComboBox" name="limitComboBox">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="6">
<StringItem index="0" value="All"/>
<StringItem index="1" value="10000"/>
<StringItem index="2" value="5000"/>
<StringItem index="3" value="1000"/>
<StringItem index="4" value="500"/>
<StringItem index="5" value="100"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="limitComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
<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="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="limitTitlePanel">
<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="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="9" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="limitHeaderLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.limitHeaderLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="limitErrorMsgLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/error-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.limitErrorMsgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="10"/>
</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="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="deviceRequiredLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/error-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.deviceRequiredLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="2"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="dateRangePane">
<Container class="javax.swing.JPanel" name="dateRangePane">
<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="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="endDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="startDatePicker" min="-2" max="-2" attributes="0"/>
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="endDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="startDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="startDatePicker" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="startCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="endDatePicker" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="endCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="startDatePicker" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="startCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="endDatePicker" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="endCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="com.github.lgooddatepicker.components.DatePicker" name="startDatePicker">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dateRangeLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/calendar.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.dateRangeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="startCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.startCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="startCheckBoxStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="endCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.endCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="endCheckBoxStateChanged"/>
</Events>
</Component>
<Component class="com.github.lgooddatepicker.components.DatePicker" name="endDatePicker">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="refreshButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="needsRefreshLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.needsRefreshLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="limitPane">
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="com.github.lgooddatepicker.components.DatePicker" name="startDatePicker">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dateRangeLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/calendar.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.dateRangeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="startCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.startCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="startCheckBoxStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="endCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.endCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="endCheckBoxStateChanged"/>
</Events>
</Component>
<Component class="com.github.lgooddatepicker.components.DatePicker" name="endDatePicker">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="devicesPane">
<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="2" ipadX="0" ipadY="100" insetsTop="15" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="limitHeaderLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="limitErrorMsgLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="mostRecentLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="limitComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" 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"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="limitHeaderLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="limitErrorMsgLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="mostRecentLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="limitComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="32" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="limitHeaderLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.limitHeaderLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="mostRecentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.mostRecentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="limitComboBox">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="6">
<StringItem index="0" value="All"/>
<StringItem index="1" value="10000"/>
<StringItem index="2" value="5000"/>
<StringItem index="3" value="1000"/>
<StringItem index="4" value="500"/>
<StringItem index="5" value="100"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="limitComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="limitErrorMsgLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/error-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.limitErrorMsgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="10"/>
</Properties>
</Component>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="unCheckAllDevicesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.unCheckAllDevicesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="unCheckAllDevicesButtonActionPerformed"/>
</Events>
<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="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="0" insetsRight="9" anchor="12" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="devicesLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/image.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.devicesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="9" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="checkAllDevicesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.checkAllDevicesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkAllDevicesButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JScrollPane" name="devicesScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 75]"/>
</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="1" gridWidth="3" 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.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="devicesListPane">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[4, 100]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
</Layout>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="deviceRequiredLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/error-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.deviceRequiredLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="2"/>
</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="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="9" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="accountTypesPane">
<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="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="unCheckAllAccountTypesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.unCheckAllAccountTypesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="unCheckAllAccountTypesButtonActionPerformed"/>
</Events>
<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="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="0" insetsRight="9" anchor="12" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="accountTypesLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/accounts.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.accountTypesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="checkAllAccountTypesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.checkAllAccountTypesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkAllAccountTypesButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JScrollPane" name="accountTypesScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[2, 200]"/>
</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="1" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="9" 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.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="accountTypeListPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="3"/>
</Layout>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="accountTypeRequiredLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/error-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.accountTypeRequiredLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="2"/>
</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="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>

View File

@ -53,6 +53,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent.COMPLETED;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.Account;
@ -63,6 +64,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.DataSource;
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
import static org.sleuthkit.datamodel.Relationship.Type.CONTACT;
@ -96,9 +98,10 @@ final public class FiltersPanel extends JPanel {
* Listens to ingest events to enable refresh button
*/
private final PropertyChangeListener ingestListener;
private final PropertyChangeListener ingestJobListener;
/**
* Flag that indicates the UI is not up-sto-date with respect to the case DB
* Flag that indicates the UI is not up-to-date with respect to the case DB
* and it should be refreshed (by reapplying the filters).
*/
private boolean needsRefresh;
@ -123,6 +126,11 @@ final public class FiltersPanel extends JPanel {
@NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"})
public FiltersPanel() {
initComponents();
CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true);
accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox());
accountTypeListPane.add(panel);
deviceRequiredLabel.setVisible(false);
accountTypeRequiredLabel.setVisible(false);
startDatePicker.setDate(LocalDate.now().minusWeeks(3));
@ -155,18 +163,30 @@ final public class FiltersPanel extends JPanel {
// Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
if (null != eventData
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
updateFilters(false);
&& (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()))
{
updateFilters(true);
needsRefresh = true;
validateFilters();
}
}
};
this.ingestJobListener = pce -> {
String eventType = pce.getPropertyName();
if (eventType.equals(COMPLETED.toString()) &&
updateFilters(true)) {
needsRefresh = true;
validateFilters();
}
}
};
applyFiltersButton.addActionListener(e -> applyFilters());
refreshButton.addActionListener(e -> applyFilters());
}
/**
@ -219,19 +239,26 @@ final public class FiltersPanel extends JPanel {
/**
* Updates the filter widgets to reflect he data sources/types in the case.
*/
private void updateFilters(boolean initialState) {
updateAccountTypeFilter();
updateDeviceFilter(initialState);
private boolean updateFilters(boolean initialState) {
boolean newAccountType = updateAccountTypeFilter(initialState);
boolean newDeviceFilter = updateDeviceFilter(initialState);
// both or either are true, return true;
return newAccountType || newDeviceFilter;
}
@Override
public void addNotify() {
super.addNotify();
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
IngestManager.getInstance().addIngestJobEventListener(ingestJobListener);
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
//clear the device filter widget when the case changes.
devicesMap.clear();
devicesListPane.removeAll();
accountTypeMap.clear();
accountTypeListPane.removeAll();
});
}
@ -239,69 +266,109 @@ final public class FiltersPanel extends JPanel {
public void removeNotify() {
super.removeNotify();
IngestManager.getInstance().removeIngestModuleEventListener(ingestListener);
IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener);
}
/**
* Populate the Account Types filter widgets
*
* @param selected the initial value for the account type checkbox
*
* @return True, if a new accountType was found
*/
private void updateAccountTypeFilter() {
//TODO: something like this commented code could be used to show only
//the account types that are found:
//final CommunicationsManager communicationsManager = Case.getCurrentOpenCase().getSleuthkitCase().getCommunicationsManager();
//List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
//accountTypesInUSe.forEach(...)
Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> {
if (type.equals(Account.Type.CREDIT_CARD)) {
//don't show a check box for credit cards
} else {
accountTypeMap.computeIfAbsent(type, t -> {
CheckBoxIconPanel panel = new CheckBoxIconPanel(
type.getDisplayName(),
new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type))));
panel.setSelected(true);
panel.addItemListener(validationListener);
private boolean updateAccountTypeFilter(boolean selected) {
boolean newOneFound = false;
try {
final CommunicationsManager communicationsManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
for (Account.Type type : accountTypesInUse) {
if (!accountTypeMap.containsKey(type) && !type.equals(Account.Type.CREDIT_CARD)) {
CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(type, selected);
accountTypeMap.put(type, panel.getCheckBox());
accountTypeListPane.add(panel);
if (t.equals(Account.Type.DEVICE)) {
//Deveice type filter is enabled based on whether we are in table or graph view.
panel.setEnabled(deviceAccountTypeEnabled);
}
return panel.getCheckBox();
});
}
});
}
newOneFound = true;
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to update to update Account Types Filter", ex);
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "A case is required to update the account types filter.", ex);
}
if (newOneFound) {
accountTypeListPane.revalidate();
}
return newOneFound;
}
/**
* Helper function to create a new instance of the CheckBoxIconPanel base on
* the Account.Type and initalState (check box state).
*
* @param type Account.Type to display on the panel
* @param initalState initial check box state
*
* @return instance of the CheckBoxIconPanel
*/
private CheckBoxIconPanel createAccoutTypeCheckBoxPanel(Account.Type type, boolean initalState) {
CheckBoxIconPanel panel = new CheckBoxIconPanel(
type.getDisplayName(),
new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type))));
panel.setSelected(initalState);
panel.addItemListener(validationListener);
return panel;
}
/**
* Populate the devices filter widgets
*
* @param selected Sets the initial state of device check box
*
* @return true if a new device was found
*/
private void updateDeviceFilter(boolean initialState) {
private boolean updateDeviceFilter(boolean selected) {
boolean newOneFound = false;
try {
final SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase();
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
//store the device id in the map, but display a datasource name in the UI.
devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> {
final JCheckBox jCheckBox = new JCheckBox(dsName, initialState);
jCheckBox.addItemListener(validationListener);
devicesListPane.add(jCheckBox);
return jCheckBox;
});
if(devicesMap.containsKey(dataSource.getDeviceId())) {
continue;
}
final JCheckBox jCheckBox = new JCheckBox(dsName, selected);
jCheckBox.addItemListener(validationListener);
devicesListPane.add(jCheckBox);
devicesMap.put(dataSource.getDeviceId(), jCheckBox);
newOneFound = true;
}
} catch (NoCurrentCaseException ex) {
logger.log(Level.INFO, "Filter update cancelled. Case is closed.");
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
}
if(newOneFound) {
devicesListPane.revalidate();
}
return newOneFound;
}
/**
* Given a list of subFilters, set the states of the panel controls
* accordingly.
*
* @param subFilters A list of subFilters
* @param commFilter Contains a list of subFilters
*/
public void setFilters(CommunicationsFilter commFilter) {
List<CommunicationsFilter.SubFilter> subFilters = commFilter.getAndFilters();
@ -317,7 +384,7 @@ final public class FiltersPanel extends JPanel {
}
/**
* Sets the state of the device filter checkboxes
* Sets the state of the device filter check boxes
*
* @param deviceFilter Selected devices
*/
@ -364,6 +431,12 @@ final public class FiltersPanel extends JPanel {
endDatePicker.setEnabled(state.isEnabled());
}
/**
* Sets the state of the most recent UI controls based on the current values
* in MostRecentFilter.
*
* @param filter The MostRecentFilter state to be set
*/
private void setMostRecentFilter(MostRecentFilter filter) {
int limit = filter.getLimit();
if(limit > 0) {
@ -392,135 +465,124 @@ final public class FiltersPanel extends JPanel {
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
applyFiltersButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/tick.png"))); // NOI18N
applyFiltersButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.applyFiltersButton.text")); // NOI18N
applyFiltersButton.setPreferredSize(null);
setLayout(new java.awt.GridBagLayout());
topPane.setLayout(new java.awt.GridBagLayout());
filtersTitleLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/funnel.png"))); // NOI18N
filtersTitleLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.filtersTitleLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
topPane.add(filtersTitleLabel, gridBagConstraints);
unCheckAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllAccountTypesButton.text")); // NOI18N
unCheckAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() {
refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
refreshButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.refreshButton.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
topPane.add(refreshButton, gridBagConstraints);
applyFiltersButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/tick.png"))); // NOI18N
applyFiltersButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.applyFiltersButton.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
topPane.add(applyFiltersButton, gridBagConstraints);
needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N
needsRefreshLabel.setForeground(new java.awt.Color(255, 0, 0));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
topPane.add(needsRefreshLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END;
gridBagConstraints.weightx = 1.0;
add(topPane, gridBagConstraints);
scrollPane.setBorder(null);
mainPanel.setLayout(new java.awt.GridBagLayout());
limitPane.setLayout(new java.awt.GridBagLayout());
mostRecentLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.mostRecentLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 9, 0, 9);
limitPane.add(mostRecentLabel, gridBagConstraints);
limitComboBox.setEditable(true);
limitComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "All", "10000", "5000", "1000", "500", "100" }));
limitComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
unCheckAllAccountTypesButtonActionPerformed(evt);
limitComboBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
limitPane.add(limitComboBox, gridBagConstraints);
accountTypesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/accounts.png"))); // NOI18N
accountTypesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypesLabel.text")); // NOI18N
limitTitlePanel.setLayout(new java.awt.GridBagLayout());
checkAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllAccountTypesButton.text")); // NOI18N
checkAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkAllAccountTypesButtonActionPerformed(evt);
}
});
limitHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitHeaderLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
limitTitlePanel.add(limitHeaderLabel, gridBagConstraints);
accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200));
limitErrorMsgLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N
limitErrorMsgLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitErrorMsgLabel.text")); // NOI18N
limitErrorMsgLabel.setForeground(new java.awt.Color(255, 0, 0));
limitErrorMsgLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
limitTitlePanel.add(limitErrorMsgLabel, gridBagConstraints);
accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.Y_AXIS));
accountTypesScrollPane.setViewportView(accountTypeListPane);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 9, 0);
limitPane.add(limitTitlePanel, gridBagConstraints);
accountTypeRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N
accountTypeRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypeRequiredLabel.text")); // NOI18N
accountTypeRequiredLabel.setForeground(new java.awt.Color(255, 0, 0));
accountTypeRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
javax.swing.GroupLayout accountTypesPaneLayout = new javax.swing.GroupLayout(accountTypesPane);
accountTypesPane.setLayout(accountTypesPaneLayout);
accountTypesPaneLayout.setHorizontalGroup(
accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, accountTypesPaneLayout.createSequentialGroup()
.addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(accountTypesPaneLayout.createSequentialGroup()
.addComponent(accountTypesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(accountTypeRequiredLabel))
.addGroup(accountTypesPaneLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(unCheckAllAccountTypesButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(checkAllAccountTypesButton))
.addGroup(accountTypesPaneLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(accountTypesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGap(0, 0, 0))
);
accountTypesPaneLayout.setVerticalGroup(
accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(accountTypesPaneLayout.createSequentialGroup()
.addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(accountTypesLabel)
.addComponent(accountTypeRequiredLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(accountTypesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(checkAllAccountTypesButton)
.addComponent(unCheckAllAccountTypesButton)))
);
unCheckAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllDevicesButton.text")); // NOI18N
unCheckAllDevicesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
unCheckAllDevicesButtonActionPerformed(evt);
}
});
devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/image.png"))); // NOI18N
devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N
checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N
checkAllDevicesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkAllDevicesButtonActionPerformed(evt);
}
});
devicesScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
devicesScrollPane.setMinimumSize(new java.awt.Dimension(27, 75));
devicesListPane.setMinimumSize(new java.awt.Dimension(4, 100));
devicesListPane.setLayout(new javax.swing.BoxLayout(devicesListPane, javax.swing.BoxLayout.Y_AXIS));
devicesScrollPane.setViewportView(devicesListPane);
deviceRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N
deviceRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.deviceRequiredLabel.text")); // NOI18N
deviceRequiredLabel.setForeground(new java.awt.Color(255, 0, 0));
deviceRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
javax.swing.GroupLayout devicesPaneLayout = new javax.swing.GroupLayout(devicesPane);
devicesPane.setLayout(devicesPaneLayout);
devicesPaneLayout.setHorizontalGroup(
devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(devicesPaneLayout.createSequentialGroup()
.addComponent(devicesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(deviceRequiredLabel))
.addGroup(devicesPaneLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(unCheckAllDevicesButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(checkAllDevicesButton))
.addGroup(devicesPaneLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(devicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
devicesPaneLayout.setVerticalGroup(
devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(devicesPaneLayout.createSequentialGroup()
.addGroup(devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(devicesLabel)
.addComponent(deviceRequiredLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(devicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(checkAllDevicesButton)
.addComponent(unCheckAllDevicesButton))
.addGap(5, 5, 5))
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(15, 0, 15, 0);
mainPanel.add(limitPane, gridBagConstraints);
startDatePicker.setEnabled(false);
@ -580,97 +642,178 @@ final public class FiltersPanel extends JPanel {
.addComponent(endCheckBox)))
);
refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
refreshButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.refreshButton.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0);
mainPanel.add(dateRangePane, gridBagConstraints);
needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N
needsRefreshLabel.setForeground(new java.awt.Color(255, 0, 0));
devicesPane.setLayout(new java.awt.GridBagLayout());
limitHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitHeaderLabel.text")); // NOI18N
mostRecentLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.mostRecentLabel.text")); // NOI18N
limitComboBox.setEditable(true);
limitComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "All", "10000", "5000", "1000", "500", "100" }));
limitComboBox.addActionListener(new java.awt.event.ActionListener() {
unCheckAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllDevicesButton.text")); // NOI18N
unCheckAllDevicesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
limitComboBoxActionPerformed(evt);
unCheckAllDevicesButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 9);
devicesPane.add(unCheckAllDevicesButton, gridBagConstraints);
limitErrorMsgLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N
limitErrorMsgLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitErrorMsgLabel.text")); // NOI18N
limitErrorMsgLabel.setForeground(new java.awt.Color(255, 0, 0));
limitErrorMsgLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/image.png"))); // NOI18N
devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 9, 0);
devicesPane.add(devicesLabel, gridBagConstraints);
javax.swing.GroupLayout limitPaneLayout = new javax.swing.GroupLayout(limitPane);
limitPane.setLayout(limitPaneLayout);
limitPaneLayout.setHorizontalGroup(
limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(limitPaneLayout.createSequentialGroup()
.addComponent(limitHeaderLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(limitErrorMsgLabel)
.addContainerGap())
.addGroup(limitPaneLayout.createSequentialGroup()
.addContainerGap()
.addComponent(mostRecentLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(limitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
limitPaneLayout.setVerticalGroup(
limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(limitPaneLayout.createSequentialGroup()
.addContainerGap()
.addGroup(limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(limitHeaderLabel)
.addComponent(limitErrorMsgLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(mostRecentLabel)
.addComponent(limitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 32, Short.MAX_VALUE))
);
checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N
checkAllDevicesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkAllDevicesButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0);
devicesPane.add(checkAllDevicesButton, gridBagConstraints);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(devicesPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(accountTypesPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(filtersTitleLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(refreshButton))
.addComponent(dateRangePane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(needsRefreshLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(limitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(filtersTitleLabel)
.addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(refreshButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(needsRefreshLabel)
.addGap(4, 4, 4)
.addComponent(devicesPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(accountTypesPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dateRangePane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(limitPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
devicesScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
devicesScrollPane.setMinimumSize(new java.awt.Dimension(27, 75));
devicesListPane.setMinimumSize(new java.awt.Dimension(4, 100));
devicesListPane.setLayout(new javax.swing.BoxLayout(devicesListPane, javax.swing.BoxLayout.Y_AXIS));
devicesScrollPane.setViewportView(devicesListPane);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
devicesPane.add(devicesScrollPane, gridBagConstraints);
deviceRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N
deviceRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.deviceRequiredLabel.text")); // NOI18N
deviceRequiredLabel.setForeground(new java.awt.Color(255, 0, 0));
deviceRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 9, 0);
devicesPane.add(deviceRequiredLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.ipady = 100;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0);
mainPanel.add(devicesPane, gridBagConstraints);
accountTypesPane.setLayout(new java.awt.GridBagLayout());
unCheckAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllAccountTypesButton.text")); // NOI18N
unCheckAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
unCheckAllAccountTypesButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 9);
accountTypesPane.add(unCheckAllAccountTypesButton, gridBagConstraints);
accountTypesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/accounts.png"))); // NOI18N
accountTypesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypesLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
accountTypesPane.add(accountTypesLabel, gridBagConstraints);
checkAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllAccountTypesButton.text")); // NOI18N
checkAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkAllAccountTypesButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0);
accountTypesPane.add(checkAllAccountTypesButton, gridBagConstraints);
accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200));
accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.PAGE_AXIS));
accountTypesScrollPane.setViewportView(accountTypeListPane);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0);
accountTypesPane.add(accountTypesScrollPane, gridBagConstraints);
accountTypeRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N
accountTypeRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypeRequiredLabel.text")); // NOI18N
accountTypeRequiredLabel.setForeground(new java.awt.Color(255, 0, 0));
accountTypeRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
accountTypesPane.add(accountTypeRequiredLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0);
mainPanel.add(accountTypesPane, gridBagConstraints);
scrollPane.setViewportView(mainPanel);
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;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0);
add(scrollPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
/**
@ -738,6 +881,11 @@ final public class FiltersPanel extends JPanel {
endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0);
}
/**
* Get a MostRecentFilter that based on the current state of the ui controls.
*
* @return A new instance of MostRecentFilter
*/
private MostRecentFilter getMostRecentFilter() {
String value = (String)limitComboBox.getSelectedItem();
if(value.trim().equalsIgnoreCase("all")){
@ -760,21 +908,6 @@ final public class FiltersPanel extends JPanel {
return new DateControlState (endDatePicker.getDate(), endCheckBox.isSelected());
}
/**
* Enable or disable the device account type filter. The filter should be
* disabled for the browse/table mode and enabled for the visualization.
*
* @param enable True to enable the device account type filter, False to
* disable it.
*/
void setDeviceAccountTypeEnabled(boolean enable) {
deviceAccountTypeEnabled = enable;
JCheckBox deviceCheckbox = accountTypeMap.get(Account.Type.DEVICE);
if (deviceCheckbox != null) {
deviceCheckbox.setEnabled(deviceAccountTypeEnabled);
}
}
/**
* Set the selection state of all the account type check boxes
*
@ -796,11 +929,11 @@ final public class FiltersPanel extends JPanel {
}
/**
* Helper method that sets all the checkboxes in the given map to the given
* Helper method that sets all the check boxes in the given map to the given
* selection state.
*
* @param map A map from anything to JCheckBoxes.
* @param selected The selection state to set all the checkboxes to.
* @param selected The selection state to set all the check boxes to.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private void setAllSelected(Map<?, JCheckBox> map, boolean selected) {
@ -931,11 +1064,15 @@ final public class FiltersPanel extends JPanel {
private final javax.swing.JLabel limitErrorMsgLabel = new javax.swing.JLabel();
private final javax.swing.JLabel limitHeaderLabel = new javax.swing.JLabel();
private final javax.swing.JPanel limitPane = new javax.swing.JPanel();
private final javax.swing.JPanel limitTitlePanel = new javax.swing.JPanel();
private final javax.swing.JPanel mainPanel = new javax.swing.JPanel();
private final javax.swing.JLabel mostRecentLabel = new javax.swing.JLabel();
private final javax.swing.JLabel needsRefreshLabel = new javax.swing.JLabel();
private final javax.swing.JButton refreshButton = new javax.swing.JButton();
private final javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane();
private final javax.swing.JCheckBox startCheckBox = new javax.swing.JCheckBox();
private final com.github.lgooddatepicker.components.DatePicker startDatePicker = new com.github.lgooddatepicker.components.DatePicker();
private final javax.swing.JPanel topPane = new javax.swing.JPanel();
private final javax.swing.JButton unCheckAllAccountTypesButton = new javax.swing.JButton();
private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton();
// End of variables declaration//GEN-END:variables

View File

@ -914,23 +914,24 @@ final public class VisualizationPanel extends JPanel {
Object[] selectionCells = graph.getSelectionCells();
if (selectionCells.length > 0) {
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
HashSet<AccountDeviceInstance> deviceInstances = new HashSet<>();
HashSet<AccountDeviceInstance> selectedNodes = new HashSet<>();
HashSet<SelectionInfo.GraphEdge> selectedEdges = new HashSet<>();
for (mxICell cell : selectedCells) {
if (cell.isEdge()) {
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance());
deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance());
selectedEdges.add(new SelectionInfo.GraphEdge(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance(),
((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance()));
} else if (cell.isVertex()) {
deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
selectedNodes.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
}
}
relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter));
relationshipBrowser.setSelectionInfo(new SelectionInfo(selectedNodes, selectedEdges, currentFilter));
} else {
relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter));
relationshipBrowser.setSelectionInfo(new SelectionInfo(new HashSet<>(), new HashSet<>(), currentFilter));
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

View File

@ -1,15 +1,21 @@
ContactDetailsPane.nameLabel.text=Placeholder
SummaryViewer.countsPanel.border.title=Counts
SummaryViewer.emailLabel.text=Emails:
SummaryViewer.contactsLabel.text=Contacts:
SummaryViewer.attachmentsLabel.text=Attachments:
SummaryViewer.attachmentsLabel.text=Media Attachments:
OutlineViewPanel.messageLabel.text=<Control Disabled>
SummaryViewer.messagesDataLabel.text=messages
SummaryViewer.callLogsDataLabel.text=callLogs
SummaryViewer.contactsDataLabel.text=contacts
SummaryViewer.emailDataLabel.text=emails
SummaryViewer.attachmentsDataLabel.text=attachments
SummaryViewer.messagesLabel.text=Messages:
SummaryViewer.callLogsLabel.text=Call Logs:
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
ThreadPane.backButton.text=<---
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
MessageViewer.threadsLabel.text=Select a Thread to View
MessageViewer.threadNameLabel.text=<threadName>
MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
MessageViewer.backButton.AccessibleContext.accessibleDescription=
MessageViewer.backButton.text=Threads
MessageViewer.showAllButton.text=All Messages

View File

@ -11,7 +11,7 @@ ContactsViewer_columnHeader_Name=Name
ContactsViewer_columnHeader_Phone=Phone
ContactsViewer_noContacts_message=<No contacts found for selected account>
ContactsViewer_tabTitle=Contacts
MediaViewer_Name=Media
MediaViewer_Name=Media Attachments
MessageNode_Node_Property_Attms=Attachments
MessageNode_Node_Property_Date=Date
MessageNode_Node_Property_From=From
@ -20,27 +20,39 @@ MessageNode_Node_Property_To=To
MessageNode_Node_Property_Type=Type
MessageViewer_columnHeader_Attms=Attachments
MessageViewer_columnHeader_Date=Date
MessageViewer_columnHeader_EarlyDate=Earliest Message
MessageViewer_columnHeader_From=From
MessageViewer_columnHeader_Subject=Subject
MessageViewer_columnHeader_To=To
MessageViewer_no_messages=<No messages found for selected account>
MessageViewer_tabTitle=Messages
MessageViewer_viewMessage_all=All
MessageViewer_viewMessage_calllogs=Call Logs
MessageViewer_viewMessage_selected=Selected
MessageViewer_viewMessage_unthreaded=Unthreaded
SummaryViewer.countsPanel.border.title=Counts
SummaryViewer.emailLabel.text=Emails:
SummaryViewer.contactsLabel.text=Contacts:
SummaryViewer.attachmentsLabel.text=Attachments:
SummaryViewer.attachmentsLabel.text=Media Attachments:
OutlineViewPanel.messageLabel.text=<Control Disabled>
SummaryViewer.messagesDataLabel.text=messages
SummaryViewer.callLogsDataLabel.text=callLogs
SummaryViewer.contactsDataLabel.text=contacts
SummaryViewer.emailDataLabel.text=emails
SummaryViewer.attachmentsDataLabel.text=attachments
SummaryViewer.messagesLabel.text=Messages:
SummaryViewer.callLogsLabel.text=Call Logs:
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
SummaryViewer_CaseRefNameColumn_Title=Case Name
SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Other Occurrences>
SummaryViewer_Creation_Date_Title=Creation Date
SummaryViewer_FileRefNameColumn_Title=Path
SummaryViewer_TabTitle=Summary
SummeryViewer_FileRef_Message=<Select one Accout to see File References>
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
ThreadPane.backButton.text=<---
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
MessageViewer.threadsLabel.text=Select a Thread to View
MessageViewer.threadNameLabel.text=<threadName>
MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
MessageViewer.backButton.AccessibleContext.accessibleDescription=
MessageViewer.backButton.text=Threads
MessageViewer.showAllButton.text=All Messages

View File

@ -17,34 +17,7 @@
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<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="propertySheet" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</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="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="propertySheet" pref="283" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="nameLabel">
<Properties>
@ -55,11 +28,21 @@
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="ContactDetailsPane.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="2" ipadX="0" ipadY="0" insetsTop="16" insetsLeft="15" insetsBottom="15" insetsRight="15" anchor="23" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
<Properties>
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
</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="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="15" insetsBottom="16" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -73,38 +73,36 @@ public final class ContactDetailsPane extends javax.swing.JPanel implements Expl
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer();
nameLabel = new javax.swing.JLabel();
propertySheet = new org.openide.explorer.propertysheet.PropertySheet();
setLayout(new java.awt.GridBagLayout());
nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(16, 15, 15, 15);
add(nameLabel, gridBagConstraints);
propertySheet.setDescriptionAreaVisible(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(nameLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(nameLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE)
.addContainerGap())
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(9, 15, 16, 15);
add(propertySheet, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents

View File

@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* ChildFactory for ContactNodes.
*/
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
private static final Logger logger = Logger.getLogger(ContactsChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
@ -68,36 +68,28 @@ final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
*/
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
return false;
}
if(selectionInfo == null) {
return true;
}
final Set<Content> relationshipSources;
try {
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == TSK_CONTACT) {
list.add(bba);
}
});
relationshipSources = selectionInfo.getRelationshipSources();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS
return false;
}
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == TSK_CONTACT) {
list.add(bba);
}
});
return true;
}

View File

@ -11,29 +11,38 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane" name="contactPane">
</Component>
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
</Component>
<Container class="javax.swing.JSplitPane" name="splitPane">
<Properties>
<Property name="orientation" type="int" value="0"/>
</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>
</Form>

View File

@ -23,7 +23,6 @@ import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
@ -126,6 +125,9 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer{
updateOutlineViewPanel();
}
});
splitPane.setResizeWeight(0.5);
splitPane.setDividerLocation(0.5);
}
@Override
@ -183,29 +185,32 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer{
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
splitPane = new javax.swing.JSplitPane();
contactPane = new org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane();
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(outlineViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(outlineViewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, 332, Short.MAX_VALUE))
);
setLayout(new java.awt.GridBagLayout());
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
splitPane.setRightComponent(contactPane);
splitPane.setLeftComponent(outlineViewPanel);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(splitPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane contactPane;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -11,58 +11,57 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail" name="thumbnailViewer">
<Container class="javax.swing.JSplitPane" name="splitPane">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[350, 102]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 400]"/>
</Property>
<Property name="orientation" type="int" value="0"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM)"/>
</AuxValues>
</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>
</Component>
<Component class="javax.swing.JSeparator" name="separator">
</Component>
<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="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail" name="thumbnailViewer">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[350, 102]"/>
</Property>
<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 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>
</Form>

View File

@ -59,12 +59,17 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
private final ModifiableProxyLookup proxyLookup;
@Messages({
"MediaViewer_Name=Media"
"MediaViewer_Name=Media Attachments"
})
/**
* Creates new form ThumbnailViewer
*/
public MediaViewer() {
initComponents();
splitPane.setResizeWeight(0.5);
splitPane.setDividerLocation(0.5);
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
// 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) -> {
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
handleNodeSelectionChange();
@ -110,26 +113,21 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
@Override
public void setSelectionInfo(SelectionInfo info) {
final Set<Content> relationshipSources;
CommunicationsManager communicationManager;
Set<Content> relationshipSources;
Set<BlackboardArtifact> artifactList = new HashSet<>();
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
relationshipSources = communicationManager.getRelationshipSources(info.getAccountDevicesInstances(), info.getCommunicationsFilter());
relationshipSources = info.getRelationshipSources();
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
artifactList.add((BlackboardArtifact) content);
});
} catch (TskCoreException | NoCurrentCaseException ex) {
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to update selection." , ex);
}
if(artifactList.size() == 0) {
thumbnailViewer.resetComponent();
}
thumbnailViewer.resetComponent();
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentsChildren(artifactList)), tableEM), true, this.getClass().getName()));
}
@ -190,43 +188,37 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
splitPane = new javax.swing.JSplitPane();
thumbnailViewer = new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM);
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.setPreferredSize(new java.awt.Dimension(450, 400));
splitPane.setLeftComponent(thumbnailViewer);
contentViewer.setPreferredSize(new java.awt.Dimension(450, 400));
splitPane.setRightComponent(contentViewer);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(thumbnailViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.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))
);
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;
gridBagConstraints.weighty = 1.0;
add(splitPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
private javax.swing.JSeparator separator;
private javax.swing.JSplitPane splitPane;
private org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail thumbnailViewer;
// End of variables declaration//GEN-END:variables

View File

@ -18,16 +18,13 @@
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Level;
import javax.swing.Action;
import org.apache.commons.lang3.StringUtils;
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.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -40,24 +37,35 @@ 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_SUBJECT;
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.TskCoreException;
import org.sleuthkit.autopsy.communications.Utils;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
/**
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
*/
final class MessageNode extends BlackboardArtifactNode {
class MessageNode extends BlackboardArtifactNode {
public static final String UNTHREADED_ID = "<UNTHREADED>";
public static final String CALL_LOG_ID = "<CALLLOG>";
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
private final String threadID;
private final Action preferredAction;
MessageNode(BlackboardArtifact artifact) {
MessageNode(BlackboardArtifact artifact, String threadID, Action preferredAction) {
super(artifact);
this.preferredAction = preferredAction;
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
this.threadID = threadID;
}
@Messages({
@ -72,7 +80,6 @@ final class MessageNode extends BlackboardArtifactNode {
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
List<Tag> tags = getAllTagsFromDatabase();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
@ -80,19 +87,15 @@ final class MessageNode extends BlackboardArtifactNode {
}
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();
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) {
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",CALL_LOG_ID)); //NON-NLS
} else {
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS
}
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (null != fromID) {
@ -183,4 +186,13 @@ final class MessageNode extends BlackboardArtifactNode {
public String getSourceName() {
return getDisplayName();
}
String getThreadID() {
return threadID;
}
@Override
public Action getPreferredAction() {
return preferredAction;
}
}

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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,-126,0,0,2,-76"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="rootMessagesPane">
<Properties>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="threads"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="threadsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.threadsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="15" insetsBottom="9" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="showAllButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.showAllButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showAllButtonActionPerformed"/>
</Events>
<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="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="15" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="rootTablePane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
<LineBorder/>
</Border>
</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="1" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="9" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="messagePanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="messages"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.communications.relationships.MessagesPanel" name="threadMessagesPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessagesPanel()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="0" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="backButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.backButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.backButton.AccessibleContext.accessibleDescription" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="backButtonActionPerformed"/>
</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="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="9" insetsRight="15" anchor="13" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="showingMessagesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.showingMessagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="15" insetsBottom="5" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="threadNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.threadNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="5" insetsBottom="5" insetsRight="15" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,444 @@
/*
* 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.communications.relationships;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Node.Property;
import org.openide.nodes.Node.PropertySet;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* The main panel for the messages tab of the RelationshipViewer
*
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class MessageViewer extends JPanel implements RelationshipsViewer {
private static final Logger logger = Logger.getLogger(MessageViewer.class.getName());
private final ModifiableProxyLookup proxyLookup;
private final PropertyChangeListener focusPropertyListener;
private final ThreadChildNodeFactory rootMessageFactory;
private final MessagesChildNodeFactory threadMessageNodeFactory;
private SelectionInfo currentSelectionInfo = null;
OutlineViewPanel currentPanel;
@Messages({
"MessageViewer_tabTitle=Messages",
"MessageViewer_columnHeader_From=From",
"MessageViewer_columnHeader_Date=Date",
"MessageViewer_columnHeader_To=To",
"MessageViewer_columnHeader_EarlyDate=Earliest Message",
"MessageViewer_columnHeader_Subject=Subject",
"MessageViewer_columnHeader_Attms=Attachments",
"MessageViewer_no_messages=<No messages found for selected account>",
"MessageViewer_viewMessage_all=All",
"MessageViewer_viewMessage_selected=Selected",
"MessageViewer_viewMessage_unthreaded=Unthreaded",
"MessageViewer_viewMessage_calllogs=Call Logs"})
/**
* Creates new form MessageViewer
*/
public MessageViewer() {
initComponents();
currentPanel = rootTablePane;
proxyLookup = new ModifiableProxyLookup(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
rootMessageFactory = new ThreadChildNodeFactory(new ShowThreadMessagesAction());
threadMessageNodeFactory = new MessagesChildNodeFactory();
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
// explaination of focusPropertyListener
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
final Component newFocusOwner = (Component) focusEvent.getNewValue();
if (newFocusOwner == null) {
return;
}
if (isDescendingFrom(newFocusOwner, rootTablePane)) {
proxyLookup.setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, MessageViewer.this)) {
proxyLookup.setNewLookups(createLookup(currentPanel.getExplorerManager(), getActionMap()));
}
}
};
rootTablePane.getExplorerManager().setRootContext(
new AbstractNode(Children.create(rootMessageFactory, true)));
rootTablePane.getOutlineView().setPopupAllowed(false);
Outline outline = rootTablePane.getOutlineView().getOutline();
rootTablePane.getOutlineView().setPropertyColumns(
"Date", Bundle.MessageViewer_columnHeader_EarlyDate(),
"Subject", Bundle.MessageViewer_columnHeader_Subject()
);
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type");
outline.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
rootTablePane.getExplorerManager().addPropertyChangeListener((PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
showSelectedThread();
}
});
threadMessagesPanel.setChildFactory(threadMessageNodeFactory);
rootTablePane.setTableColumnsWidth(10, 20, 70);
Image image = getScaledImage((new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))).getImage(), 16, 16);
backButton.setIcon(new ImageIcon(image) );
}
@Override
public String getDisplayName() {
return Bundle.MessageViewer_tabTitle();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
currentSelectionInfo = info;
currentPanel = rootTablePane;
CardLayout layout = (CardLayout) this.getLayout();
layout.show(this, "threads");
rootMessageFactory.refresh(info);
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@Override
public void addNotify() {
super.addNotify();
//add listener that maintains correct selection in the Global Actions Context
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner", focusPropertyListener);
}
@Override
public void removeNotify() {
super.removeNotify();
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removePropertyChangeListener("focusOwner", focusPropertyListener);
}
@SuppressWarnings("rawtypes")
private void showSelectedThread() {
final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes();
if (nodes == null) {
return;
}
if (nodes.length == 0 || nodes.length > 1) {
return;
}
ArrayList<String> threadIDList = new ArrayList<>();
String subject = "";
PropertySet[] propertySets = nodes[0].getPropertySets();
for (PropertySet pset : propertySets) {
Property[] properties = pset.getProperties();
for (Property prop : properties) {
if (prop.getName().equalsIgnoreCase("threadid")) {
try {
String threadID = prop.getValue().toString();
if (!threadIDList.contains(threadID)) {
threadIDList.add(threadID);
}
} catch (IllegalAccessException | InvocationTargetException ex) {
logger.log(Level.WARNING, String.format("Unable to get threadid for node: %s", nodes[0].getDisplayName()), ex);
}
} else if (prop.getName().equalsIgnoreCase("subject")) {
try {
subject = prop.getValue().toString();
} catch (IllegalAccessException | InvocationTargetException ex) {
logger.log(Level.WARNING, String.format("Unable to get subject for node: %s", nodes[0].getDisplayName()), ex);
subject = "<unavailable>";
}
}
}
}
if (!threadIDList.isEmpty()) {
threadMessageNodeFactory.refresh(currentSelectionInfo, threadIDList);
if (!subject.isEmpty()) {
threadNameLabel.setText(subject);
} else {
if (threadIDList.contains(MessageNode.CALL_LOG_ID)) {
threadNameLabel.setText(Bundle.MessageViewer_viewMessage_calllogs());
} else {
threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded());
}
}
showMessagesPane();
}
}
/**
* Make the threads pane visible.
*/
private void showThreadsPane() {
switchCard("threads");
}
/**
* Make the message pane visible.
*/
private void showMessagesPane() {
switchCard("messages");
}
/**
* Changes the visible panel (card).
*
* @param cardName Name of card to show
*/
private void switchCard(String cardName) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
CardLayout layout = (CardLayout)getLayout();
layout.show(MessageViewer.this, cardName);
}
});
}
/**
* Scales the given image to the given width and height.
*
* @param srcImg Image to scale
* @param w Image width
* @param h Image height
*
* @return Scaled version of srcImg
*/
private Image getScaledImage(Image srcImg, int w, int h){
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.'
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
rootMessagesPane = new javax.swing.JPanel();
threadsLabel = new javax.swing.JLabel();
showAllButton = new javax.swing.JButton();
rootTablePane = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
messagePanel = new javax.swing.JPanel();
threadMessagesPanel = new MessagesPanel();
backButton = new javax.swing.JButton();
showingMessagesLabel = new javax.swing.JLabel();
threadNameLabel = new javax.swing.JLabel();
setLayout(new java.awt.CardLayout());
rootMessagesPane.setOpaque(false);
rootMessagesPane.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(threadsLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(15, 15, 9, 0);
rootMessagesPane.add(threadsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(showAllButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showAllButton.text")); // NOI18N
showAllButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showAllButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 15, 15, 0);
rootMessagesPane.add(showAllButton, gridBagConstraints);
rootTablePane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 15, 9, 15);
rootMessagesPane.add(rootTablePane, gridBagConstraints);
add(rootMessagesPane, "threads");
messagePanel.setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15);
messagePanel.add(threadMessagesPanel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.text")); // NOI18N
backButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
backButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 9, 15);
messagePanel.add(backButton, gridBagConstraints);
backButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.AccessibleContext.accessibleDescription")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showingMessagesLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(9, 15, 5, 0);
messagePanel.add(showingMessagesLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadNameLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(9, 5, 5, 15);
messagePanel.add(threadNameLabel, gridBagConstraints);
add(messagePanel, "messages");
}// </editor-fold>//GEN-END:initComponents
private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
try {
rootTablePane.getExplorerManager().setSelectedNodes(new Node[0]);
} catch (PropertyVetoException ex) {
Exceptions.printStackTrace(ex);
}
showThreadsPane();
}//GEN-LAST:event_backButtonActionPerformed
private void showAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAllButtonActionPerformed
threadMessageNodeFactory.refresh(currentSelectionInfo, null);
threadNameLabel.setText("All Messages");
showMessagesPane();
}//GEN-LAST:event_showAllButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton backButton;
private javax.swing.JPanel messagePanel;
private javax.swing.JPanel rootMessagesPane;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel rootTablePane;
private javax.swing.JButton showAllButton;
private javax.swing.JLabel showingMessagesLabel;
private org.sleuthkit.autopsy.communications.relationships.MessagesPanel threadMessagesPanel;
private javax.swing.JLabel threadNameLabel;
private javax.swing.JLabel threadsLabel;
// End of variables declaration//GEN-END:variables
/**
* The preferred action of the table nodes.
*/
class ShowThreadMessagesAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
showSelectedThread();
}
});
}
}
}

View File

@ -18,98 +18,194 @@
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* ChildFactory that creates createKeys and nodes from a given selectionInfo for
* only emails, call logs and messages.
* A ChildFactory subclass for creating MessageNodes from a set of
* BlackboardArtifact objects.
*
*/
final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
public class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact>{
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
/**
* Construct a new MessageChildNodeFactory from the currently selectionInfo
*
* @param selectionInfo SelectionInfo object for the currently selected
* accounts
*/
MessagesChildNodeFactory(SelectionInfo selectionInfo) {
private List<String> threadIDs;
MessagesChildNodeFactory(SelectionInfo selectionInfo, List<String> threadIDs) {
this.selectionInfo = selectionInfo;
this.threadIDs = threadIDs;
}
MessagesChildNodeFactory() {
this(null, null);
}
/**
* Updates the current instance of selectionInfo and calls the refresh method.
*
* @param selectionInfo New instance of the currently selected accounts
* @param threadIDs A list of threadIDs to filter the keys by, null will
* return all keys for the selected accounts.
*/
public void refresh(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
public void refresh(SelectionInfo selectionInfo, List<String> threadIDs) {
this.threadIDs = threadIDs;
this.selectionInfo = selectionInfo;
refresh(true);
}
/**
* Creates a list of Keys (BlackboardArtifact) for only messages for the
* currently selected accounts
*
* @param list List of BlackboardArtifact to populate
*
* @return True on success
*/
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
return false;
}
if(selectionInfo == null) {
return true;
}
final Set<Content> relationshipSources;
try {
relationshipSources = selectionInfo.getRelationshipSources();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS
return false;
}
try {
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
for(Content content: relationshipSources) {
if( !(content instanceof BlackboardArtifact)){
continue;
}
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
if (fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
continue;
}
// We want email and message artifacts that do not have "threadIDs" to appear as one thread in the UI
// To achive this assign any artifact that does not have a threadID
// the "UNTHREADED_ID"
// All call logs will default to a single call logs thread
String artifactThreadID;
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) {
artifactThreadID = MessageNode.CALL_LOG_ID;
} else {
artifactThreadID = MessageNode.UNTHREADED_ID;
}
BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
if(attribute != null) {
artifactThreadID = attribute.getValueString();
}
if(threadIDs == null || threadIDs.contains(artifactThreadID)) {
list.add(bba);
}
});
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
logger.log(Level.SEVERE, "Failed to load artifacts for relationship sources.", ex); //NON-NLS
}
list.sort(new DateComparator());
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact key) {
return new MessageNode(key);
return new MessageNode(key, null, null);
}
/**
* A comparator class for comparing BlackboardArtifacts of type
* TSK_EMAIL_MSG, TSK_MESSAGE, and TSK_CALLLOG by their respective creation
* date-time.
*/
class DateComparator implements Comparator<BlackboardArtifact> {
@Override
public int compare(BlackboardArtifact bba1, BlackboardArtifact bba2) {
BlackboardAttribute attribute1 = null;
BlackboardAttribute attribute2 = null;
// Inializing to Long.MAX_VALUE so that if a BlackboardArtifact of
// any unexpected type is passed in, it will bubble to the top of
// the list.
long dateTime1 = Long.MAX_VALUE;
long dateTime2 = Long.MAX_VALUE;
if (bba1 != null) {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba1.getArtifactTypeID());
if (fromID != null) {
try {
switch (fromID) {
case TSK_EMAIL_MSG:
attribute1 = bba1.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
break;
case TSK_MESSAGE:
attribute1 = bba1.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
break;
case TSK_CALLLOG:
attribute1 = bba1.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
break;
default:
attribute1 = null;
break;
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to compare attributes for artifact %d", bba1.getArtifactID()), ex);
}
}
}
if (bba2 != null) {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba2.getArtifactTypeID());
if (fromID != null) {
try {
switch (fromID) {
case TSK_EMAIL_MSG:
attribute2 = bba2.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
break;
case TSK_MESSAGE:
attribute2 = bba2.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
break;
case TSK_CALLLOG:
attribute2 = bba2.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
break;
default:
attribute2 = null;
break;
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to compare attributes for artifact %d", bba2.getArtifactID()), ex);
}
}
}
if (attribute1 != null) {
dateTime1 = attribute1.getValueLong();
}
if (attribute2 != null) {
dateTime2 = attribute2.getValueLong();
}
return Long.compare(dateTime1, dateTime2);
}
}
}

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="splitPane">
<Properties>
<Property name="orientation" type="int" value="0"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<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>
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="messageContentViewer">
<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>
</Form>

View File

@ -6,7 +6,7 @@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@ -22,56 +22,38 @@ import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.NodeAdapter;
import org.openide.nodes.NodeMemberEvent;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
/**
* Visualation for the messages of the currently selected accounts.
*
* General Purpose class for panels that need OutlineView of message nodes at
* the top with a MessageContentViewer at the bottom.
*/
@ServiceProvider(service = RelationshipsViewer.class)
public final class MessagesViewer extends JPanel implements RelationshipsViewer {
public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider {
private final Outline outline;
private final ModifiableProxyLookup proxyLookup;
private final PropertyChangeListener focusPropertyListener;
private final MessagesChildNodeFactory nodeFactory;
@Messages({
"MessageViewer_tabTitle=Messages",
"MessageViewer_columnHeader_From=From",
"MessageViewer_columnHeader_To=To",
"MessageViewer_columnHeader_Date=Date",
"MessageViewer_columnHeader_Subject=Subject",
"MessageViewer_columnHeader_Attms=Attachments",
"MessageViewer_no_messages=<No messages found for selected account>"
})
/**
* Visualation for the messages of the currently selected accounts.
* Creates new form MessagesPanel
*/
public MessagesViewer() {
public MessagesPanel() {
initComponents();
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
nodeFactory = new MessagesChildNodeFactory(null);
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
// explaination of focusPropertyListener
@ -82,10 +64,10 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
if (newFocusOwner == null) {
return;
}
if (isDescendingFrom(newFocusOwner, contentViewer)) {
if (isDescendingFrom(newFocusOwner, messageContentViewer)) {
//if the focus owner is within the MessageContentViewer (the attachments table)
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) {
proxyLookup.setNewLookups(createLookup(((MessageDataContent) messageContentViewer).getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, MessagesPanel.this)) {
//... or if it is within the Results table.
proxyLookup.setNewLookups(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
@ -109,52 +91,24 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
final Node[] nodes = outlineViewPanel.getExplorerManager().getSelectedNodes();
if (nodes != null && nodes.length == 1) {
contentViewer.setNode(nodes[0]);
messageContentViewer.setNode(nodes[0]);
}
else {
contentViewer.setNode(null);
messageContentViewer.setNode(null);
}
}
});
outlineViewPanel.getExplorerManager().setRootContext(
new TableFilterNode(
new DataResultFilterNode(
new AbstractNode(
Children.create(nodeFactory, true)),
outlineViewPanel.getExplorerManager()),
true));
// When a new set of nodes are added to the OutlineView the childrenAdded
// seems to be fired before the childrenRemoved.
outlineViewPanel.getExplorerManager().getRootContext().addNodeListener(new NodeAdapter() {
@Override
public void childrenAdded(NodeMemberEvent nme) {
updateOutlineViewPanel();
}
@Override
public void childrenRemoved(NodeMemberEvent nme) {
updateOutlineViewPanel();
}
});
splitPane.setResizeWeight(0.5);
splitPane.setDividerLocation(0.5);
outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10);
}
@Override
public String getDisplayName() {
return Bundle.MessageViewer_tabTitle();
public MessagesPanel(ChildFactory<?> nodeFactory) {
this();
setChildFactory(nodeFactory);
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
nodeFactory.refresh(info);
}
@Override
public Lookup getLookup() {
return proxyLookup;
@ -174,16 +128,16 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removePropertyChangeListener("focusOwner", focusPropertyListener);
}
private void updateOutlineViewPanel() {
int nodeCount = outlineViewPanel.getExplorerManager().getRootContext().getChildren().getNodesCount();
if(nodeCount == 0) {
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
} else {
outlineViewPanel.showOutlineView();
}
}
final void setChildFactory(ChildFactory<?> nodeFactory) {
outlineViewPanel.getExplorerManager().setRootContext(
new TableFilterNode(
new DataResultFilterNode(
new AbstractNode(
Children.create(nodeFactory, true)),
outlineViewPanel.getExplorerManager()),true));
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -193,28 +147,23 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
contentViewer = new MessageDataContent();
splitPane = new javax.swing.JSplitPane();
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
messageContentViewer = new MessageDataContent();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(outlineViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(outlineViewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE))
);
setLayout(new java.awt.BorderLayout());
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
splitPane.setLeftComponent(outlineViewPanel);
splitPane.setRightComponent(messageContentViewer);
add(splitPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer messageContentViewer;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<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>
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
</AuxValues>
</Component>
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
</Component>
</SubComponents>
</Form>

View File

@ -20,11 +20,6 @@
</Layout>
<SubComponents>
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[300, 400]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="outlineCard"/>

View File

@ -19,7 +19,9 @@
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.CardLayout;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.explorer.view.OutlineView;
@ -98,6 +100,28 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
super.setEnabled(enabled);
outlineView.setEnabled(enabled);
}
/**
* Sets the width of the columns of the OutlineView based on the passed in
* list of percentages. There should be on double value for each column
* in the OutlineView.
*
* @param percentages A series of double percentages values representing
* what percent of the total width of the table each
* column should have.
*/
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.
@ -113,8 +137,6 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
messageLabel = new javax.swing.JLabel();
setLayout(new java.awt.CardLayout(5, 5));
outlineView.setPreferredSize(new java.awt.Dimension(300, 400));
add(outlineView, "outlineCard");
messagePanel.setLayout(new java.awt.BorderLayout());

View File

@ -13,40 +13,19 @@
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
</Properties>
<Container class="javax.swing.JTabbedPane" name="tabPane">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="tabPaneStateChanged"/>
</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="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.JScrollPaneSupportLayout"/>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
</Container>
</SubComponents>
</Form>

View File

@ -31,7 +31,7 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
private SelectionInfo currentSelection;
private final MessagesViewer messagesViewer;
private final MessageViewer messagesViewer;
private final ContactsViewer contactsViewer;
private final SummaryViewer summaryViewer;
private final MediaViewer mediaViewer;
@ -42,26 +42,23 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
* Creates new form RelationshipBrowser
*/
public RelationshipBrowser() {
messagesViewer = new MessagesViewer();
initComponents();
messagesViewer = new MessageViewer();
contactsViewer = new ContactsViewer();
summaryViewer = new SummaryViewer();
mediaViewer = new MediaViewer();
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
initComponents();
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
tabPane.add(mediaViewer.getDisplayName(), mediaViewer);
}
/**
* Sets the value of currentSelection and passes the SelectionInfo onto the
* currently selected\visible tab.
* currently selected, visible tab.
*
* @param info Currently selected account nodes
*/
@ -78,33 +75,25 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
scrollPane = new javax.swing.JScrollPane();
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() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
tabPaneStateChanged(evt);
}
});
scrollPane.setViewportView(tabPane);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING))
);
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))
);
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;
gridBagConstraints.weighty = 1.0;
add(tabPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
@ -121,7 +110,6 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane scrollPane;
private javax.swing.JTabbedPane tabPane;
// End of variables declaration//GEN-END:variables

View File

@ -40,7 +40,8 @@ public final class SelectionInfo {
private static final Logger logger = Logger.getLogger(SelectionInfo.class.getName());
private final Set<AccountDeviceInstance> accountDeviceInstances;
private final Set<AccountDeviceInstance> selectedNodes;
private final Set<GraphEdge> selectedEdges;
private final CommunicationsFilter communicationFilter;
private final Set<Account> accounts;
@ -50,26 +51,38 @@ public final class SelectionInfo {
/**
* Wraps the details of the currently selected accounts.
*
* @param accountDeviceInstances Selected accountDecivedInstances
* @param selectedNodes Selected AccountDeviceInstances
* @param selectedEdges Selected pairs of AccountDeviceInstances
* @param communicationFilter Currently selected communications filters
*/
public SelectionInfo(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter communicationFilter) {
this.accountDeviceInstances = accountDeviceInstances;
public SelectionInfo(Set<AccountDeviceInstance> selectedNodes, Set<GraphEdge> selectedEdges,
CommunicationsFilter communicationFilter) {
this.selectedNodes = selectedNodes;
this.selectedEdges = selectedEdges;
this.communicationFilter = communicationFilter;
accounts = new HashSet<>();
accountDeviceInstances.forEach((instance) -> {
selectedNodes.forEach((instance) -> {
accounts.add(instance.getAccount());
});
}
/**
* Returns the currently selected accountDeviceInstances
* Returns the currently selected nodes
*
* @return Set of AccountDeviceInstance
*/
public Set<AccountDeviceInstance> getAccountDevicesInstances() {
return accountDeviceInstances;
public Set<AccountDeviceInstance> getSelectedNodes() {
return selectedNodes;
}
/**
* Returns the currently selected edges
*
* @return Set of GraphEdge objects
*/
public Set<GraphEdge> getSelectedEdges() {
return selectedEdges;
}
/**
@ -85,28 +98,50 @@ public final class SelectionInfo {
return accounts;
}
/**
* Get the set of relationship sources from the case database
*
* @return the relationship sources (may be empty)
* @throws TskCoreException
*/
Set<Content> getRelationshipSources() throws TskCoreException {
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException ex) {
throw new TskCoreException("Failed to get current case", ex);
}
Set<Content> relationshipSources = new HashSet<>();
try {
// Add all nodes
relationshipSources.addAll(communicationManager.getRelationshipSources(getSelectedNodes(), getCommunicationsFilter()));
// Add all edges. For edges, the relationship has to include both endpoints
for (SelectionInfo.GraphEdge edge : getSelectedEdges()) {
relationshipSources.addAll(communicationManager.getRelationshipSources(edge.getStartNode(),
edge.getEndNode(), getCommunicationsFilter()));
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationships from case database.", ex); //NON-NLS
}
return relationshipSources;
}
public Set<BlackboardArtifact> getArtifacts() {
if(accountArtifacts == null) {
accountArtifacts = new HashSet<>();
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
return null;
}
final Set<Content> relationshipSources;
try {
relationshipSources = communicationManager.getRelationshipSources(getAccountDevicesInstances(), getCommunicationsFilter());
final Set<Content> relationshipSources = getRelationshipSources();
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
accountArtifacts.add((BlackboardArtifact) content);
});
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS
return accountArtifacts;
}
}
@ -182,4 +217,24 @@ public final class SelectionInfo {
}
}
/**
* Utility class to represent an edge from the graph visualization.
*/
public static class GraphEdge {
AccountDeviceInstance startNode;
AccountDeviceInstance endNode;
public GraphEdge(AccountDeviceInstance startNode, AccountDeviceInstance endNode) {
this.startNode = startNode;
this.endNode = endNode;
}
public AccountDeviceInstance getStartNode() {
return startNode;
}
public AccountDeviceInstance getEndNode() {
return endNode;
}
}
}

View File

@ -11,36 +11,10 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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,4,7,0,0,4,-35"/>
</AuxValues>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="countsPanel">
<Properties>
@ -52,6 +26,11 @@
</Border>
</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="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
@ -59,21 +38,19 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="attachmentsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="messagesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="callLogsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="contactsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="emailLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="emailDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="contactsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="callLogsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="messagesDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace pref="959" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -81,11 +58,6 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="attachmentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="messagesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="messagesDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
@ -102,8 +74,8 @@
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="emailLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="emailDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
@ -111,13 +83,6 @@
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="emailLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.emailLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="contactsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@ -174,16 +139,9 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="emailDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.emailDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="fileReferencesPanel">
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="fileReferencesPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
@ -192,12 +150,14 @@
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[472, 300]"/>
</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="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 class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="caseReferencesPanel">
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="caseReferencesPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
@ -206,10 +166,12 @@
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[472, 300]"/>
</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="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>
</SubComponents>
</Form>

View File

@ -46,8 +46,8 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
"SummaryViewer_FileRefNameColumn_Title=Path",
"SummaryViewer_CaseRefNameColumn_Title=Case Name",
"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>",})
/**
* Creates new form SummaryViewer
@ -70,6 +70,9 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_CaseRefNameColumn_Title());
clearControls();
caseReferencesPanel.hideOutlineView(Bundle.SummaryViewer_CentralRepository_Message());
fileReferencesPanel.hideOutlineView(Bundle.SummeryViewer_FileRef_Message());
}
@Override
@ -97,14 +100,16 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
setEnabled(false);
clearControls();
fileReferencesPanel.hideOutlineView(Bundle.SummeryViewer_FileRef_Message());
} else {
SelectionSummary summaryDetails = info.getSummary();
attachmentsDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt()));
contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt()));
emailDataLabel.setText(Integer.toString(summaryDetails.getEmailCnt()));
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt()));
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt() + summaryDetails.getEmailCnt()));
fileReferencesPanel.showOutlineView();
fileReferencesPanel.setNode(new AbstractNode(Children.create(new AccountSourceContentChildNodeFactory(info.getAccounts()), true)));
caseReferencesPanel.setNode(new AbstractNode(Children.create(new CorrelationCaseChildNodeFactory(info.getAccounts()), true)));
@ -129,7 +134,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
attachmentsLabel.setEnabled(enabled);
callLogsLabel.setEnabled(enabled);
contactsLabel.setEnabled(enabled);
emailLabel.setEnabled(enabled);
messagesLabel.setEnabled(enabled);
caseReferencesPanel.setEnabled(enabled);
fileReferencesPanel.setEnabled(enabled);
@ -143,7 +147,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
attachmentsDataLabel.setText("");
callLogsDataLabel.setText("");
contactsDataLabel.setText("");
emailDataLabel.setText("");
messagesDataLabel.setText("");
fileReferencesPanel.setNode(new AbstractNode(Children.LEAF));
@ -178,9 +181,9 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
countsPanel = new javax.swing.JPanel();
emailLabel = new javax.swing.JLabel();
contactsLabel = new javax.swing.JLabel();
messagesLabel = new javax.swing.JLabel();
callLogsLabel = new javax.swing.JLabel();
@ -189,13 +192,12 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
messagesDataLabel = new javax.swing.JLabel();
callLogsDataLabel = new javax.swing.JLabel();
contactsDataLabel = new javax.swing.JLabel();
emailDataLabel = new javax.swing.JLabel();
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N
setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(emailLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailLabel.text")); // NOI18N
countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(contactsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsLabel.text")); // NOI18N
@ -213,8 +215,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
org.openide.awt.Mnemonics.setLocalizedText(contactsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(emailDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailDataLabel.text")); // NOI18N
javax.swing.GroupLayout countsPanelLayout = new javax.swing.GroupLayout(countsPanel);
countsPanel.setLayout(countsPanelLayout);
countsPanelLayout.setHorizontalGroup(
@ -222,28 +222,22 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
.addGroup(countsPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(attachmentsLabel)
.addComponent(messagesLabel)
.addComponent(callLogsLabel)
.addComponent(contactsLabel)
.addComponent(emailLabel))
.addComponent(attachmentsLabel))
.addGap(18, 18, 18)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(emailDataLabel)
.addComponent(attachmentsDataLabel)
.addComponent(contactsDataLabel)
.addComponent(callLogsDataLabel)
.addComponent(messagesDataLabel)
.addComponent(attachmentsDataLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(messagesDataLabel))
.addContainerGap(959, Short.MAX_VALUE))
);
countsPanelLayout.setVerticalGroup(
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(countsPanelLayout.createSequentialGroup()
.addGap(7, 7, 7)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(attachmentsLabel)
.addComponent(attachmentsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(messagesLabel)
.addComponent(messagesDataLabel))
@ -257,40 +251,38 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
.addComponent(contactsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(emailLabel)
.addComponent(emailDataLabel))
.addComponent(attachmentsLabel)
.addComponent(attachmentsDataLabel))
.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.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.setPreferredSize(new java.awt.Dimension(472, 300));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(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))
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(caseReferencesPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
@ -303,8 +295,6 @@ public class SummaryViewer extends javax.swing.JPanel implements RelationshipsVi
private javax.swing.JLabel contactsDataLabel;
private javax.swing.JLabel contactsLabel;
private javax.swing.JPanel countsPanel;
private javax.swing.JLabel emailDataLabel;
private javax.swing.JLabel emailLabel;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel fileReferencesPanel;
private javax.swing.JLabel messagesDataLabel;
private javax.swing.JLabel messagesLabel;

View File

@ -0,0 +1,347 @@
/*
* 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.communications.relationships;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.Action;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* ChildFactory that creates createKeys and nodes from a given selectionInfo for
* only emails, call logs and messages.
*
*/
final class ThreadChildNodeFactory extends ChildFactory<BlackboardArtifact> {
private static final Logger logger = Logger.getLogger(ThreadChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
private final Action preferredAction;
/**
* Construct a new ThreadChildNodeFactory from the currently selectionInfo
*
* @param preferredAction SelectionInfo object for the currently selected
* accounts
*/
ThreadChildNodeFactory(Action preferredAction) {
this.preferredAction = preferredAction;
}
/**
* Updates the current instance of selectionInfo and calls the refresh method.
*
* @param selectionInfo New instance of the currently selected accounts
*/
public void refresh(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
refresh(true);
}
/**
* Creates a list of Keys (BlackboardArtifact) for only messages for the
* currently selected accounts.
*
* @param list List of BlackboardArtifact to populate
*
* @return True on success
*/
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
if(selectionInfo == null) {
return true;
}
try {
final Set<Content> relationshipSources = selectionInfo.getRelationshipSources();
createRootMessageKeys(list, relationshipSources) ;
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS
return false;
}
return true;
}
/**
* Adds only BlackboardArtifact objects to the list where are the earliest
* message in a message thread (based on threadID). If there are "unthreaded"
* messages (messages that do not have a threadID) one representitive artifact
* will be added to the list and dealt with a node creation time.
*
* @param list List to populate with BlackboardArtifact keys
* @param relationshipSources Set of Content objects
* @return True on success
* @throws TskCoreException
*/
private boolean createRootMessageKeys(List<BlackboardArtifact> list, Set<Content> relationshipSources) throws TskCoreException{
Map<String, BlackboardArtifact> rootMessageMap = new HashMap<>();
for(Content content: relationshipSources) {
if(!(content instanceof BlackboardArtifact)) {
continue;
}
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
// We want email and message artifacts that do not have "threadIDs" to appear as one thread in the UI
// To achive this assign any artifact that does not have a threadID
// the "UNTHREADED_ID"
// All call logs will default to a single call logs thread
String threadID;
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) {
threadID = MessageNode.CALL_LOG_ID;
} else {
threadID = MessageNode.UNTHREADED_ID;
}
BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
if(attribute != null) {
threadID = attribute.getValueString();
}
BlackboardArtifact tableArtifact = rootMessageMap.get(threadID);
if(tableArtifact == null) {
rootMessageMap.put(threadID, bba);
} else {
// Get the date of the message
BlackboardAttribute tableAttribute = null;
switch(fromID) {
case TSK_EMAIL_MSG:
tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
// put the earliest message into the table
if(tableAttribute != null
&& attribute != null
&& tableAttribute.getValueLong() > attribute.getValueLong()) {
rootMessageMap.put(threadID, bba);
}
break;
case TSK_MESSAGE:
tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
// put the earliest message into the table
if(tableAttribute != null
&& attribute != null
&& tableAttribute.getValueLong() < attribute.getValueLong()) {
rootMessageMap.put(threadID, bba);
}
break;
case TSK_CALLLOG:
tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
// put the earliest message into the table
if(tableAttribute != null
&& attribute != null
&& tableAttribute.getValueLong() > attribute.getValueLong()) {
rootMessageMap.put(threadID, bba);
}
break;
}
}
}
}
for(BlackboardArtifact bba: rootMessageMap.values()) {
list.add(bba);
}
list.sort(new ThreadDateComparator());
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact bba) {
BlackboardAttribute attribute = null;
try {
attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to get threadID for artifact: %s", bba.getName()), ex);
}
if (attribute != null) {
return new ThreadNode(bba, attribute.getValueString(), preferredAction);
} else {
if (bba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) {
return new CallLogNode();
} else {
// Only one of these should occur.
return new UnthreadedNode();
}
}
}
/**
* This node represents the "call log" thread.
*/
final class CallLogNode extends AbstractNode {
/**
* Construct an instance of a CallLogNode.
*/
CallLogNode() {
super(Children.LEAF);
setDisplayName("Call Logs");
this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/unthreaded.png" );
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
// Give this node a threadID of "CALL_LOG_ID"
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.CALL_LOG_ID));
return sheet;
}
}
/**
* This node represents the "unthreaded" thread.
*/
final class UnthreadedNode extends AbstractNode {
/**
* Construct an instance of UnthreadNode.
*/
UnthreadedNode() {
super(Children.LEAF);
setDisplayName("Unthreaded");
this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/unthreaded.png" );
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
// Give this node a threadID of "UNTHEADED_ID"
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.UNTHREADED_ID));
return sheet;
}
}
/**
* A comparator class for comparing BlackboardArtifacts of type
* TSK_EMAIL_MSG, TSK_MESSAGE, and TSK_CALLLOG by their respective creation
* date-time.
*
* Nodes will be sorted newest to oldest.
*/
class ThreadDateComparator implements Comparator<BlackboardArtifact> {
@Override
public int compare(BlackboardArtifact bba1, BlackboardArtifact bba2) {
BlackboardAttribute attribute1 = null;
BlackboardAttribute attribute2 = null;
// Inializing to Long.MAX_VALUE so that if a BlackboardArtifact of
// any unexpected type is passed in, it will bubble to the top of
// the list.
long dateTime1 = Long.MAX_VALUE;
long dateTime2 = Long.MAX_VALUE;
if (bba1 != null) {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba1.getArtifactTypeID());
if (fromID != null) {
try {
switch (fromID) {
case TSK_EMAIL_MSG:
attribute1 = bba1.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
break;
case TSK_MESSAGE:
attribute1 = bba1.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
break;
case TSK_CALLLOG:
attribute1 = bba1.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
break;
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to compare attributes for artifact %d", bba1.getArtifactID()), ex);
}
}
}
if (bba1 != null) {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba2.getArtifactTypeID());
if (fromID != null) {
try {
switch (fromID) {
case TSK_EMAIL_MSG:
attribute2 = bba2.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
break;
case TSK_MESSAGE:
attribute2 = bba2.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
break;
case TSK_CALLLOG:
attribute2 = bba2.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
break;
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to compare attributes for artifact %d", bba2.getArtifactID()), ex);
}
}
}
if (attribute1 != null) {
dateTime1 = attribute1.getValueLong();
}
if (attribute2 != null) {
dateTime2 = attribute2.getValueLong();
}
return Long.compare(dateTime1, dateTime2) * -1;
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.communications.relationships;
import java.util.logging.Level;
import javax.swing.Action;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An AbstractNode subclass which wraps a MessageNode object. Doing this allows
* for the reuse of the createSheet and other function from MessageNode, but
* also some customizing of how a ThreadNode is shown.
*/
final class ThreadNode extends AbstractNode{
private static final Logger logger = Logger.getLogger(ThreadNode.class.getName());
private final static int MAX_SUBJECT_LENGTH = 120;
final private MessageNode messageNode;
ThreadNode(BlackboardArtifact artifact, String threadID, Action preferredAction) {
super(Children.LEAF);
messageNode = new MessageNode(artifact, threadID, preferredAction);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/threaded.png" );
}
@Override
protected Sheet createSheet() {
BlackboardArtifact artifact = messageNode.getArtifact();
if(artifact == null) {
return messageNode.createSheet() ;
}
Sheet sheet = messageNode.createSheet();
BlackboardArtifact.ARTIFACT_TYPE artifactTypeID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
// If its a text message, replace the subject node which is probably
// an empty string with the firest 120 characters of the text message
if(artifactTypeID != null && artifactTypeID == TSK_MESSAGE) {
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(TSK_TEXT.getTypeID())));
if(attribute != null) {
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
sheetSet.remove("Subject");
String msg = attribute.getDisplayString();
if(msg != null && msg.length() > MAX_SUBJECT_LENGTH) {
msg = msg.substring(0, MAX_SUBJECT_LENGTH) + "...";
}
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "", msg)); //NON-NLS
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to get the text message from message artifact %d", artifact.getId()), ex);
}
}
return sheet;
}
String getThreadID() {
return messageNode.getThreadID();
}
@Override
public Action getPreferredAction() {
return messageNode.getPreferredAction();
}
@Override
public String getDisplayName() {
return messageNode.getDisplayName();
}
}

View File

@ -83,9 +83,10 @@ MediaViewImagePanel.zoomResetButton.text=Reset
MediaViewImagePanel.zoomTextField.text=
MediaViewImagePanel.rotationTextField.text=
MediaViewImagePanel.rotateLeftButton.toolTipText=
HtmlPanel.showImagesToggleButton.text=Show Images
HtmlPanel.showImagesToggleButton.text=Download Images
MediaPlayerPanel.audioSlider.toolTipText=
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
MediaPlayerPanel.playButton.text=\u25ba
MediaPlayerPanel.infoLabel.text=No Errors
MediaViewImagePanel.tagsMenu.text_1=Tags Menu

View File

@ -22,7 +22,7 @@ GstVideoPanel.cannotProcFile.err=The media player cannot process this file.
GstVideoPanel.noOpenCase.errMsg=No open case available.
Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.
HtmlPanel_showImagesToggleButton_hide=Hide Images
HtmlPanel_showImagesToggleButton_show=Show Images
HtmlPanel_showImagesToggleButton_show=Download Images
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.
GstVideoPanel.setupVideo.infoLabel.text=Playback of deleted videos is not supported, use an external player.
@ -42,9 +42,17 @@ MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, aud
MediaPlayerPanel.noSupport=File not supported.
MediaPlayerPanel.timeFormat=%02d:%02d:%02d
MediaPlayerPanel.unknownTime=Unknown
MediaViewImagePanel.createTagOption=Create
MediaViewImagePanel.deleteTagOption=Delete
MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory.
MediaViewImagePanel.errorLabel.text=Could not load file into Media View.
MediaViewImagePanel.exportSaveText=Save
MediaViewImagePanel.exportTagOption=Export
MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E
MediaViewImagePanel.fileChooserTitle=Choose a save location
MediaViewImagePanel.hideTagOption=Hide
MediaViewImagePanel.successfulExport=Tagged image was successfully saved.
MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk.
MediaViewVideoPanel.pauseButton.text=\u25ba
MediaViewVideoPanel.progressLabel.text=00:00
MediaViewVideoPanel.infoLabel.text=info
@ -145,12 +153,13 @@ MediaViewImagePanel.zoomResetButton.text=Reset
MediaViewImagePanel.zoomTextField.text=
MediaViewImagePanel.rotationTextField.text=
MediaViewImagePanel.rotateLeftButton.toolTipText=
HtmlPanel.showImagesToggleButton.text=Show Images
HtmlPanel.showImagesToggleButton.text=Download Images
MediaPlayerPanel.audioSlider.toolTipText=
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
MediaPlayerPanel.playButton.text=\u25ba
MediaPlayerPanel.infoLabel.text=No Errors
MediaViewImagePanel.tagsMenu.text_1=Tags Menu
# {0} - tableName
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
# {0} - tableName

View File

@ -77,12 +77,12 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer
}
/**
* Get the FileTypeViewer for a given mimetype
* Get the FileTypeViewer for a given file
*
* @param mimeType
* @param file
*
* @return FileTypeViewer, null if no known content viewer supports the
* mimetype
* file
*/
private FileTypeViewer getSupportingViewer(AbstractFile file) {
FileTypeViewer viewer = mimeTypeToViewerMap.get(file.getMIMEType());
@ -143,7 +143,7 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer
viewer.setFile(file);
this.removeAll();
this.add(viewer.getComponent());
this.repaint();
this.validate();
}
}

View File

@ -18,7 +18,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" 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>
<Component id="htmlJPanel" max="32767" attributes="0"/>
</Group>

View File

@ -18,6 +18,11 @@
*/
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.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
@ -25,8 +30,9 @@ import javafx.concurrent.Worker;
import javafx.scene.web.WebView;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Node;
import net.htmlparser.jericho.Attribute;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;
import org.openide.util.NbBundle.Messages;
import org.w3c.dom.Document;
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
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 String TEXT_TYPE = "text/plain";
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
*
* @return The cleansed HTML String
*/
private String cleanseHTML(String htmlInString) {
org.jsoup.nodes.Document doc = Jsoup.parse(htmlInString);
// remove all 'img' tags.
doc.select("img").stream().forEach(Node::remove);
// remove all 'span' tags, these are often images which are ads
doc.select("span").stream().forEach(Node::remove);
return doc.html();
String returnString = "";
try {
Source source = new Source(new StringReader(htmlInString));
OutputDocument document = new OutputDocument(source);
//remove background images
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.
*/
@Messages({
"HtmlPanel_showImagesToggleButton_show=Show Images",
"HtmlPanel_showImagesToggleButton_show=Download Images",
"HtmlPanel_showImagesToggleButton_hide=Hide Images",
"Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.",})
private void refresh() {
@ -164,7 +221,7 @@ final class HtmlPanel extends javax.swing.JPanel {
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.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)
);
layout.setVerticalGroup(

View File

@ -11,30 +11,8 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Form>

View File

@ -37,17 +37,18 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName());
private static final String[] SUPPORTED_MIMETYPES = new String[]{
"text/html",
"application/xhtml+xml"
};
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
/**
* Creates new form HtmlViewerPanel
*/
HtmlViewer() {
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
private void initComponents() {
htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
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())
);
setLayout(new java.awt.BorderLayout());
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
// End of variables declaration//GEN-END:variables
@Override
public List<String> getSupportedMIMETypes() {
return Arrays.asList(SUPPORTED_MIMETYPES);

View File

@ -19,7 +19,7 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<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>
<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"/>
</Events>
</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, &quot;{key}&quot;)"/>
</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>
</Container>
</SubComponents>

View File

@ -20,18 +20,30 @@ package org.sleuthkit.autopsy.contentviewers;
import java.awt.EventQueue;
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.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static java.util.Objects.nonNull;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javafx.application.Platform;
import javafx.collections.ListChangeListener.Change;
import javafx.concurrent.Task;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
@ -45,19 +57,41 @@ import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
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.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.openide.util.NbBundle;
import org.python.google.common.collect.Lists;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog;
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog.TagNameAndComment;
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.ImageTagsUtil;
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.corelibs.OpenCvLoader;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
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
@ -70,17 +104,30 @@ import org.sleuthkit.datamodel.AbstractFile;
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 final static Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName());
private final boolean fxInited;
private JFXPanel fxPanel;
private Group imageGroup;
private ImageTaggingTool tagger;
private AbstractFile file;
private Group masterGroup;
private ImageTagsGroup tagsGroup;
private ImageTagCreator imageTagCreator;
private ImageView fxImageView;
private ScrollPane scrollPane;
private final ProgressBar progressBar = new ProgressBar();
private final MaskerPane maskerPane = new MaskerPane();
private final JPopupMenu imageTaggingOptions = 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 rotation; // Can be 0, 90, 180, and 270.
@ -113,36 +160,178 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
/**
* Creates new form MediaViewImagePanel
*/
@NbBundle.Messages({
"MediaViewImagePanel.createTagOption=Create",
"MediaViewImagePanel.deleteTagOption=Delete",
"MediaViewImagePanel.hideTagOption=Hide",
"MediaViewImagePanel.exportTagOption=Export"
})
public MediaViewImagePanel() {
initComponents();
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(Bundle.MediaViewImagePanel_createTagOption());
createTagMenuItem.addActionListener((event) -> createTag());
imageTaggingOptions.add(createTagMenuItem);
imageTaggingOptions.add(new JSeparator());
deleteTagMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_deleteTagOption());
deleteTagMenuItem.addActionListener((event) -> deleteTag());
imageTaggingOptions.add(deleteTagMenuItem);
imageTaggingOptions.add(new JSeparator());
hideTagsMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_hideTagOption());
hideTagsMenuItem.addActionListener((event) -> showOrHideTags());
imageTaggingOptions.add(hideTagsMenuItem);
imageTaggingOptions.add(new JSeparator());
exportTagsMenuItem = new JMenuItem(Bundle.MediaViewImagePanel_exportTagOption());
exportTagsMenuItem.addActionListener((event) -> exportTags());
imageTaggingOptions.add(exportTagsMenuItem);
imageTaggingOptions.setPopupSize(300, 150);
//Disable image tagging for non-windows users or upon failure to load OpenCV.
if (!PlatformUtil.isWindowsOS() || !OpenCvLoader.hasOpenCvLoaded()) {
tagsMenu.setEnabled(false);
imageTaggingOptions.setEnabled(false);
}
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?)
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);
subscribeTagMenuItemsToStateChanges();
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);
masterGroup.getChildren().add(tagsGroup);
fxImageView.setSmooth(true);
fxImageView.setCache(true);
//Update buttons when users select (or unselect) image tags.
tagsGroup.addFocusChangeListener((event) -> {
if (event.getPropertyName().equals(ImageTagControls.NOT_FOCUSED.getName())) {
if (masterGroup.getChildren().contains(imageTagCreator)) {
return;
}
EventQueue.invokeLater(() -> {
add(fxPanel);//add jfx ui to JPanel
});
if (tagsGroup.getChildren().isEmpty()) {
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() {
return fxInited;
}
@ -154,10 +343,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
Platform.runLater(() -> {
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
fxImageView.setImage(null);
tagger.defaultSettings();
pcs.firePropertyChange(new PropertyChangeEvent(this,
"state", null, State.DEFAULT));
masterGroup.getChildren().clear();
scrollPane.setContent(null);
scrollPane.setContent(imageGroup);
scrollPane.setContent(masterGroup);
});
}
@ -205,14 +395,31 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
try {
Image fxImage = readImageTask.get();
masterGroup.getChildren().clear();
tagsGroup.getChildren().clear();
this.file = file;
if (nonNull(fxImage)) {
// We have a non-null image, so let's show it.
fxImageView.setImage(fxImage);
imageGroup.getChildren().remove(tagger);
tagger = new ImageTaggingTool(fxImageView, Color.RED);
imageGroup.getChildren().add(tagger);
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 {
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
}
@ -252,6 +459,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
*/
@ -303,6 +556,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
zoomInButton = new javax.swing.JButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
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));
addComponentListener(new java.awt.event.ComponentAdapter() {
@ -406,6 +663,23 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
}
});
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);
}// </editor-fold>//GEN-END:initComponents
@ -450,12 +724,237 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
updateView();
}//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 taggedImage = ImageTagsUtil.getImageWithTags(file, regions);
Path output = Paths.get(exportChooser.getSelectedFile().getPath(),
FilenameUtils.getBaseName(file.getName()) + "-with_tags.png"); //NON-NLS
ImageIO.write(taggedImage, "png", output.toFile());
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport());
} catch (Exception ex) { //Runtime exceptions may spill out of ImageTagsUtil from JavaFX.
//This ensures we (devs and users) have something when it doesn't work.
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
if (imageTaggingOptions.isEnabled()) {
imageTaggingOptions.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
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 jSeparator2;
private javax.swing.JButton rotateLeftButton;
private javax.swing.JButton rotateRightButton;
private javax.swing.JTextField rotationTextField;
private javax.swing.JButton tagsMenu;
private javax.swing.JToolBar toolbar;
private javax.swing.JButton zoomInButton;
private javax.swing.JButton zoomOutButton;
@ -601,8 +1100,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
// Add the transforms in reverse order of intended execution.
// Note: They MUST be added in this order to ensure translate is
// executed last.
imageGroup.getTransforms().clear();
imageGroup.getTransforms().addAll(translate, rotate, scale);
masterGroup.getTransforms().clear();
masterGroup.getTransforms().addAll(translate, rotate, scale);
// Adjust scroll bar positions for view changes.
if (viewportWidth > fxPanel.getWidth()) {
@ -618,107 +1117,4 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
rotationTextField.setText((int) rotation + "°");
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);
}
}
}

View File

@ -271,22 +271,7 @@
</Constraint>
</Constraints>
<Layout>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Container>
<Container class="javax.swing.JScrollPane" name="rtfbodyScrollPane">
<Properties>

View File

@ -87,7 +87,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
private static final int ATTM_TAB_INDEX = 4;
private final List<JTextComponent> textAreas;
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
/**
* Artifact currently being displayed
*/
@ -101,6 +101,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
@NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
public MessageContentViewer() {
initComponents();
htmlPane.add(htmlPanel);
envelopePanel.setBackground(new Color(0, 0, 0, 38));
drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
attachmentsScrollPane.setViewportView(drp);
@ -153,7 +154,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
textbodyScrollPane = new javax.swing.JScrollPane();
textbodyTextArea = new javax.swing.JTextArea();
htmlPane = new javax.swing.JPanel();
htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
rtfbodyScrollPane = new javax.swing.JScrollPane();
rtfbodyTextPane = new javax.swing.JTextPane();
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
javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane);
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)
);
htmlPane.setLayout(new java.awt.BorderLayout());
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
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.JTextArea headersTextArea;
private javax.swing.JPanel htmlPane;
private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
private javax.swing.JTabbedPane msgbodyTabbedPane;
private javax.swing.JScrollPane rtfbodyScrollPane;
private javax.swing.JTextPane rtfbodyTextPane;
@ -534,7 +523,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
textComponent.setCaretPosition(0); //make sure we start at the top
}
}
final boolean hasText = attributeText.length() > 0;
msgbodyTabbedPane.setEnabledAt(index, hasText);
@ -680,18 +669,18 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Set<String> keepProps = new HashSet<>(Arrays.asList(
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
//Remove all other props except for the ones above
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
for(Property<?> p : sheetSet.getProperties()) {
if(!keepProps.contains(p.getName())){
for (Property<?> p : sheetSet.getProperties()) {
if (!keepProps.contains(p.getName())) {
sheetSet.remove(p.getName());
}
}

View File

@ -0,0 +1,353 @@
/*
* 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;
private final PhysicalTag physicalTag;
//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 = 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);
}
public double getWidth() {
return physicalTag.getWidth();
}
public double getHeight() {
return physicalTag.getHeight();
}
/**
* 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);
}
};
}
}
}

View File

@ -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");
}

View 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);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.geometry.Point2D;
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;
}
ImageTag selection = getTagToSelect(new Point2D(e.getX(), e.getY()));
requestFocus(selection);
});
}
/**
* 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;
}
}
/**
* Find which tag to select on a user mouse press. If multiple tags are
* overlapping, pick the smallest one that is determined by the L + W of
* the tag sides.
*
* @param coordinate User mouse press location
* @return The tag to give focus
*/
private ImageTag getTagToSelect(Point2D coordinate) {
ImageTag tagToSelect = null;
double minTagSize = Double.MAX_VALUE;
//Find all intersecting tags, select the absolute min based on L + W.
for (Node node : this.getChildren()) {
ImageTag tag = (ImageTag) node;
double tagSize = tag.getWidth() + tag.getHeight();
if (tag.contains(coordinate) && tagSize < minTagSize) {
tagToSelect = tag;
minTagSize = tagSize;
}
}
return tagToSelect;
}
/**
* 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 == null || 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();
}
}

View File

@ -0,0 +1,238 @@
/*
* 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.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
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.autopsy.coreutils.ImageUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ReadContentInputStream;
/**
* Utility for drawing rectangles on image files.
*/
public final class ImageTagsUtil {
//String constant for writing PNG in ImageIO
private final static String AWT_PNG = "png";
//String constant for encoding PNG in OpenCV
private final static String OPENCV_PNG = ".png";
/**
* Creates an image with tags applied.
*
* @param file Source image.
* @param tagRegions Tags to apply.
* @return Tagged image.
*
* @throws IOException
* @throws InterruptedException Calling thread was interrupted
* @throws ExecutionException Error while reading image from AbstractFile
*/
public static BufferedImage getImageWithTags(AbstractFile file,
Collection<ImageTagRegion> tagRegions) throws IOException, InterruptedException, ExecutionException {
//The raw image in OpenCV terms
Mat sourceImage = getImageMatFromFile(file);
//Image with tags in OpenCV terms
MatOfByte taggedMatrix = getTaggedImageMatrix(sourceImage, tagRegions);
try (ByteArrayInputStream taggedStream = new ByteArrayInputStream(taggedMatrix.toArray())) {
return ImageIO.read(taggedStream);
} finally {
sourceImage.release();
taggedMatrix.release();
}
}
/**
* Get the image from file.
*
* @param file
* @return
* @throws IOException
* @throws InterruptedException
* @throws ExecutionException
*/
private static BufferedImage getImageFromFile(AbstractFile file) throws IOException, InterruptedException, ExecutionException {
if (ImageUtils.isGIF(file)) {
//Grab the first frame.
try (BufferedInputStream bufferedReadContentStream =
new BufferedInputStream(new ReadContentInputStream(file))) {
return ImageIO.read(bufferedReadContentStream);
}
} else {
//Otherwise, read the full image.
Task<Image> readImageTask = ImageUtils.newReadImageTask(file);
readImageTask.run();
Image fxResult = readImageTask.get();
return SwingFXUtils.fromFXImage(fxResult, null);
}
}
/**
* Reads the image and converts it into an OpenCV equivalent.
*
* @param file Image to read
* @return raw image bytes
*
* @throws IOException
* @throws InterruptedException Calling thread was interrupted.
* @throws ExecutionException Error while reading image from AbstractFile
*/
private static Mat getImageMatFromFile(AbstractFile file) throws InterruptedException, ExecutionException, IOException {
//Get image from file
BufferedImage buffImage = getImageFromFile(file);
//Convert it to OpenCV Mat.
try (ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {
ImageIO.write(buffImage, AWT_PNG, outStream);
byte[] imageBytes = outStream.toByteArray();
MatOfByte rawSourceBytes = new MatOfByte(imageBytes);
Mat sourceImage = Highgui.imdecode(rawSourceBytes, Highgui.IMREAD_COLOR);
rawSourceBytes.release();
return sourceImage;
}
}
/**
* Adds tags to an image matrix.
*
* @param sourceImage
* @param tagRegions
* @return
*/
private static MatOfByte getTaggedImageMatrix(Mat sourceImage, Collection<ImageTagRegion> tagRegions) {
//Apply all tags to source image
for (ImageTagRegion region : tagRegions) {
Point topLeft = new Point(region.getX(), region.getY());
Point bottomRight = new Point(topLeft.x + region.getWidth(),
topLeft.y + region.getHeight());
//Red
Scalar rectangleBorderColor = new Scalar(0, 0, 255);
int rectangleBorderWidth = (int) Math.rint(region.getStrokeThickness());
Core.rectangle(sourceImage, topLeft, bottomRight,
rectangleBorderColor, rectangleBorderWidth);
}
MatOfByte taggedMatrix = new MatOfByte();
Highgui.imencode(OPENCV_PNG, sourceImage, taggedMatrix);
return taggedMatrix;
}
/**
* Creates a thumbnail 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
* @return BufferedImage Thumbnail image
*
* @throws InterruptedException Calling thread was interrupted.
* @throws ExecutionException Error while reading image from file.
*/
public static BufferedImage getThumbnailWithTags(AbstractFile file, Collection<ImageTagRegion> tagRegions,
IconSize iconSize) throws IOException, InterruptedException, ExecutionException {
//Raw image
Mat sourceImage = getImageMatFromFile(file);
//Full size image with tags
MatOfByte taggedMatrix = getTaggedImageMatrix(sourceImage, tagRegions);
//Resized to produce thumbnail
MatOfByte thumbnailMatrix = getResizedMatrix(taggedMatrix, iconSize);
try (ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(thumbnailMatrix.toArray())) {
return ImageIO.read(thumbnailStream);
} finally {
sourceImage.release();
taggedMatrix.release();
thumbnailMatrix.release();
}
}
/**
* Resizes the image matrix.
*
* @param taggedMatrix Image to resize.
* @param size Size of thumbnail.
*
* @return A new resized image matrix.
*/
private static MatOfByte getResizedMatrix(MatOfByte taggedMatrix, IconSize size) {
Size resizeDimensions = new Size(size.getSize(), size.getSize());
Mat taggedImage = Highgui.imdecode(taggedMatrix, Highgui.IMREAD_COLOR);
Mat thumbnailImage = new Mat();
Imgproc.resize(taggedImage, thumbnailImage, resizeDimensions);
MatOfByte thumbnailMatrix = new MatOfByte();
Highgui.imencode(OPENCV_PNG, thumbnailImage, thumbnailMatrix);
thumbnailImage.release();
taggedImage.release();
return thumbnailMatrix;
}
private ImageTagsUtil() {
}
/**
* 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;
}
}
}

View File

@ -23,6 +23,7 @@ import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.datamodel.AbstractFile;
/**
* A DataContentViewer that displays text with the TextViewers available.
@ -90,6 +91,17 @@ public class TextContentViewer implements DataContentViewer {
if (node == null) {
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);
}

View File

@ -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
* supported.
*

Some files were not shown because too many files have changed in this diff Show More