mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into solr4_batching_6766
This commit is contained in:
commit
99b9985c20
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,12 +61,23 @@ 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");
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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, "{key}")"/>
|
|
||||||
</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, "{key}")"/>
|
|
||||||
</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>
|
|
@ -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
|
|
||||||
}
|
|
@ -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.
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
@ -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
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
||||||
|
@ -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;
|
||||||
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
@ -209,6 +209,18 @@ final class AutoIngestJobLogger {
|
|||||||
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.
|
||||||
*
|
*
|
||||||
|
@ -2441,6 +2441,15 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user