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

This commit is contained in:
Eugene Livis 2020-09-11 17:01:48 -04:00
commit 99b9985c20
24 changed files with 1510 additions and 1010 deletions

View File

@ -26,7 +26,7 @@ CallLogArtifactViewer_label_from=From
CallLogArtifactViewer_label_to=To CallLogArtifactViewer_label_to=To
CallLogArtifactViewer_suffix_local=(Local) CallLogArtifactViewer_suffix_local=(Local)
CallLogArtifactViewer_value_unknown=Unknown CallLogArtifactViewer_value_unknown=Unknown
#{0} - contact name # {0} - contact name
CommunicationArtifactViewerHelper_contact_label=Contact: {0} CommunicationArtifactViewerHelper_contact_label=Contact: {0}
CommunicationArtifactViewerHelper_contact_label_unknown=Unknown CommunicationArtifactViewerHelper_contact_label_unknown=Unknown
CommunicationArtifactViewerHelper_menuitem_copy=Copy CommunicationArtifactViewerHelper_menuitem_copy=Copy

View File

@ -440,7 +440,7 @@ final class CommunicationArtifactViewerHelper {
* @return A JLabel with the contact information. * @return A JLabel with the contact information.
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"#{0} - contact name", "# {0} - contact name",
"CommunicationArtifactViewerHelper_contact_label=Contact: {0}", "CommunicationArtifactViewerHelper_contact_label=Contact: {0}",
"CommunicationArtifactViewerHelper_contact_label_unknown=Unknown" "CommunicationArtifactViewerHelper_contact_label_unknown=Unknown"
}) })

View File

@ -43,7 +43,8 @@ public class DataSourceCountsSummary {
* @return The count. * @return The count.
*/ */
public static Long getCountOfFiles(DataSource currentDataSource) { public static Long getCountOfFiles(DataSource currentDataSource) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, null, return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource,
null,
"Unable to get count of files, providing empty results"); "Unable to get count of files, providing empty results");
} }
@ -55,7 +56,7 @@ public class DataSourceCountsSummary {
* @return The count. * @return The count.
*/ */
public static Long getCountOfAllocatedFiles(DataSource currentDataSource) { public static Long getCountOfAllocatedFiles(DataSource currentDataSource) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC), DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC),
"Unable to get counts of unallocated files for datasource, providing empty results"); "Unable to get counts of unallocated files for datasource, providing empty results");
} }
@ -68,9 +69,8 @@ public class DataSourceCountsSummary {
* @return The count. * @return The count.
*/ */
public static Long getCountOfUnallocatedFiles(DataSource currentDataSource) { public static Long getCountOfUnallocatedFiles(DataSource currentDataSource) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC) DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC),
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(),
"Unable to get counts of unallocated files for datasource, providing empty results"); "Unable to get counts of unallocated files for datasource, providing empty results");
} }
@ -97,8 +97,7 @@ public class DataSourceCountsSummary {
*/ */
public static Long getCountOfSlackFiles(DataSource currentDataSource) { public static Long getCountOfSlackFiles(DataSource currentDataSource) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC) "type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(),
+ " AND type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(),
"Unable to get count of slack files for datasources, providing empty results"); "Unable to get count of slack files for datasources, providing empty results");
} }

View File

@ -37,8 +37,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.datamodel.BlackboardAttribute.Type; import org.sleuthkit.datamodel.BlackboardAttribute.Type;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
import org.sleuthkit.datamodel.TskData.TSK_FS_META_FLAG_ENUM; import org.sleuthkit.datamodel.TskData.TSK_FS_META_FLAG_ENUM;
import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
@ -51,8 +51,7 @@ final class DataSourceInfoUtilities {
private static final Logger logger = Logger.getLogger(DataSourceInfoUtilities.class.getName()); private static final Logger logger = Logger.getLogger(DataSourceInfoUtilities.class.getName());
/** /**
* Gets a count of tsk_files for a particular datasource where dir_type is * Gets a count of tsk_files for a particular datasource.
* not a virtual directory and has a name.
* *
* @param currentDataSource The datasource. * @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses. * @param additionalWhere Additional sql where clauses.
@ -66,8 +65,6 @@ final class DataSourceInfoUtilities {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
return skCase.countFilesWhere( return skCase.countFilesWhere(
"data_source_obj_id=" + currentDataSource.getId() "data_source_obj_id=" + currentDataSource.getId()
+ " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue()
+ " AND name<>''"
+ (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere))); + (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere)));
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.WARNING, onError, ex); logger.log(Level.WARNING, onError, ex);
@ -78,8 +75,7 @@ final class DataSourceInfoUtilities {
} }
/** /**
* Gets a count of regular files for a particular datasource where the * Gets a count of regular files for a particular datasource.
* dir_type and type are not a virtual directory and has a name.
* *
* @param currentDataSource The datasource. * @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses. * @param additionalWhere Additional sql where clauses.
@ -88,8 +84,27 @@ final class DataSourceInfoUtilities {
* @return The count of files or null on error. * @return The count of files or null on error.
*/ */
static Long getCountOfRegularFiles(DataSource currentDataSource, String additionalWhere, String onError) { static Long getCountOfRegularFiles(DataSource currentDataSource, String additionalWhere, String onError) {
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue();
if (StringUtils.isNotBlank(additionalWhere)) {
whereClause += " AND " + additionalWhere;
}
return getCountOfTskFiles(currentDataSource, whereClause, onError);
}
/**
* Gets a count of regular non-slack files for a particular datasource.
*
* @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses.
* @param onError The message to log on error.
*
* @return The count of files or null on error.
*/
static Long getCountOfRegNonSlackFiles(DataSource currentDataSource, String additionalWhere, String onError) {
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType(); + " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType();
if (StringUtils.isNotBlank(additionalWhere)) { if (StringUtils.isNotBlank(additionalWhere)) {
whereClause += " AND " + additionalWhere; whereClause += " AND " + additionalWhere;

View File

@ -43,7 +43,7 @@ public class DataSourceMimeTypeSummary {
* source, null if no count was retrieved * source, null if no count was retrieved
*/ */
public static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) { public static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
"mime_type IN " + getSqlSet(setOfMimeTypes), "mime_type IN " + getSqlSet(setOfMimeTypes),
"Unable to get count of files for specified mime types"); "Unable to get count of files for specified mime types");
} }
@ -61,11 +61,22 @@ public class DataSourceMimeTypeSummary {
* have the specific mime type, but do have a mime type. * have the specific mime type, but do have a mime type.
*/ */
public static Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) { public static Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
"mime_type NOT IN " + getSqlSet(setOfMimeTypes) "mime_type NOT IN " + getSqlSet(setOfMimeTypes)
+ " AND mime_type IS NOT NULL AND mime_type <> '' ", + " AND mime_type IS NOT NULL AND mime_type <> '' ",
"Unable to get count of files without specified mime types"); "Unable to get count of files without specified mime types");
} }
/**
* Get a count of all regular files in a datasource.
* @param dataSource The datasource.
* @return The count of regular files.
*/
public static Long getCountOfAllRegularFiles(DataSource dataSource) {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null,
"Unable to get count of all regular files");
}
/** /**
* Gets the number of files in the data source with no assigned mime type. * Gets the number of files in the data source with no assigned mime type.
@ -77,7 +88,7 @@ public class DataSourceMimeTypeSummary {
* *
*/ */
public static Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) { public static Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
"(mime_type IS NULL OR mime_type = '') ", "(mime_type IS NULL OR mime_type = '') ",
"Unable to get count of files without a mime type"); "Unable to get count of files without a mime type");
} }

View File

@ -28,8 +28,6 @@ DataSourceSummaryDetailsPanel.acquisitionDetailsTextArea.text=
DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text=Acquisition Details: DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text=Acquisition Details:
DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text=Unallocated Space: DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text=Unallocated Space:
DataSourceSummaryDetailsPanel.unallocatedSizeValue.text= DataSourceSummaryDetailsPanel.unallocatedSizeValue.text=
DataSourceSummaryCountsPanel.byCategoryLabel.text=Files by Category
DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type
DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs
DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts
DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches

View File

@ -1,31 +1,8 @@
AnalysisPanel_countColumn_title=Count AnalysisPanel_countColumn_title=Count
AnalysisPanel_keyColumn_title=Name AnalysisPanel_keyColumn_title=Name
CTL_DataSourceSummaryAction=Data Source Summary CTL_DataSourceSummaryAction=Data Source Summary
DataSourceSummaryCountsPanel.ArtifactCountsTableModel.count.header=Count
DataSourceSummaryCountsPanel.ArtifactCountsTableModel.type.header=Result Type
DataSourceSummaryCountsPanel.byMimeTypeLabel.text=Files by MIME Type
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.all.row=All
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.allocated.row=Allocated
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.count.header=Count
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.directory.row=Directory
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.slack.row=Slack
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.type.header=File Type
DataSourceSummaryCountsPanel.FilesByCategoryTableModel.unallocated.row=Unallocated
DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.audio.row=Audio
DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.documents.row=Documents
DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.executables.row=Executables
DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.images.row=Images
DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.videos.row=Videos
DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_notAnalyzed_label=Not Analyzed
DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_other_label=Other
DataSourceSummaryDetailsPanel.getDataSources.error.text=Failed to get the list of datasources for the current case. DataSourceSummaryDetailsPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.
DataSourceSummaryDetailsPanel.getDataSources.error.title=Load Failure DataSourceSummaryDetailsPanel.getDataSources.error.title=Load Failure
DataSourceSummaryDetailsPanel.units.bytes=\ bytes
DataSourceSummaryDetailsPanel.units.gigabytes=\ GB
DataSourceSummaryDetailsPanel.units.kilobytes=\ kB
DataSourceSummaryDetailsPanel.units.megabytes=\ MB
DataSourceSummaryDetailsPanel.units.petabytes=\ PB
DataSourceSummaryDetailsPanel.units.terabytes=\ TB
DataSourceSummaryDialog.closeButton.text=Close DataSourceSummaryDialog.closeButton.text=Close
DataSourceSummaryDetailsPanel.displayNameLabel.text=Display Name: DataSourceSummaryDetailsPanel.displayNameLabel.text=Display Name:
DataSourceSummaryDetailsPanel.originalNameLabel.text=Name: DataSourceSummaryDetailsPanel.originalNameLabel.text=Name:
@ -56,8 +33,6 @@ DataSourceSummaryDetailsPanel.acquisitionDetailsTextArea.text=
DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text=Acquisition Details: DataSourceSummaryDetailsPanel.acquisitionDetailsLabel.text=Acquisition Details:
DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text=Unallocated Space: DataSourceSummaryDetailsPanel.unallocatedSizeLabel.text=Unallocated Space:
DataSourceSummaryDetailsPanel.unallocatedSizeValue.text= DataSourceSummaryDetailsPanel.unallocatedSizeValue.text=
DataSourceSummaryCountsPanel.byCategoryLabel.text=Files by Category
DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type
DataSourceSummaryDialog.window.title=Data Sources Summary DataSourceSummaryDialog.window.title=Data Sources Summary
DataSourceSummaryNode.column.dataSourceName.header=Data Source Name DataSourceSummaryNode.column.dataSourceName.header=Data Source Name
DataSourceSummaryNode.column.files.header=Files DataSourceSummaryNode.column.files.header=Files
@ -67,10 +42,10 @@ DataSourceSummaryNode.column.tags.header=Tags
DataSourceSummaryNode.column.type.header=Type DataSourceSummaryNode.column.type.header=Type
DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
DataSourceSummaryTabbedPane_analysisTab_title=Analysis DataSourceSummaryTabbedPane_analysisTab_title=Analysis
DataSourceSummaryTabbedPane_countsTab_title=Counts
DataSourceSummaryTabbedPane_detailsTab_title=Container DataSourceSummaryTabbedPane_detailsTab_title=Container
DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History
DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files
DataSourceSummaryTabbedPane_typesTab_title=Types
DataSourceSummaryTabbedPane_userActivityTab_title=User Activity DataSourceSummaryTabbedPane_userActivityTab_title=User Activity
DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs
DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts
@ -105,4 +80,27 @@ RecentFilesPanel.openDocsLabel.text=Recently Opened Documents
RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.downloadLabel.text=Recent Downloads
RecentFilesPanel.attachmentLabel.text=Recent Attachements RecentFilesPanel.attachmentLabel.text=Recent Attachements
RecentFilesPanel_col_head_date=Date RecentFilesPanel_col_head_date=Date
SizeRepresentationUtil_units_bytes=\ bytes
SizeRepresentationUtil_units_gigabytes=\ GB
SizeRepresentationUtil_units_kilobytes=\ kB
SizeRepresentationUtil_units_megabytes=\ MB
SizeRepresentationUtil_units_petabytes=\ PB
SizeRepresentationUtil_units_terabytes=\ TB
TypesPanel_artifactsTypesPieChart_title=Artifact Types
TypesPanel_fileMimeTypesChart_audio_title=Audio
TypesPanel_fileMimeTypesChart_documents_title=Documents
TypesPanel_fileMimeTypesChart_executables_title=Executables
TypesPanel_fileMimeTypesChart_images_title=Images
TypesPanel_fileMimeTypesChart_notAnalyzed_title=Not Analyzed
TypesPanel_fileMimeTypesChart_other_title=Other
TypesPanel_fileMimeTypesChart_title=File Types
TypesPanel_fileMimeTypesChart_unknown_title=Unknown
TypesPanel_fileMimeTypesChart_videos_title=Videos
TypesPanel_filesByCategoryTable_allocatedRow_title=Allocated Files
TypesPanel_filesByCategoryTable_directoryRow_title=Directories
TypesPanel_filesByCategoryTable_slackRow_title=Slack Files
TypesPanel_filesByCategoryTable_unallocatedRow_title=Unallocated Files
TypesPanel_osLabel_title=OS
TypesPanel_sizeLabel_title=Size
TypesPanel_usageLabel_title=Usage
ViewSummaryInformationAction.name.text=View Summary Information ViewSummaryInformationAction.name.text=View Summary Information

View File

@ -1,222 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.8" 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="scrollParent" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="scrollParent" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollParent">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="parentPanel">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[840, 320]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="fileTypePiePanel" min="-2" pref="400" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="fileCountsByCategoryScrollPane" alignment="0" min="-2" pref="140" max="-2" attributes="0"/>
<Component id="byCategoryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="filesByCatParent" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="resultsByTypeLabel" min="-2" pref="79" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="artifactCountsScrollPane" min="-2" pref="244" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="resultsByTypeParent" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="fileTypePiePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="byCategoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="resultsByTypeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="resultsByTypeParent" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="148" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="artifactCountsScrollPane" pref="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="fileCountsByCategoryScrollPane" min="-2" pref="107" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="31" max="-2" attributes="0"/>
<Component id="filesByCatParent" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="fileCountsByCategoryScrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<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.JTable" name="fileCountsByCategoryTable">
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="byCategoryLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="DataSourceSummaryCountsPanel.byCategoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="resultsByTypeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="DataSourceSummaryCountsPanel.resultsByTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Container class="javax.swing.JScrollPane" name="artifactCountsScrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<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.JTable" name="artifactCountsTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="fileTypePiePanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 300]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="fileTypePieChart"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="filesByCatParent">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Container class="javax.swing.JPanel" name="resultsByTypeParent">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -1,289 +0,0 @@
/*
* 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.datasourcesummary.ui;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.NonEditableTableModel;
import java.util.Map;
import javax.swing.JLabel;
import javax.swing.table.DefaultTableCellRenderer;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceCountsSummary;
import org.sleuthkit.datamodel.DataSource;
/**
* Panel for displaying summary information on the known files present in the
* specified DataSource
*/
@Messages({
"DataSourceSummaryCountsPanel.ArtifactCountsTableModel.type.header=Result Type",
"DataSourceSummaryCountsPanel.ArtifactCountsTableModel.count.header=Count",
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.type.header=File Type",
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.count.header=Count"
})
class DataSourceSummaryCountsPanel extends BaseDataSourceSummaryPanel {
private static final long serialVersionUID = 1L;
// Result returned for a data model if no data found.
private static final Object[][] EMPTY_PAIRS = new Object[][]{};
// column headers for file by category table
private static final Object[] FILE_BY_CATEGORY_COLUMN_HEADERS = new Object[]{
Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_type_header(),
Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_count_header()
};
// column headers for artifact counts table
private static final Object[] ARTIFACT_COUNTS_COLUMN_HEADERS = new Object[]{
Bundle.DataSourceSummaryCountsPanel_ArtifactCountsTableModel_type_header(),
Bundle.DataSourceSummaryCountsPanel_ArtifactCountsTableModel_count_header()
};
private final DefaultTableCellRenderer rightAlignedRenderer = new DefaultTableCellRenderer();
private final FileTypePieChart fileTypePieChart = new FileTypePieChart();
/**
* Creates new form DataSourceSummaryCountsPanel
*/
DataSourceSummaryCountsPanel() {
rightAlignedRenderer.setHorizontalAlignment(JLabel.RIGHT);
initComponents();
fileCountsByCategoryTable.getTableHeader().setReorderingAllowed(false);
artifactCountsTable.getTableHeader().setReorderingAllowed(false);
setDataSource(null);
}
@Override
protected void onNewDataSource(DataSource dataSource) {
if (dataSource == null || !Case.isCaseOpen()) {
updateCountsTableData(EMPTY_PAIRS, EMPTY_PAIRS);
} else {
updateCountsTableData(getFileCategoryModel(dataSource), getArtifactCountsModel(dataSource));
}
this.fileTypePieChart.setDataSource(dataSource);
}
/**
* Specify the DataSource to display file information for.
*
* @param fileCategoryDataModel The file category data model.
* @param artifactDataModel The artifact type data model.
*/
private void updateCountsTableData(Object[][] fileCategoryDataModel, Object[][] artifactDataModel) {
fileCountsByCategoryTable.setModel(new NonEditableTableModel(fileCategoryDataModel, FILE_BY_CATEGORY_COLUMN_HEADERS));
fileCountsByCategoryTable.getColumnModel().getColumn(1).setCellRenderer(rightAlignedRenderer);
fileCountsByCategoryTable.getColumnModel().getColumn(0).setPreferredWidth(130);
artifactCountsTable.setModel(new NonEditableTableModel(artifactDataModel, ARTIFACT_COUNTS_COLUMN_HEADERS));
artifactCountsTable.getColumnModel().getColumn(0).setPreferredWidth(230);
artifactCountsTable.getColumnModel().getColumn(1).setCellRenderer(rightAlignedRenderer);
this.repaint();
}
/**
* Determines the JTable data model for datasource file categories.
*
* @param dataSource The DataSource.
*
* @return The model to be used with a JTable.
*/
@Messages({
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.all.row=All",
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.allocated.row=Allocated",
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.unallocated.row=Unallocated",
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.slack.row=Slack",
"DataSourceSummaryCountsPanel.FilesByCategoryTableModel.directory.row=Directory"
})
private static Object[][] getFileCategoryModel(DataSource selectedDataSource) {
Long fileCount = zeroIfNull(DataSourceCountsSummary.getCountOfFiles(selectedDataSource));
Long unallocatedFiles = zeroIfNull(DataSourceCountsSummary.getCountOfUnallocatedFiles(selectedDataSource));
Long allocatedFiles = zeroIfNull(DataSourceCountsSummary.getCountOfAllocatedFiles(selectedDataSource));
Long slackFiles = zeroIfNull(DataSourceCountsSummary.getCountOfSlackFiles(selectedDataSource));
Long directories = zeroIfNull(DataSourceCountsSummary.getCountOfDirectories(selectedDataSource));
return new Object[][]{
new Object[]{Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_all_row(), fileCount},
new Object[]{Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_allocated_row(), allocatedFiles},
new Object[]{Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_unallocated_row(), unallocatedFiles},
new Object[]{Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_slack_row(), slackFiles},
new Object[]{Bundle.DataSourceSummaryCountsPanel_FilesByCategoryTableModel_directory_row(), directories}
};
}
/**
* Returns 0 if value is null.
*
* @param origValue The original value.
*
* @return The value or 0 if null.
*/
private static Long zeroIfNull(Long origValue) {
return origValue == null ? 0 : origValue;
}
/**
* The counts of different artifact types found in a DataSource.
*
* @param selectedDataSource The DataSource.
*
* @return The JTable data model of counts of artifact types.
*/
private static Object[][] getArtifactCountsModel(DataSource selectedDataSource) {
Map<String, Long> artifactMapping = DataSourceCountsSummary.getCountsOfArtifactsByType(selectedDataSource);
if (artifactMapping == null) {
return EMPTY_PAIRS;
}
return artifactMapping.entrySet().stream()
.filter((entrySet) -> entrySet != null && entrySet.getKey() != null)
.sorted((a, b) -> a.getKey().compareTo(b.getKey()))
.map((entrySet) -> new Object[]{entrySet.getKey(), entrySet.getValue()})
.toArray(Object[][]::new);
}
/**
* 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() {
javax.swing.JScrollPane scrollParent = new javax.swing.JScrollPane();
javax.swing.JPanel parentPanel = new javax.swing.JPanel();
javax.swing.JScrollPane fileCountsByCategoryScrollPane = new javax.swing.JScrollPane();
fileCountsByCategoryTable = new javax.swing.JTable();
javax.swing.JLabel byCategoryLabel = new javax.swing.JLabel();
javax.swing.JLabel resultsByTypeLabel = new javax.swing.JLabel();
javax.swing.JScrollPane artifactCountsScrollPane = new javax.swing.JScrollPane();
artifactCountsTable = new javax.swing.JTable();
javax.swing.JPanel fileTypePiePanel = fileTypePieChart;
javax.swing.JPanel filesByCatParent = new javax.swing.JPanel();
javax.swing.JPanel resultsByTypeParent = new javax.swing.JPanel();
parentPanel.setMinimumSize(new java.awt.Dimension(840, 320));
fileCountsByCategoryScrollPane.setViewportView(fileCountsByCategoryTable);
org.openide.awt.Mnemonics.setLocalizedText(byCategoryLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryCountsPanel.class, "DataSourceSummaryCountsPanel.byCategoryLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(resultsByTypeLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryCountsPanel.class, "DataSourceSummaryCountsPanel.resultsByTypeLabel.text")); // NOI18N
artifactCountsTable.setAutoCreateRowSorter(true);
artifactCountsScrollPane.setViewportView(artifactCountsTable);
fileTypePiePanel.setPreferredSize(new java.awt.Dimension(400, 300));
javax.swing.GroupLayout filesByCatParentLayout = new javax.swing.GroupLayout(filesByCatParent);
filesByCatParent.setLayout(filesByCatParentLayout);
filesByCatParentLayout.setHorizontalGroup(
filesByCatParentLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
filesByCatParentLayout.setVerticalGroup(
filesByCatParentLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
javax.swing.GroupLayout resultsByTypeParentLayout = new javax.swing.GroupLayout(resultsByTypeParent);
resultsByTypeParent.setLayout(resultsByTypeParentLayout);
resultsByTypeParentLayout.setHorizontalGroup(
resultsByTypeParentLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
resultsByTypeParentLayout.setVerticalGroup(
resultsByTypeParentLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
javax.swing.GroupLayout parentPanelLayout = new javax.swing.GroupLayout(parentPanel);
parentPanel.setLayout(parentPanelLayout);
parentPanelLayout.setHorizontalGroup(
parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(parentPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(fileTypePiePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addGroup(parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fileCountsByCategoryScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(byCategoryLabel)
.addComponent(filesByCatParent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGroup(parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(resultsByTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(parentPanelLayout.createSequentialGroup()
.addComponent(artifactCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 244, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(resultsByTypeParent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
parentPanelLayout.setVerticalGroup(
parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(parentPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(parentPanelLayout.createSequentialGroup()
.addComponent(fileTypePiePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(parentPanelLayout.createSequentialGroup()
.addGroup(parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(byCategoryLabel)
.addComponent(resultsByTypeLabel))
.addGroup(parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, parentPanelLayout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(resultsByTypeParent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(148, 148, 148))
.addGroup(parentPanelLayout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(parentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(artifactCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(parentPanelLayout.createSequentialGroup()
.addComponent(fileCountsByCategoryScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(31, 31, 31)
.addComponent(filesByCatParent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())))))
);
scrollParent.setViewportView(parentPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollParent)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollParent)
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTable artifactCountsTable;
private javax.swing.JTable fileCountsByCategoryTable;
// End of variables declaration//GEN-END:variables
}

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.datasourcesummary.ui; package org.sleuthkit.autopsy.datasourcesummary.ui;
import java.text.DecimalFormat;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
@ -36,8 +35,6 @@ class DataSourceSummaryDetailsPanel extends BaseDataSourceSummaryPanel {
//Because this panel was made using the gridbaglayout and netbean's Customize Layout tool it will be best to continue to modify it through that //Because this panel was made using the gridbaglayout and netbean's Customize Layout tool it will be best to continue to modify it through that
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Integer SIZE_COVERSION_CONSTANT = 1000;
private static final DecimalFormat APPROXIMATE_SIZE_FORMAT = new DecimalFormat("#.##");
private static final Logger logger = Logger.getLogger(DataSourceSummaryDetailsPanel.class.getName()); private static final Logger logger = Logger.getLogger(DataSourceSummaryDetailsPanel.class.getName());
/** /**
@ -70,8 +67,7 @@ class DataSourceSummaryDetailsPanel extends BaseDataSourceSummaryPanel {
private void updateDetailsPanelData(DataSource selectedDataSource, Long unallocatedFilesSize, String osDetails, String usage) { private void updateDetailsPanelData(DataSource selectedDataSource, Long unallocatedFilesSize, String osDetails, String usage) {
clearTableValues(); clearTableValues();
if (selectedDataSource != null) { if (selectedDataSource != null) {
unallocatedSizeValue.setText(getSizeString(unallocatedFilesSize)); unallocatedSizeValue.setText(SizeRepresentationUtil.getSizeString(unallocatedFilesSize));
timeZoneValue.setText(selectedDataSource.getTimeZone()); timeZoneValue.setText(selectedDataSource.getTimeZone());
displayNameValue.setText(selectedDataSource.getName()); displayNameValue.setText(selectedDataSource.getName());
originalNameValue.setText(selectedDataSource.getName()); originalNameValue.setText(selectedDataSource.getName());
@ -100,8 +96,8 @@ class DataSourceSummaryDetailsPanel extends BaseDataSourceSummaryPanel {
*/ */
private void setFieldsForImage(Image selectedImage) { private void setFieldsForImage(Image selectedImage) {
imageTypeValue.setText(selectedImage.getType().getName()); imageTypeValue.setText(selectedImage.getType().getName());
sizeValue.setText(getSizeString(selectedImage.getSize())); sizeValue.setText(SizeRepresentationUtil.getSizeString(selectedImage.getSize()));
sectorSizeValue.setText(getSizeString(selectedImage.getSsize())); sectorSizeValue.setText(SizeRepresentationUtil.getSizeString(selectedImage.getSsize()));
for (String path : selectedImage.getPaths()) { for (String path : selectedImage.getPaths()) {
((DefaultTableModel) filePathsTable.getModel()).addRow(new Object[]{path}); ((DefaultTableModel) filePathsTable.getModel()).addRow(new Object[]{path});
@ -139,55 +135,6 @@ class DataSourceSummaryDetailsPanel extends BaseDataSourceSummaryPanel {
} }
} }
/**
* Get a long size in bytes as a string formated to be read by users.
*
* @param size Long value representing a size in bytes
*
* @return return a string formated with a user friendly version of the size
* as a string, returns empty String when provided empty size
*/
@Messages({
"DataSourceSummaryDetailsPanel.units.bytes= bytes",
"DataSourceSummaryDetailsPanel.units.kilobytes= kB",
"DataSourceSummaryDetailsPanel.units.megabytes= MB",
"DataSourceSummaryDetailsPanel.units.gigabytes= GB",
"DataSourceSummaryDetailsPanel.units.terabytes= TB",
"DataSourceSummaryDetailsPanel.units.petabytes= PB"
})
private static String getSizeString(Long size) {
if (size == null) {
return "";
}
double approximateSize = size;
if (approximateSize < SIZE_COVERSION_CONSTANT) {
return String.valueOf(size) + Bundle.DataSourceSummaryDetailsPanel_units_bytes();
}
approximateSize /= SIZE_COVERSION_CONSTANT;
if (approximateSize < SIZE_COVERSION_CONSTANT) {
return APPROXIMATE_SIZE_FORMAT.format(approximateSize) + Bundle.DataSourceSummaryDetailsPanel_units_kilobytes()
+ " (" + String.valueOf(size) + Bundle.DataSourceSummaryDetailsPanel_units_bytes() + ")";
}
approximateSize /= SIZE_COVERSION_CONSTANT;
if (approximateSize < SIZE_COVERSION_CONSTANT) {
return APPROXIMATE_SIZE_FORMAT.format(approximateSize) + Bundle.DataSourceSummaryDetailsPanel_units_megabytes()
+ " (" + String.valueOf(size) + Bundle.DataSourceSummaryDetailsPanel_units_bytes() + ")";
}
approximateSize /= SIZE_COVERSION_CONSTANT;
if (approximateSize < SIZE_COVERSION_CONSTANT) {
return APPROXIMATE_SIZE_FORMAT.format(approximateSize) + Bundle.DataSourceSummaryDetailsPanel_units_gigabytes()
+ " (" + String.valueOf(size) + Bundle.DataSourceSummaryDetailsPanel_units_bytes() + ")";
}
approximateSize /= SIZE_COVERSION_CONSTANT;
if (approximateSize < SIZE_COVERSION_CONSTANT) {
return APPROXIMATE_SIZE_FORMAT.format(approximateSize) + Bundle.DataSourceSummaryDetailsPanel_units_terabytes()
+ " (" + String.valueOf(size) + Bundle.DataSourceSummaryDetailsPanel_units_bytes() + ")";
}
approximateSize /= SIZE_COVERSION_CONSTANT;
return APPROXIMATE_SIZE_FORMAT.format(approximateSize) + Bundle.DataSourceSummaryDetailsPanel_units_petabytes()
+ " (" + String.valueOf(size) + Bundle.DataSourceSummaryDetailsPanel_units_bytes() + ")";
}
/** /**
* Update the visibility of all fields and their labels based on whether * Update the visibility of all fields and their labels based on whether
* they have contents. Empty fields have them and their contents hidden. * they have contents. Empty fields have them and their contents hidden.

View File

@ -18,11 +18,11 @@
*/ */
package org.sleuthkit.autopsy.datasourcesummary.ui; package org.sleuthkit.autopsy.datasourcesummary.ui;
import java.util.ArrayList; import java.awt.Component;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
@ -33,7 +33,7 @@ import org.sleuthkit.datamodel.DataSource;
* IngestJobInfoPanel. * IngestJobInfoPanel.
*/ */
@Messages({ @Messages({
"DataSourceSummaryTabbedPane_countsTab_title=Counts", "DataSourceSummaryTabbedPane_typesTab_title=Types",
"DataSourceSummaryTabbedPane_detailsTab_title=Container", "DataSourceSummaryTabbedPane_detailsTab_title=Container",
"DataSourceSummaryTabbedPane_userActivityTab_title=User Activity", "DataSourceSummaryTabbedPane_userActivityTab_title=User Activity",
"DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History", "DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History",
@ -42,18 +42,76 @@ import org.sleuthkit.datamodel.DataSource;
}) })
public class DataSourceSummaryTabbedPane extends JTabbedPane { public class DataSourceSummaryTabbedPane extends JTabbedPane {
/**
* Records of tab information (i.e. title, component, function to call on
* new data source).
*/
private static class DataSourceTab {
private final String tabTitle;
private final Component component;
private final Consumer<DataSource> onDataSource;
/**
* Main constructor.
*
* @param tabTitle The title of the tab.
* @param component The component to be displayed.
* @param onDataSource The function to be called on a new data source.
*/
DataSourceTab(String tabTitle, Component component, Consumer<DataSource> onDataSource) {
this.tabTitle = tabTitle;
this.component = component;
this.onDataSource = onDataSource;
}
/**
* Main constructor.
*
* @param tabTitle The title of the tab.
* @param panel The component to be displayed in the tab.
*/
DataSourceTab(String tabTitle, BaseDataSourceSummaryPanel panel) {
this.tabTitle = tabTitle;
this.component = panel;
this.onDataSource = panel::setDataSource;
}
/**
* @return The title for the tab.
*/
String getTabTitle() {
return tabTitle;
}
/**
* @return The component to display in the tab.
*/
Component getComponent() {
return component;
}
/**
* @return The function to be called on new data source.
*/
Consumer<DataSource> getOnDataSource() {
return onDataSource;
}
}
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// A pair of the tab name and the corresponding BaseDataSourceSummaryTabs to be displayed.
private final List<Pair<String, BaseDataSourceSummaryPanel>> tabs = new ArrayList<>(Arrays.asList(
Pair.of(Bundle.DataSourceSummaryTabbedPane_countsTab_title(), new DataSourceSummaryCountsPanel()),
Pair.of(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new DataSourceSummaryUserActivityPanel()),
Pair.of(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()),
Pair.of(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel())
));
private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel();
private final List<DataSourceTab> tabs = Arrays.asList(
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new DataSourceSummaryUserActivityPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryDetailsPanel())
);
private DataSource dataSource = null; private DataSource dataSource = null;
/** /**
@ -64,18 +122,9 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane {
} }
private void initComponent() { private void initComponent() {
for (Pair<String, BaseDataSourceSummaryPanel> tab : tabs) { for (DataSourceTab tab : tabs) {
addTab(tab.getKey(), tab.getValue()); addTab(tab.getTabTitle(), tab.getComponent());
} }
// IngestJobInfoPanel is not specifically a data source summary panel
// and is called separately for that reason.
addTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel);
// The Container tab should be last.
Pair<String, BaseDataSourceSummaryPanel> tab = Pair.of(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryDetailsPanel());
addTab(tab.getKey(), tab.getValue());
tabs.add(tab);
} }
/** /**
@ -95,12 +144,8 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane {
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource; this.dataSource = dataSource;
for (Pair<String, BaseDataSourceSummaryPanel> tab : tabs) { for (DataSourceTab tab : tabs) {
tab.getValue().setDataSource(dataSource); tab.getOnDataSource().accept(dataSource);
} }
// IngestJobInfoPanel is not specifically a data source summary panel
// and is called separately for that reason.
ingestHistoryPanel.setDataSource(dataSource);
} }
} }

View File

@ -1,190 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.datasourcesummary.ui;
import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.JPanel;
import org.sleuthkit.datamodel.DataSource;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import javax.swing.JLabel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceMimeTypeSummary;
import static org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
/**
* A Pie Chart that shows file mime types in a data source.
*/
class FileTypePieChart extends JPanel {
private static final long serialVersionUID = 1L;
private static final Font DEFAULT_FONT = new JLabel().getFont();
private static final Font DEFAULT_HEADER_FONT = new Font(DEFAULT_FONT.getName(), DEFAULT_FONT.getStyle(), (int) (DEFAULT_FONT.getSize() * 1.5));
private final DefaultPieDataset dataset = new DefaultPieDataset();
private DataSource dataSource;
// used for determining mime types that fall in the 'other' category
private static final Set<String> ALL_CATEGORY_MIME_TYPES = Arrays.asList(
FileTypeCategory.IMAGE,
FileTypeCategory.VIDEO,
FileTypeCategory.AUDIO,
FileTypeCategory.DOCUMENTS,
FileTypeCategory.EXECUTABLE)
.stream()
.flatMap((cat) -> cat.getMediaTypes().stream())
.collect(Collectors.toSet());
/**
* Default constructor for the pie chart.
*/
@Messages({
"DataSourceSummaryCountsPanel.byMimeTypeLabel.text=Files by MIME Type",
"DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.audio.row=Audio",
"DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.documents.row=Documents",
"DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.executables.row=Executables",
"DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.images.row=Images",
"DataSourceSummaryCountsPanel.FilesByMimeTypeTableModel.videos.row=Videos",
"DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_other_label=Other",
"DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_notAnalyzed_label=Not Analyzed"
})
FileTypePieChart() {
// Create chart
JFreeChart chart = ChartFactory.createPieChart(
Bundle.DataSourceSummaryCountsPanel_byMimeTypeLabel_text(),
dataset,
true,
true,
false);
chart.setBackgroundPaint(null);
chart.getLegend().setItemFont(DEFAULT_FONT);
chart.getTitle().setFont(DEFAULT_HEADER_FONT);
PiePlot plot = ((PiePlot) chart.getPlot());
//Format Label
PieSectionLabelGenerator labelGenerator = new StandardPieSectionLabelGenerator(
"{0}: {1} ({2})", new DecimalFormat("0"), new DecimalFormat("0.0%"));
plot.setLabelGenerator(labelGenerator);
plot.setLabelFont(DEFAULT_FONT);
plot.setBackgroundPaint(null);
plot.setOutlinePaint(null);
// Create Panel
ChartPanel panel = new ChartPanel(chart);
this.setLayout(new BorderLayout());
this.add(panel, BorderLayout.CENTER);
}
/**
* The datasource currently used as the model with this pie chart.
*
* @return The datasource currently being used as the model in this pie
* chart.
*/
DataSource getDataSource() {
return dataSource;
}
/**
* Sets datasource to visualize in the pie chart.
*
* @param dataSource The datasource to use in this pie chart.
*/
void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.dataset.clear();
if (dataSource != null) {
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_images_row(),
this.dataSource, FileTypeCategory.IMAGE);
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_videos_row(),
this.dataSource, FileTypeCategory.VIDEO);
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_audio_row(),
this.dataSource, FileTypeCategory.AUDIO);
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_documents_row(),
this.dataSource, FileTypeCategory.DOCUMENTS);
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_executables_row(),
this.dataSource, FileTypeCategory.EXECUTABLE);
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_other_label(),
DataSourceMimeTypeSummary.getCountOfFilesNotInMimeTypes(this.dataSource, ALL_CATEGORY_MIME_TYPES));
addIfPresent(Bundle.DataSourceSummaryCountsPanel_FilesByMimeTypeTableModel_notAnalyzed_label(),
DataSourceMimeTypeSummary.getCountOfFilesWithNoMimeType(this.dataSource));
}
}
/**
* Adds count for file type category if there is a value. Uses fields
* 'dataSource' and 'dataset'.
*
* @param label The label for this pie slice.
* @param dataSource The data source.
* @param category The category for the pie slice.
*/
private void addIfPresent(String label, DataSource dataSource, FileTypeUtils.FileTypeCategory category) {
if (dataSource == null) {
return;
}
Long count = getCount(dataSource, category);
addIfPresent(label, count);
}
/**
* Adds count for a a label if the count is non-null and greater than 0.
*
* @param label The label.
* @param count The count.
*/
private void addIfPresent(String label, Long count) {
if (count != null && count > 0) {
this.dataset.setValue(label, count);
}
}
/**
* Retrieves the counts of files of a particular mime type for a particular
* DataSource.
*
* @param dataSource The DataSource.
* @param category The mime type category.
*
* @return The count.
*/
private static Long getCount(DataSource dataSource, FileTypeUtils.FileTypeCategory category) {
return DataSourceMimeTypeSummary.getCountOfFilesForMimeTypes(dataSource, category.getMediaTypes());
}
}

View File

@ -0,0 +1,103 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.datasourcesummary.ui;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import org.openide.util.NbBundle;
/**
* This class provides utilities for representing storage size in most relevant
* units (i.e. bytes, megabytes, etc.).
*/
public final class SizeRepresentationUtil {
private static final int SIZE_CONVERSION_CONSTANT = 1000;
private static final DecimalFormat APPROXIMATE_SIZE_FORMAT = new DecimalFormat("#.##");
private static List<String> UNITS = Arrays.asList(
Bundle.SizeRepresentationUtil_units_bytes(),
Bundle.SizeRepresentationUtil_units_kilobytes(),
Bundle.SizeRepresentationUtil_units_megabytes(),
Bundle.SizeRepresentationUtil_units_gigabytes(),
Bundle.SizeRepresentationUtil_units_terabytes(),
Bundle.SizeRepresentationUtil_units_petabytes()
);
/**
* Get a long size in bytes as a string formated to be read by users.
*
* @param size Long value representing a size in bytes.
*
* @return Return a string formated with a user friendly version of the size
* as a string, returns empty String when provided empty size.
*/
public static String getSizeString(Long size) {
return getSizeString(size, APPROXIMATE_SIZE_FORMAT, true);
}
/**
* Get a long size in bytes as a string formated to be read by users.
*
* @param size Long value representing a size in byte.s
* @param format The means of formatting the number.
* @param showFullSize Optionally show the number of bytes in the
* datasource.
*
* @return Return a string formated with a user friendly version of the size
* as a string, returns empty String when provided empty size.
*/
@NbBundle.Messages({
"SizeRepresentationUtil_units_bytes= bytes",
"SizeRepresentationUtil_units_kilobytes= kB",
"SizeRepresentationUtil_units_megabytes= MB",
"SizeRepresentationUtil_units_gigabytes= GB",
"SizeRepresentationUtil_units_terabytes= TB",
"SizeRepresentationUtil_units_petabytes= PB"
})
public static String getSizeString(Long size, DecimalFormat format, boolean showFullSize) {
if (size == null) {
return "";
}
double approximateSize = size;
int unitsIndex = 0;
for (; unitsIndex < UNITS.size(); unitsIndex++) {
if (approximateSize < SIZE_CONVERSION_CONSTANT) {
break;
} else {
approximateSize /= SIZE_CONVERSION_CONSTANT;
}
}
String fullSize = size + UNITS.get(0);
String closestUnitSize = format.format(approximateSize) + UNITS.get(unitsIndex);
if (unitsIndex == 0) {
return fullSize;
} else if (showFullSize) {
return String.format("%s (%s)", closestUnitSize, fullSize);
} else {
return closestUnitSize;
}
}
private SizeRepresentationUtil() {
}
}

View File

@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.8" 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,2,20,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollParent">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<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.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="contentParent">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
<EmptyBorder bottom="10" left="10" right="10" top="10"/>
</Border>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32787, 32787]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 490]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="3"/>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="usagePanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 20]"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 20]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="usageLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="osPanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 20]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="osLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="sizePanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 20]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="sizeLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="fileMimeTypesPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
<EmptyBorder bottom="5" left="5" right="5" top="5"/>
</Border>
</Property>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 300]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 300]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 300]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="fileMimeTypesChart"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<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, 5]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 5]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 5]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
</AuxValues>
</Component>
<Container class="javax.swing.JPanel" name="allocatedPanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 16]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 16]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 16]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="allocatedLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="unallocatedPanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 16]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 16]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 16]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="unallocatedLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="slackPanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 16]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 16]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 16]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="slackLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="directoriesPanel">
<Properties>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 16]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[10, 16]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[800, 16]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="directoriesLabel"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Component class="javax.swing.Box$Filler" name="filler3">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 32767]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,377 @@
/*
* 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.datasourcesummary.ui;
import java.awt.BorderLayout;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.swing.JLabel;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceCountsSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceDetailsSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceMimeTypeSummary;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.AbstractLoadableComponent;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem;
import org.sleuthkit.datamodel.DataSource;
/**
* Panel for displaying summary information on the known files present in the
* specified DataSource.
*/
@Messages({
"TypesPanel_artifactsTypesPieChart_title=Artifact Types",
"TypesPanel_filesByCategoryTable_allocatedRow_title=Allocated Files",
"TypesPanel_filesByCategoryTable_unallocatedRow_title=Unallocated Files",
"TypesPanel_filesByCategoryTable_slackRow_title=Slack Files",
"TypesPanel_filesByCategoryTable_directoryRow_title=Directories",
"TypesPanel_fileMimeTypesChart_title=File Types",
"TypesPanel_fileMimeTypesChart_audio_title=Audio",
"TypesPanel_fileMimeTypesChart_documents_title=Documents",
"TypesPanel_fileMimeTypesChart_executables_title=Executables",
"TypesPanel_fileMimeTypesChart_images_title=Images",
"TypesPanel_fileMimeTypesChart_videos_title=Videos",
"TypesPanel_fileMimeTypesChart_other_title=Other",
"TypesPanel_fileMimeTypesChart_unknown_title=Unknown",
"TypesPanel_fileMimeTypesChart_notAnalyzed_title=Not Analyzed",
"TypesPanel_usageLabel_title=Usage",
"TypesPanel_osLabel_title=OS",
"TypesPanel_sizeLabel_title=Size"})
class TypesPanel extends BaseDataSourceSummaryPanel {
/**
* A label that allows for displaying loading messages and can be used with
* a DataFetchResult. Text displays as "<key>:<value | message>".
*/
private static class LoadableLabel extends AbstractLoadableComponent<String> {
private static final long serialVersionUID = 1L;
private final JLabel label = new JLabel();
private final String key;
/**
* Main constructor for the label.
*
* @param key The key to be displayed.
*/
LoadableLabel(String key) {
this.key = key;
setLayout(new BorderLayout());
add(label, BorderLayout.CENTER);
this.showResults(null);
}
private void setValue(String value, boolean italicize) {
String formattedKey = StringUtils.isBlank(key) ? "" : key;
String formattedValue = StringUtils.isBlank(value) ? "" : value;
String htmlFormattedValue = (italicize) ? String.format("<i>%s</i>", formattedValue) : formattedValue;
label.setText(String.format("<html><div style='text-align: center;'>%s: %s</div></html>", formattedKey, htmlFormattedValue));
}
@Override
protected void setMessage(boolean visible, String message) {
setValue(message, true);
}
@Override
protected void setResults(String data) {
setValue(data, false);
}
}
private static final long serialVersionUID = 1L;
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat("#,###");
// All file type categories.
private static final List<Pair<String, Set<String>>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes()),
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes()),
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes()),
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes()),
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes()),
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")))
);
private final LoadableLabel usageLabel = new LoadableLabel(Bundle.TypesPanel_usageLabel_title());
private final LoadableLabel osLabel = new LoadableLabel(Bundle.TypesPanel_osLabel_title());
private final LoadableLabel sizeLabel = new LoadableLabel(Bundle.TypesPanel_sizeLabel_title());
private final PieChartPanel fileMimeTypesChart = new PieChartPanel(Bundle.TypesPanel_fileMimeTypesChart_title());
private final LoadableLabel allocatedLabel = new LoadableLabel(Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title());
private final LoadableLabel unallocatedLabel = new LoadableLabel(Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title());
private final LoadableLabel slackLabel = new LoadableLabel(Bundle.TypesPanel_filesByCategoryTable_slackRow_title());
private final LoadableLabel directoriesLabel = new LoadableLabel(Bundle.TypesPanel_filesByCategoryTable_directoryRow_title());
// all loadable components
private final List<LoadableComponent<?>> loadables = Arrays.asList(
usageLabel,
osLabel,
sizeLabel,
fileMimeTypesChart,
allocatedLabel,
unallocatedLabel,
slackLabel,
directoriesLabel
);
// all of the means for obtaining data for the gui components.
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents = Arrays.asList(
// usage label worker
new DataFetchWorker.DataFetchComponents<>(
DataSourceDetailsSummary::getDataSourceType,
usageLabel::showDataFetchResult),
// os label worker
new DataFetchWorker.DataFetchComponents<>(
DataSourceDetailsSummary::getOperatingSystems,
osLabel::showDataFetchResult),
// size label worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> {
Long size = dataSource == null ? null : dataSource.getSize();
return SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false);
},
sizeLabel::showDataFetchResult),
// file types worker
new DataFetchWorker.DataFetchComponents<>(
this::getMimeTypeCategoriesModel,
fileMimeTypesChart::showDataFetchResult),
// allocated files worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getStringOrZero(DataSourceCountsSummary.getCountOfAllocatedFiles(dataSource)),
allocatedLabel::showDataFetchResult),
// unallocated files worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getStringOrZero(DataSourceCountsSummary.getCountOfUnallocatedFiles(dataSource)),
unallocatedLabel::showDataFetchResult),
// slack files worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getStringOrZero(DataSourceCountsSummary.getCountOfSlackFiles(dataSource)),
slackLabel::showDataFetchResult),
// directories worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getStringOrZero(DataSourceCountsSummary.getCountOfDirectories(dataSource)),
directoriesLabel::showDataFetchResult)
);
/**
* Main constructor.
*/
public TypesPanel() {
initComponents();
}
@Override
protected void onNewDataSource(DataSource dataSource) {
// if no data source is present or the case is not open,
// set results for tables to null.
if (dataSource == null || !Case.isCaseOpen()) {
this.dataFetchComponents.forEach((item) -> item.getResultHandler()
.accept(DataFetchResult.getSuccessResult(null)));
} else {
// set tables to display loading screen
this.loadables.forEach((table) -> table.showDefaultLoadingMessage());
// create swing workers to run for each table
List<DataFetchWorker<?, ?>> workers = dataFetchComponents
.stream()
.map((components) -> new DataFetchWorker<>(components, dataSource))
.collect(Collectors.toList());
// submit swing workers to run
submit(workers);
}
}
/**
* Gets all the data for the file type pie chart.
*
* @param dataSource The datasource.
*
* @return The pie chart items.
*/
private List<PieChartItem> getMimeTypeCategoriesModel(DataSource dataSource) {
if (dataSource == null) {
return null;
}
// for each category of file types, get the counts of files
List<Pair<String, Long>> fileCategoryItems = FILE_MIME_TYPE_CATEGORIES
.stream()
.map((strCat) -> {
return Pair.of(strCat.getLeft(),
getLongOrZero(DataSourceMimeTypeSummary.getCountOfFilesForMimeTypes(
dataSource, strCat.getRight())));
})
.collect(Collectors.toList());
// get a count of all files with no mime type
Long noMimeTypeCount = getLongOrZero(DataSourceMimeTypeSummary.getCountOfFilesWithNoMimeType(dataSource));
// get the sum of all counts for the known categories
Long categoryTotalCount = getLongOrZero(fileCategoryItems.stream()
.collect(Collectors.summingLong((pair) -> pair.getValue())));
// get a count of all regular files
Long allRegularFiles = getLongOrZero(DataSourceMimeTypeSummary.getCountOfAllRegularFiles(dataSource));
// create entry for mime types in other category
fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(),
allRegularFiles - (categoryTotalCount + noMimeTypeCount)));
// create entry for not analyzed mime types category
fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_notAnalyzed_title(),
noMimeTypeCount));
// create pie chart items to provide to pie chart
return fileCategoryItems.stream()
.filter(keyCount -> keyCount.getRight() != null && keyCount.getRight() > 0)
.map(keyCount -> new PieChartItem(keyCount.getLeft(), keyCount.getRight()))
.collect(Collectors.toList());
}
/**
* Returns the long value or zero if longVal is null.
*
* @param longVal The long value.
*
* @return The long value or 0 if provided value is null.
*/
private static long getLongOrZero(Long longVal) {
return longVal == null ? 0 : longVal;
}
/**
* Returns string value of long with comma separators. If null returns a
* string of '0'.
*
* @param longVal The long value.
*
* @return The string value of the long.
*/
private static String getStringOrZero(Long longVal) {
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
}
/**
* 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() {
javax.swing.JScrollPane scrollParent = new javax.swing.JScrollPane();
javax.swing.JPanel contentParent = new javax.swing.JPanel();
javax.swing.JPanel usagePanel = usageLabel;
javax.swing.JPanel osPanel = osLabel;
javax.swing.JPanel sizePanel = sizeLabel;
javax.swing.JPanel fileMimeTypesPanel = fileMimeTypesChart;
javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5));
javax.swing.JPanel allocatedPanel = allocatedLabel;
javax.swing.JPanel unallocatedPanel = unallocatedLabel;
javax.swing.JPanel slackPanel = slackLabel;
javax.swing.JPanel directoriesPanel = directoriesLabel;
javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
setLayout(new java.awt.BorderLayout());
contentParent.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
contentParent.setMaximumSize(new java.awt.Dimension(32787, 32787));
contentParent.setMinimumSize(new java.awt.Dimension(400, 490));
contentParent.setLayout(new javax.swing.BoxLayout(contentParent, javax.swing.BoxLayout.PAGE_AXIS));
usagePanel.setAlignmentX(0.0F);
usagePanel.setMaximumSize(new java.awt.Dimension(32767, 20));
usagePanel.setMinimumSize(new java.awt.Dimension(10, 20));
usagePanel.setName(""); // NOI18N
usagePanel.setPreferredSize(new java.awt.Dimension(800, 20));
contentParent.add(usagePanel);
osPanel.setAlignmentX(0.0F);
osPanel.setMaximumSize(new java.awt.Dimension(32767, 20));
osPanel.setMinimumSize(new java.awt.Dimension(10, 20));
osPanel.setPreferredSize(new java.awt.Dimension(800, 20));
contentParent.add(osPanel);
sizePanel.setAlignmentX(0.0F);
sizePanel.setMaximumSize(new java.awt.Dimension(32767, 20));
sizePanel.setMinimumSize(new java.awt.Dimension(10, 20));
sizePanel.setPreferredSize(new java.awt.Dimension(800, 20));
contentParent.add(sizePanel);
fileMimeTypesPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
fileMimeTypesPanel.setAlignmentX(0.0F);
fileMimeTypesPanel.setMaximumSize(new java.awt.Dimension(400, 300));
fileMimeTypesPanel.setMinimumSize(new java.awt.Dimension(400, 300));
fileMimeTypesPanel.setPreferredSize(new java.awt.Dimension(400, 300));
contentParent.add(fileMimeTypesPanel);
contentParent.add(filler2);
allocatedPanel.setAlignmentX(0.0F);
allocatedPanel.setMaximumSize(new java.awt.Dimension(32767, 16));
allocatedPanel.setMinimumSize(new java.awt.Dimension(10, 16));
allocatedPanel.setPreferredSize(new java.awt.Dimension(800, 16));
contentParent.add(allocatedPanel);
unallocatedPanel.setAlignmentX(0.0F);
unallocatedPanel.setMaximumSize(new java.awt.Dimension(32767, 16));
unallocatedPanel.setMinimumSize(new java.awt.Dimension(10, 16));
unallocatedPanel.setPreferredSize(new java.awt.Dimension(800, 16));
contentParent.add(unallocatedPanel);
slackPanel.setAlignmentX(0.0F);
slackPanel.setMaximumSize(new java.awt.Dimension(32767, 16));
slackPanel.setMinimumSize(new java.awt.Dimension(10, 16));
slackPanel.setPreferredSize(new java.awt.Dimension(800, 16));
contentParent.add(slackPanel);
directoriesPanel.setAlignmentX(0.0F);
directoriesPanel.setMaximumSize(new java.awt.Dimension(32767, 16));
directoriesPanel.setMinimumSize(new java.awt.Dimension(10, 16));
directoriesPanel.setPreferredSize(new java.awt.Dimension(800, 16));
contentParent.add(directoriesPanel);
contentParent.add(filler3);
scrollParent.setViewportView(contentParent);
add(scrollParent, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,170 @@
/*
* 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.datasourcesummary.uiutils;
import java.util.Collection;
import java.util.logging.Level;
import javax.swing.JPanel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Abstract class for common methods of a loadable component.
*/
@NbBundle.Messages({
"AbstractLoadableComponent_loadingMessage_defaultText=Loading results...",
"AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results.",
"AbstractLoadableComponent_noDataExists_defaultText=No data exists.",})
public abstract class AbstractLoadableComponent<T> extends JPanel implements LoadableComponent<T> {
private static final long serialVersionUID = 1L;
/**
* The default loading message.
*/
public static final String DEFAULT_LOADING_MESSAGE = Bundle.AbstractLoadableComponent_loadingMessage_defaultText();
/**
* The default error message.
*/
public static final String DEFAULT_ERROR_MESSAGE = Bundle.AbstractLoadableComponent_errorMessage_defaultText();
/**
* The default 'no results' message.
*/
public static final String DEFAULT_NO_RESULTS_MESSAGE = Bundle.AbstractLoadableComponent_noDataExists_defaultText();
private static final Logger logger = Logger.getLogger(AbstractLoadableComponent.class.getName());
/**
* @return The default error message.
*/
public static String getDefaultErrorMessage() {
return DEFAULT_ERROR_MESSAGE;
}
/**
* @return The default message for no results.
*/
public static String getDefaultNoResultsMessage() {
return DEFAULT_NO_RESULTS_MESSAGE;
}
/**
* Clears the results from the underlying JTable and shows the provided
* message.
*
* @param message The message to be shown.
*/
public synchronized void showMessage(String message) {
setResults(null);
setMessage(true, message);
repaint();
}
/**
* Shows a default loading message on the table. This will clear any results
* in the table.
*/
public void showDefaultLoadingMessage() {
showMessage(DEFAULT_LOADING_MESSAGE);
}
/**
* Shows the list as rows of data in the table. If overlay message will be
* cleared if present.
*
* @param data The data to be shown where each item represents a row of
* data.
*/
public synchronized void showResults(T data) {
setMessage(false, null);
setResults(data);
repaint();
}
/**
* Shows the data in a DataFetchResult. If there was an error during the
* operation, the errorMessage will be displayed. If the operation completed
* successfully and no data is present, noResultsMessage will be shown.
* Otherwise, the data will be shown as rows in the table.
*
* @param result The DataFetchResult.
* @param errorMessage The error message to be shown in the event of an
* error.
* @param noResultsMessage The message to be shown if there are no results
* but the operation completed successfully.
*/
public void showDataFetchResult(DataFetchResult<T> result, String errorMessage, String noResultsMessage) {
if (result == null) {
logger.log(Level.SEVERE, "Null data fetch result received.");
return;
}
switch (result.getResultType()) {
case SUCCESS:
T data = result.getData();
if (data == null || (data instanceof Collection<?> && ((Collection<?>) data).isEmpty())) {
showMessage(noResultsMessage);
} else {
showResults(data);
}
break;
case ERROR:
// if there is an error, log accordingly, set result list to
// empty and display error message
logger.log(Level.WARNING, "An exception was caused while results were loaded.", result.getException());
showMessage(errorMessage);
break;
default:
// an unknown loading state was specified. log accordingly.
logger.log(Level.SEVERE, "No known loading state was found in result.");
break;
}
}
/**
* Shows the data in a DataFetchResult. If there was an error during the
* operation, the DEFAULT_ERROR_MESSAGE will be displayed. If the operation
* completed successfully and no data is present, DEFAULT_NO_RESULTS_MESSAGE
* will be shown. Otherwise, the data will be shown as rows in the table.
*
* @param result The DataFetchResult.
*/
public void showDataFetchResult(DataFetchResult<T> result) {
showDataFetchResult(result, DEFAULT_ERROR_MESSAGE, DEFAULT_NO_RESULTS_MESSAGE);
}
/**
* Sets the message and visibility of the message. Repaint does not need to
* be handled in this method.
*
* @param visible The visibility of the message.
* @param message The message to be displayed if visible.
*/
protected abstract void setMessage(boolean visible, String message);
/**
* Sets the data to be shown in the JTable. Repaint does not need to be
* handled in this method.
*
* @param data The list of data objects to be shown.
*/
protected abstract void setResults(T data);
}

View File

@ -0,0 +1,87 @@
/*
* 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.datasourcesummary.uiutils;
import java.awt.Graphics;
import javax.swing.JLabel;
/**
* Base class for drawing a message overlay. Contains a paint method for
* painting a JLabel using a java.awt.Graphics object.
*/
public class BaseMessageOverlay {
private final JLabel label;
private boolean visible = false;
/**
* Main constructor for the Overlay.
*/
public BaseMessageOverlay() {
label = new JLabel();
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setOpaque(false);
}
/**
* @return Whether or not this message overlay should be visible.
*/
public boolean isVisible() {
return visible;
}
/**
* Sets this layer visible when painted. In order to be shown in UI, this
* component needs to be repainted.
*
* @param visible Whether or not it is visible.
*/
public void setVisible(boolean visible) {
this.visible = visible;
}
/**
* Sets the message to be displayed in the child jlabel.
*
* @param message The message to be displayed.
*/
public void setMessage(String message) {
label.setText(String.format("<html><div style='text-align: center;'>%s</div></html>",
message == null ? "" : message));
}
/**
* Paints the jlabel at full width and height with the graphics object.
*
* @param g The graphics object.
* @param width The width.
* @param height The height.
*/
public void paintOverlay(Graphics g, int width, int height) {
if (!visible) {
return;
}
// paint the jlabel if visible.
label.setBounds(0, 0, width, height);
label.paint(g);
}
}

View File

@ -1,3 +1,3 @@
JTablePanel_errorMessage_defaultText=There was an error loading results. AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results.
JTablePanel_loadingMessage_defaultText=Loading results... AbstractLoadableComponent_loadingMessage_defaultText=Loading results...
JTablePanel_noDataExists_defaultText=No data exists. AbstractLoadableComponent_noDataExists_defaultText=No data exists.

View File

@ -23,31 +23,22 @@ import java.awt.Graphics;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayer; import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.plaf.LayerUI; import javax.swing.plaf.LayerUI;
import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.CellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.CellModel;
/** /**
* A table that displays a list of items and also can display messages for * A table that displays a list of items and also can display messages for
* loading, load error, and not loaded. * loading, load error, and not loaded.
*/ */
@Messages({ public class JTablePanel<T> extends AbstractLoadableComponent<List<T>> {
"JTablePanel_loadingMessage_defaultText=Loading results...",
"JTablePanel_errorMessage_defaultText=There was an error loading results.",
"JTablePanel_noDataExists_defaultText=No data exists.",})
public class JTablePanel<T> extends JPanel {
/** /**
* JTables don't allow displaying messages. So this LayerUI is used to * JTables don't allow displaying messages. So this LayerUI is used to
@ -58,27 +49,7 @@ public class JTablePanel<T> extends JPanel {
private static class Overlay extends LayerUI<JComponent> { private static class Overlay extends LayerUI<JComponent> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final BaseMessageOverlay overlayDelegate = new BaseMessageOverlay();
private final JLabel label;
private boolean visible;
/**
* Main constructor for the Overlay.
*/
Overlay() {
label = new JLabel();
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setOpaque(false);
}
/**
* @return Whether or not this message overlay should be visible.
*/
boolean isVisible() {
return visible;
}
/** /**
* Sets this layer visible when painted. In order to be shown in UI, * Sets this layer visible when painted. In order to be shown in UI,
@ -87,7 +58,7 @@ public class JTablePanel<T> extends JPanel {
* @param visible Whether or not it is visible. * @param visible Whether or not it is visible.
*/ */
void setVisible(boolean visible) { void setVisible(boolean visible) {
this.visible = visible; overlayDelegate.setVisible(visible);
} }
/** /**
@ -96,25 +67,13 @@ public class JTablePanel<T> extends JPanel {
* @param message The message to be displayed. * @param message The message to be displayed.
*/ */
void setMessage(String message) { void setMessage(String message) {
label.setText(String.format("<html><div style='text-align: center;'>%s</div></html>", overlayDelegate.setMessage(message);
message == null ? "" : message));
} }
@Override @Override
public void paint(Graphics g, JComponent c) { public void paint(Graphics g, JComponent c) {
// Paint the underlying view.
super.paint(g, c); super.paint(g, c);
overlayDelegate.paintOverlay(g, c.getWidth(), c.getHeight());
if (!visible) {
return;
}
int w = c.getWidth();
int h = c.getHeight();
// paint the jlabel if visible.
label.setBounds(0, 0, w, h);
label.paint(g);
} }
} }
@ -179,12 +138,6 @@ public class JTablePanel<T> extends JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(JTablePanel.class.getName());
private static final String DEFAULT_LOADING_MESSAGE = Bundle.JTablePanel_loadingMessage_defaultText();
private static final String DEFAULT_ERROR_MESSAGE = Bundle.JTablePanel_errorMessage_defaultText();
private static final String DEFAULT_NO_RESULTS_MESSAGE = Bundle.JTablePanel_noDataExists_defaultText();
private static final CellModelTableCellRenderer DEFAULT_CELL_RENDERER = new CellModelTableCellRenderer(); private static final CellModelTableCellRenderer DEFAULT_CELL_RENDERER = new CellModelTableCellRenderer();
/** /**
@ -231,7 +184,7 @@ public class JTablePanel<T> extends JPanel {
.map((colModel) -> colModel.getCellRenderer()) .map((colModel) -> colModel.getCellRenderer())
.collect(Collectors.toList()); .collect(Collectors.toList());
return new DefaultListTableModel<>(columnRenderers); return new DefaultListTableModel<T>(columnRenderers);
} }
/** /**
@ -248,20 +201,6 @@ public class JTablePanel<T> extends JPanel {
return resultTable.setColumnModel(getTableColumnModel(columns)); return resultTable.setColumnModel(getTableColumnModel(columns));
} }
/**
* @return The default error message.
*/
public static String getDefaultErrorMessage() {
return DEFAULT_ERROR_MESSAGE;
}
/**
* @return The default message for no results.
*/
public static String getDefaultNoResultsMessage() {
return DEFAULT_NO_RESULTS_MESSAGE;
}
private JScrollPane tableScrollPane; private JScrollPane tableScrollPane;
private Overlay overlayLayer; private Overlay overlayLayer;
private ListTableModel<T> tableModel; private ListTableModel<T> tableModel;
@ -285,7 +224,7 @@ public class JTablePanel<T> extends JPanel {
} }
/** /**
* Set the table model. This method must be called prior to calling * Set the table model. This method must be called prior to calling
* setResultList. * setResultList.
* *
* @param tableModel * @param tableModel
@ -318,18 +257,8 @@ public class JTablePanel<T> extends JPanel {
return this; return this;
} }
/** @Override
* Sets the data to be shown in the JTable. Repaint is not handled in this protected void setResults(List<T> data) {
* method and should be handled separately.
*
* @param data The list of data objects to be shown.
*/
private void setResultList(List<T> data) {
if(tableModel == null) {
throw new IllegalStateException("ListTableModel has not be initialized");
}
// set the list of data to be shown as either the data or an empty list // set the list of data to be shown as either the data or an empty list
// on null. // on null.
List<T> dataToSet = (data == null) ? Collections.emptyList() : data; List<T> dataToSet = (data == null) ? Collections.emptyList() : data;
@ -341,102 +270,12 @@ public class JTablePanel<T> extends JPanel {
this.tableModel.setDataRows(dataToSet); this.tableModel.setDataRows(dataToSet);
} }
/** @Override
* Sets the message and visibility of the overlay. Repaint is not handled in protected void setMessage(boolean visible, String message) {
* this method and should be handled separately.
*
* @param visible The visibility of the overlay.
* @param message The message in the overlay.
*/
private void setOverlay(boolean visible, String message) {
this.overlayLayer.setVisible(visible); this.overlayLayer.setVisible(visible);
this.overlayLayer.setMessage(message); this.overlayLayer.setMessage(message);
} }
/**
* Clears the results from the underlying JTable and shows the provided
* message.
*
* @param message The message to be shown.
*/
public synchronized void showMessage(String message) {
setResultList(null);
setOverlay(true, message);
repaint();
}
/**
* Shows a default loading message on the table. This will clear any results
* in the table.
*/
public void showDefaultLoadingMessage() {
showMessage(DEFAULT_LOADING_MESSAGE);
}
/**
* Shows the list as rows of data in the table. If overlay message will be
* cleared if present.
*
* @param data The data to be shown where each item represents a row of
* data.
*/
public synchronized void showResults(List<T> data) {
setOverlay(false, null);
setResultList(data);
repaint();
}
/**
* Shows the data in a DataFetchResult. If there was an error during the
* operation, the errorMessage will be displayed. If the operation completed
* successfully and no data is present, noResultsMessage will be shown.
* Otherwise, the data will be shown as rows in the table.
*
* @param result The DataFetchResult.
* @param errorMessage The error message to be shown in the event of an
* error.
* @param noResultsMessage The message to be shown if there are no results
* but the operation completed successfully.
*/
public void showDataFetchResult(DataFetchResult<List<T>> result, String errorMessage, String noResultsMessage) {
if (result == null) {
logger.log(Level.SEVERE, "Null data processor result received.");
return;
}
switch (result.getResultType()) {
case SUCCESS:
if (result.getData() == null || result.getData().isEmpty()) {
showMessage(noResultsMessage);
} else {
showResults(result.getData());
}
break;
case ERROR:
// if there is an error, log accordingly, set result list to
// empty and display error message
logger.log(Level.WARNING, "An exception was caused while results were loaded.", result.getException());
showMessage(errorMessage);
break;
default:
// an unknown loading state was specified. log accordingly.
logger.log(Level.SEVERE, "No known loading state was found in result.");
break;
}
}
/**
* Shows the data in a DataFetchResult. If there was an error during the
* operation, the DEFAULT_ERROR_MESSAGE will be displayed. If the operation
* completed successfully and no data is present, DEFAULT_NO_RESULTS_MESSAGE
* will be shown. Otherwise, the data will be shown as rows in the table.
*
* @param result The DataFetchResult.
*/
public void showDataFetchResult(DataFetchResult<List<T>> result) {
showDataFetchResult(result, DEFAULT_ERROR_MESSAGE, DEFAULT_NO_RESULTS_MESSAGE);
}
/** /**
* Initialize the gui components. * Initialize the gui components.
*/ */

View File

@ -0,0 +1,73 @@
/*
* 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.datasourcesummary.uiutils;
/**
* Interface for a loadable component that can show messages, results, or a
* DataFetchResult.
*/
public interface LoadableComponent<T> {
/**
* Clears the results from the underlying JTable and shows the provided
* message.
*
* @param message The message to be shown.
*/
void showMessage(String message);
/**
* Shows a default loading message on the table. This will clear any results
* in the table.
*/
void showDefaultLoadingMessage();
/**
* Shows the list as rows of data in the table. If overlay message will be
* cleared if present.
*
* @param data The data to be shown where each item represents a row of
* data.
*/
void showResults(T data);
/**
* Shows the data in a DataFetchResult. If there was an error during the
* operation, the errorMessage will be displayed. If the operation completed
* successfully and no data is present, noResultsMessage will be shown.
* Otherwise, the data will be shown as rows in the table.
*
* @param result The DataFetchResult.
* @param errorMessage The error message to be shown in the event of an
* error.
* @param noResultsMessage The message to be shown if there are no results
* but the operation completed successfully.
*/
void showDataFetchResult(DataFetchResult<T> result, String errorMessage, String noResultsMessage);
/**
* Shows the data in a DataFetchResult. If there was an error during the
* operation, the DEFAULT_ERROR_MESSAGE will be displayed. If the operation
* completed successfully and no data is present, DEFAULT_NO_RESULTS_MESSAGE
* will be shown. Otherwise, the data will be shown as rows in the table.
*
* @param result The DataFetchResult.
*/
void showDataFetchResult(DataFetchResult<T> result);
}

View File

@ -0,0 +1,201 @@
/*
* 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.datasourcesummary.uiutils;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Graphics2D;
import java.text.DecimalFormat;
import java.util.List;
import javax.swing.JLabel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.panel.AbstractOverlay;
import org.jfree.chart.panel.Overlay;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
/**
* A pie chart panel.
*/
public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.PieChartItem>> {
/**
* An individual pie chart slice in the pie chart.
*/
public static class PieChartItem {
private final String label;
private final double value;
/**
* Main constructor.
*
* @param label The label for this pie slice.
* @param value The value for this item.
*/
public PieChartItem(String label, double value) {
this.label = label;
this.value = value;
}
/**
* @return The label for this item.
*/
public String getLabel() {
return label;
}
/**
* @return The value for this item.
*/
public double getValue() {
return value;
}
}
/**
* A JFreeChart message overlay that can show a message for the purposes of
* the LoadableComponent.
*/
private static class MessageOverlay extends AbstractOverlay implements Overlay {
private static final long serialVersionUID = 1L;
private final BaseMessageOverlay overlay = new BaseMessageOverlay();
/**
* Sets this layer visible when painted. In order to be shown in UI,
* this component needs to be repainted.
*
* @param visible Whether or not it is visible.
*/
void setVisible(boolean visible) {
overlay.setVisible(visible);
}
/**
* Sets the message to be displayed in the child jlabel.
*
* @param message The message to be displayed.
*/
void setMessage(String message) {
overlay.setMessage(message);
}
@Override
public void paintOverlay(Graphics2D gd, ChartPanel cp) {
overlay.paintOverlay(gd, cp.getWidth(), cp.getHeight());
}
}
private static final long serialVersionUID = 1L;
private static final Font DEFAULT_FONT = new JLabel().getFont();
private static final Font DEFAULT_HEADER_FONT = new Font(DEFAULT_FONT.getName(), DEFAULT_FONT.getStyle(), (int) (DEFAULT_FONT.getSize() * 1.5));
private static final PieSectionLabelGenerator DEFAULT_LABEL_GENERATOR
= new StandardPieSectionLabelGenerator(
"{0}: {1} ({2})", new DecimalFormat("#,###"), new DecimalFormat("0.0%"));
private final MessageOverlay overlay = new MessageOverlay();
private final DefaultPieDataset dataset = new DefaultPieDataset();
private final JFreeChart chart;
/**
* Main constructor.
*/
public PieChartPanel() {
this(null);
}
/**
* Main constructor for the pie chart.
*
* @param title The title for this pie chart.
*/
public PieChartPanel(String title) {
// Create chart
this.chart = ChartFactory.createPieChart(
title,
dataset,
true,
true,
false);
chart.setBackgroundPaint(null);
chart.getLegend().setItemFont(DEFAULT_FONT);
chart.getTitle().setFont(DEFAULT_HEADER_FONT);
// don't show a legend by default
chart.removeLegend();
PiePlot plot = ((PiePlot) chart.getPlot());
plot.setLabelGenerator(DEFAULT_LABEL_GENERATOR);
plot.setLabelFont(DEFAULT_FONT);
plot.setBackgroundPaint(null);
plot.setOutlinePaint(null);
// Create Panel
ChartPanel panel = new ChartPanel(chart);
panel.addOverlay(overlay);
this.setLayout(new BorderLayout());
this.add(panel, BorderLayout.CENTER);
}
/**
* @return The title for this chart if one exists.
*/
public String getTitle() {
return (this.chart == null || this.chart.getTitle() == null)
? null
: this.chart.getTitle().getText();
}
/**
* Sets the title for this pie chart.
*
* @param title The title.
*
* @return As a utility, returns this.
*/
public PieChartPanel setTitle(String title) {
this.chart.getTitle().setText(title);
return this;
}
@Override
protected void setMessage(boolean visible, String message) {
this.overlay.setVisible(visible);
this.overlay.setMessage(message);
}
@Override
protected void setResults(List<PieChartPanel.PieChartItem> data) {
this.dataset.clear();
if (data != null) {
for (PieChartPanel.PieChartItem slice : data) {
this.dataset.setValue(slice.getLabel(), slice.getValue());
}
}
}
}

View File

@ -70,7 +70,7 @@ final class AutoIngestJobLogger {
*/ */
INFO, INFO,
/** /**
* Qualifies a log message about an unexpected event or condtion during * Qualifies a log message about an unexpected event or condition during
* automated ingest processing. * automated ingest processing.
*/ */
WARNING, WARNING,
@ -208,6 +208,18 @@ final class AutoIngestJobLogger {
void logDataSourceProcessorSelected(String dsp) throws AutoIngestJobLoggerException, InterruptedException { void logDataSourceProcessorSelected(String dsp) throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.INFO, "Using data source processor: " + dsp); log(MessageCategory.INFO, "Using data source processor: " + dsp);
} }
/**
* Log that a data source is being skipped.
*
* @param dataSourceName The name of the data source
*
* @throws AutoIngestJobLogger.AutoIngestJobLoggerException
* @throws InterruptedException
*/
void logSkippingDataSource(String dataSourceName) throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.INFO, "File type can not currently be processed");
}
/** /**
* Logs the failure of the selected data source processor. * Logs the failure of the selected data source processor.

View File

@ -1040,7 +1040,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
} }
} }
/** /**
* A task that submits an input directory scan task to the input directory * A task that submits an input directory scan task to the input directory
* scan task executor. * scan task executor.
@ -2440,6 +2440,15 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now()));
return; return;
} }
if (SupportedDataSources.shouldSkipFile(dataSource.getPath().toString())) {
Manifest manifest = currentJob.getManifest();
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), currentJob.getCaseDirectoryPath());
jobLogger.logSkippingDataSource(dataSource.getPath().toString());
sysLogger.log(Level.INFO, "Skipping data source that can not be processed ({0})", dataSource.getPath().toString());
currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now()));
return;
}
if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) {
return; return;

View File

@ -0,0 +1,53 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.experimental.autoingest;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FilenameUtils;
/**
* Utility class for checking whether a data source/file should be processed
* in an automated setting. The goal is to not spend time analyzing large
* files that Autopsy can not handle yet.
*/
public final class SupportedDataSources {
private static final List<String> UNSUPPORTED_EXTENSIONS = Arrays.asList("xry", "dar");
/**
* Check whether a file should be added to a case, either as a data source or part of a
* logical file set.
*
* @param fileName The name of the file.
*
* @return true if the file is currently unsupported and should be skipped, false otherwise.
*/
public static boolean shouldSkipFile(String fileName) {
String ext = FilenameUtils.getExtension(fileName);
if (ext == null) {
return false;
}
return UNSUPPORTED_EXTENSIONS.contains(ext.toLowerCase());
}
private SupportedDataSources() {
// Static class
}
}