cleanup of layout and commenting

This commit is contained in:
Greg DiCristofaro 2020-09-04 09:14:54 -04:00
parent 17644fe664
commit cd74274c44
10 changed files with 261 additions and 182 deletions

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.datasourcesummary.ui; package org.sleuthkit.autopsy.datasourcesummary.ui;
import java.text.DecimalFormat;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
@ -140,8 +139,6 @@ class DataSourceSummaryDetailsPanel extends BaseDataSourceSummaryPanel {
} }
} }
/** /**
* Update the visibility of all fields and their labels based on whether * Update the visibility of all fields and their labels based on whether
* they have contents. Empty fields have them and their contents hidden. * they have contents. Empty fields have them and their contents hidden.

View File

@ -1,7 +1,20 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * Autopsy Forensic Browser
* To change this template file, choose Tools | Templates *
* and open the template in the editor. * 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; package org.sleuthkit.autopsy.datasourcesummary.ui;
@ -11,8 +24,8 @@ import java.util.List;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
/** /**
* * This class provides utilities for representing storage size in most relevant
* @author gregd * units (i.e. bytes, megabytes, etc.).
*/ */
public class SizeRepresentationUtil { public class SizeRepresentationUtil {
@ -31,16 +44,26 @@ public class SizeRepresentationUtil {
/** /**
* Get a long size in bytes as a string formated to be read by users. * Get a long size in bytes as a string formated to be read by users.
* *
* @param size Long value representing a size in bytes * @param size Long value representing a size in bytes.
* *
* @return return a string formated with a user friendly version of the size * @return Return a string formated with a user friendly version of the size
* as a string, returns empty String when provided empty size * as a string, returns empty String when provided empty size.
*/ */
public static String getSizeString(Long size) { public static String getSizeString(Long size) {
return getSizeString(size, APPROXIMATE_SIZE_FORMAT, true); 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({ @NbBundle.Messages({
"SizeRepresentationUtil_units_bytes= bytes", "SizeRepresentationUtil_units_bytes= bytes",
"SizeRepresentationUtil_units_kilobytes= kB", "SizeRepresentationUtil_units_kilobytes= kB",
@ -62,10 +85,10 @@ public class SizeRepresentationUtil {
approximateSize /= SIZE_CONVERSION_CONSTANT; approximateSize /= SIZE_CONVERSION_CONSTANT;
} }
} }
String fullSize = String.valueOf(size) + UNITS.get(0); String fullSize = String.valueOf(size) + UNITS.get(0);
String closestUnitSize = format.format(approximateSize) + UNITS.get(unitsIndex); String closestUnitSize = format.format(approximateSize) + UNITS.get(unitsIndex);
if (unitsIndex == 0) { if (unitsIndex == 0) {
return fullSize; return fullSize;
} else if (showFullSize) { } else if (showFullSize) {

View File

@ -40,7 +40,10 @@
<Dimension value="[32787, 32787]"/> <Dimension value="[32787, 32787]"/>
</Property> </Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[650, 510]"/> <Dimension value="[400, 300]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 300]"/>
</Property> </Property>
</Properties> </Properties>
<AuxValues> <AuxValues>
@ -116,73 +119,31 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container> </Container>
<Container class="javax.swing.JPanel" name="pieChartRow"> <Container class="javax.swing.JPanel" name="fileMimeTypesPanel">
<Properties> <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="alignmentX" type="float" value="0.0"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[1170, 895]"/> <Dimension value="[400, 300]"/>
</Property> </Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/> <Dimension value="[400, 300]"/>
</Property> </Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/> <Dimension value="[400, 300]"/>
</Property> </Property>
</Properties> </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"/> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
<SubComponents>
<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="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[500, 375]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[500, 375]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[500, 375]"/>
</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>
<Container class="javax.swing.JPanel" name="artifactTypesPanel">
<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="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[650, 500]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[650, 500]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[650, 500]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="artifactTypesChart"/>
<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>
</SubComponents>
</Container> </Container>
<Component class="javax.swing.Box$Filler" name="filler2"> <Component class="javax.swing.Box$Filler" name="filler2">
<Properties> <Properties>
@ -252,6 +213,16 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container> </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="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/>
</AuxValues>
</Component>
</SubComponents> </SubComponents>
</Container> </Container>
</SubComponents> </SubComponents>

View File

@ -22,7 +22,6 @@ import java.awt.BorderLayout;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -46,13 +45,12 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem;
import org.sleuthkit.autopsy.guiutils.WrapLayout;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
/** /**
* Panel for displaying summary information on the known files present in the * Panel for displaying summary information on the known files present in the
* specified DataSource * specified DataSource.
*/ */
@Messages({ @Messages({
"TypesPanel_artifactsTypesPieChart_title=Artifact Types", "TypesPanel_artifactsTypesPieChart_title=Artifact Types",
@ -77,13 +75,23 @@ import org.sleuthkit.datamodel.DataSource;
"TypesPanel_sizeLabel_title=Size"}) "TypesPanel_sizeLabel_title=Size"})
class TypesPanel extends BaseDataSourceSummaryPanel { 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 class LoadableLabel extends AbstractLoadableComponent<String> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final JLabel label = new JLabel(); private final JLabel label = new JLabel();
private final String key; private final String key;
public LoadableLabel(String key) { /**
* Main constructor for the label.
*
* @param key The key to be displayed.
*/
LoadableLabel(String key) {
this.key = key; this.key = key;
setLayout(new BorderLayout()); setLayout(new BorderLayout());
add(label, BorderLayout.CENTER); add(label, BorderLayout.CENTER);
@ -96,7 +104,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
String htmlFormattedValue = (italicize) ? String.format("<i>%s</i>", formattedValue) : formattedValue; 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)); label.setText(String.format("<html><div style='text-align: center;'>%s: %s</div></html>", formattedKey, htmlFormattedValue));
} }
@Override @Override
protected void setMessage(boolean visible, String message) { protected void setMessage(boolean visible, String message) {
setValue(message, true); setValue(message, true);
@ -107,11 +115,11 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
setValue(data, false); setValue(data, false);
} }
} }
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#"); private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
// All file type categories.
private static final List<Pair<String, FileTypeCategory>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList( private static final List<Pair<String, FileTypeCategory>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE), Pair.of(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE),
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO), Pair.of(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO),
@ -120,43 +128,44 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE) Pair.of(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE)
); );
// The mime types in those categories.
private static final Set<String> CATEGORY_MIME_TYPES = FILE_MIME_TYPE_CATEGORIES private static final Set<String> CATEGORY_MIME_TYPES = FILE_MIME_TYPE_CATEGORIES
.stream() .stream()
.flatMap((cat) -> cat.getRight().getMediaTypes().stream()) .flatMap((cat) -> cat.getRight().getMediaTypes().stream())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
private final PieChartPanel fileMimeTypesChart = new PieChartPanel(Bundle.TypesPanel_fileMimeTypesChart_title()); private final PieChartPanel fileMimeTypesChart = new PieChartPanel(Bundle.TypesPanel_fileMimeTypesChart_title());
private final PieChartPanel artifactTypesChart = new PieChartPanel(Bundle.TypesPanel_artifactsTypesPieChart_title());
private final JTablePanel<Pair<String, Long>> filesByCategoryTable private final JTablePanel<Pair<String, Long>> filesByCategoryTable
= JTablePanel.getJTablePanel(Arrays.asList( = JTablePanel.getJTablePanel(Arrays.asList(
// title column
new ColumnModel<>( new ColumnModel<>(
Bundle.TypesPanel_filesByCategoryTable_labelColumn_title(), Bundle.TypesPanel_filesByCategoryTable_labelColumn_title(),
(pair) -> new DefaultCellModel(pair.getLeft()), (pair) -> new DefaultCellModel(pair.getLeft()),
250 250
), ),
// count column
new ColumnModel<>( new ColumnModel<>(
Bundle.TypesPanel_filesByCategoryTable_countColumn_title(), Bundle.TypesPanel_filesByCategoryTable_countColumn_title(),
(pair) -> new DefaultCellModel(Long.toString(pair.getRight() == null ? 0 : pair.getRight())), (pair) -> new DefaultCellModel(Long.toString(pair.getRight() == null ? 0 : pair.getRight())),
150 150
) )
)); ));
private final LoadableLabel usageLabel = new LoadableLabel(Bundle.TypesPanel_usageLabel_title()); private final LoadableLabel usageLabel = new LoadableLabel(Bundle.TypesPanel_usageLabel_title());
private final LoadableLabel osLabel = new LoadableLabel(Bundle.TypesPanel_osLabel_title()); private final LoadableLabel osLabel = new LoadableLabel(Bundle.TypesPanel_osLabel_title());
private final LoadableLabel sizeLabel = new LoadableLabel(Bundle.TypesPanel_sizeLabel_title()); private final LoadableLabel sizeLabel = new LoadableLabel(Bundle.TypesPanel_sizeLabel_title());
// all loadable components
private final List<LoadableComponent<?>> loadables = Arrays.asList( private final List<LoadableComponent<?>> loadables = Arrays.asList(
usageLabel, usageLabel,
osLabel, osLabel,
sizeLabel, sizeLabel,
fileMimeTypesChart, fileMimeTypesChart,
artifactTypesChart,
filesByCategoryTable filesByCategoryTable
); );
// all of the means for obtaining data for the gui components.
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents = Arrays.asList( private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents = Arrays.asList(
// usage label worker // usage label worker
new DataFetchWorker.DataFetchComponents<>( new DataFetchWorker.DataFetchComponents<>(
@ -177,23 +186,17 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
new DataFetchWorker.DataFetchComponents<>( new DataFetchWorker.DataFetchComponents<>(
this::getMimeTypeCategoriesModel, this::getMimeTypeCategoriesModel,
fileMimeTypesChart::showDataFetchResult), fileMimeTypesChart::showDataFetchResult),
// artifact counts worker
new DataFetchWorker.DataFetchComponents<>(
this::getArtifactCountsModel,
artifactTypesChart::showDataFetchResult),
// files by category worker // files by category worker
new DataFetchWorker.DataFetchComponents<>( new DataFetchWorker.DataFetchComponents<>(
this::getFileCategoryModel, this::getFileCategoryModel,
filesByCategoryTable::showDataFetchResult) filesByCategoryTable::showDataFetchResult)
); );
/**
* Main constructor.
*/
public TypesPanel() { public TypesPanel() {
initComponents(); initComponents();
customizeComponents();
}
private void customizeComponents() {
this.pieChartRow.setLayout(new WrapLayout(0,5));
} }
@Override @Override
@ -219,13 +222,19 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
} }
} }
/**
* Retrieves data for the file category table.
*
* @param selectedDataSource The datasource.
*
* @return The key value pairs to be displayed.
*/
private List<Pair<String, Long>> getFileCategoryModel(DataSource selectedDataSource) { private List<Pair<String, Long>> getFileCategoryModel(DataSource selectedDataSource) {
if (selectedDataSource == null) { if (selectedDataSource == null) {
return null; return null;
} }
List<Pair<String, Function<DataSource, Long>>> itemsAndRetrievers = Arrays.asList( List<Pair<String, Function<DataSource, Long>>> itemsAndRetrievers = Arrays.asList(Pair.of(Bundle.TypesPanel_filesByCategoryTable_allRow_title(), DataSourceCountsSummary::getCountOfFiles),
Pair.of(Bundle.TypesPanel_filesByCategoryTable_allRow_title(), DataSourceCountsSummary::getCountOfFiles),
Pair.of(Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), DataSourceCountsSummary::getCountOfAllocatedFiles), Pair.of(Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), DataSourceCountsSummary::getCountOfAllocatedFiles),
Pair.of(Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), DataSourceCountsSummary::getCountOfUnallocatedFiles), Pair.of(Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), DataSourceCountsSummary::getCountOfUnallocatedFiles),
Pair.of(Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), DataSourceCountsSummary::getCountOfSlackFiles), Pair.of(Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), DataSourceCountsSummary::getCountOfSlackFiles),
@ -241,17 +250,26 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Gets all the data for the file type pie chart.
*
* @param dataSource
*
* @return
*/
private List<PieChartItem> getMimeTypeCategoriesModel(DataSource dataSource) { private List<PieChartItem> getMimeTypeCategoriesModel(DataSource dataSource) {
if (dataSource == null) { if (dataSource == null) {
return null; return null;
} }
// for each category of file types, get the counts of files
Stream<Pair<String, Long>> fileCategoryItems = FILE_MIME_TYPE_CATEGORIES Stream<Pair<String, Long>> fileCategoryItems = FILE_MIME_TYPE_CATEGORIES
.stream() .stream()
.map((strCat) .map((strCat)
-> Pair.of(strCat.getLeft(), -> Pair.of(strCat.getLeft(),
DataSourceMimeTypeSummary.getCountOfFilesForMimeTypes(dataSource, strCat.getRight().getMediaTypes()))); DataSourceMimeTypeSummary.getCountOfFilesForMimeTypes(dataSource, strCat.getRight().getMediaTypes())));
// also get counts for other and not analayzed
Stream<Pair<String, Long>> otherItems = Stream.of( Stream<Pair<String, Long>> otherItems = Stream.of(
Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(), Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(),
DataSourceMimeTypeSummary.getCountOfFilesNotInMimeTypes(dataSource, CATEGORY_MIME_TYPES)), DataSourceMimeTypeSummary.getCountOfFilesNotInMimeTypes(dataSource, CATEGORY_MIME_TYPES)),
@ -259,35 +277,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
DataSourceMimeTypeSummary.getCountOfFilesWithNoMimeType(dataSource)) DataSourceMimeTypeSummary.getCountOfFilesWithNoMimeType(dataSource))
); );
// create pie chart items to provide to pie chart
return Stream.concat(fileCategoryItems, otherItems) return Stream.concat(fileCategoryItems, otherItems)
.filter(keyCount -> keyCount.getRight() != null && keyCount.getRight() > 0) .filter(keyCount -> keyCount.getRight() != null && keyCount.getRight() > 0)
.map(keyCount -> new PieChartItem(keyCount.getLeft(), keyCount.getRight())) .map(keyCount -> new PieChartItem(keyCount.getLeft(), keyCount.getRight()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* 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 List<PieChartItem> getArtifactCountsModel(DataSource selectedDataSource) {
Map<String, Long> artifactMapping = DataSourceCountsSummary.getCountsOfArtifactsByType(selectedDataSource);
if (artifactMapping == null) {
return null;
}
return artifactMapping.entrySet().stream()
.filter((entrySet) -> entrySet != null)
.sorted((a, b) -> a.getKey().compareTo(b.getKey()))
.map((entrySet) -> new PieChartItem(entrySet.getKey(), entrySet.getValue()))
.collect(Collectors.toList());
}
/** /**
* This method is called from within the constructor to initialize the form. * This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always * WARNING: Do NOT modify this code. The content of this method is always
@ -302,19 +298,19 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
javax.swing.JPanel usagePanel = usageLabel; javax.swing.JPanel usagePanel = usageLabel;
javax.swing.JPanel osPanel = osLabel; javax.swing.JPanel osPanel = osLabel;
javax.swing.JPanel sizePanel = sizeLabel; javax.swing.JPanel sizePanel = sizeLabel;
pieChartRow = new javax.swing.JPanel();
javax.swing.JPanel fileMimeTypesPanel = fileMimeTypesChart; javax.swing.JPanel fileMimeTypesPanel = fileMimeTypesChart;
javax.swing.JPanel artifactTypesPanel = artifactTypesChart;
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.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.JLabel filesByCategoryLabel = new javax.swing.JLabel(); javax.swing.JLabel filesByCategoryLabel = new javax.swing.JLabel();
javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2));
javax.swing.JPanel filesByCategoryPanel = filesByCategoryTable; javax.swing.JPanel filesByCategoryPanel = filesByCategoryTable;
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()); setLayout(new java.awt.BorderLayout());
contentParent.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); contentParent.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
contentParent.setMaximumSize(new java.awt.Dimension(32787, 32787)); contentParent.setMaximumSize(new java.awt.Dimension(32787, 32787));
contentParent.setMinimumSize(new java.awt.Dimension(650, 510)); contentParent.setMinimumSize(new java.awt.Dimension(400, 300));
contentParent.setPreferredSize(new java.awt.Dimension(400, 300));
contentParent.setLayout(new javax.swing.BoxLayout(contentParent, javax.swing.BoxLayout.PAGE_AXIS)); contentParent.setLayout(new javax.swing.BoxLayout(contentParent, javax.swing.BoxLayout.PAGE_AXIS));
usagePanel.setAlignmentX(0.0F); usagePanel.setAlignmentX(0.0F);
@ -336,24 +332,12 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
sizePanel.setPreferredSize(new java.awt.Dimension(800, 20)); sizePanel.setPreferredSize(new java.awt.Dimension(800, 20));
contentParent.add(sizePanel); contentParent.add(sizePanel);
pieChartRow.setAlignmentX(0.0F);
pieChartRow.setMaximumSize(new java.awt.Dimension(1170, 895));
pieChartRow.setMinimumSize(null);
pieChartRow.setPreferredSize(null);
fileMimeTypesPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5)); fileMimeTypesPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
fileMimeTypesPanel.setMaximumSize(new java.awt.Dimension(500, 375)); fileMimeTypesPanel.setAlignmentX(0.0F);
fileMimeTypesPanel.setMinimumSize(new java.awt.Dimension(500, 375)); fileMimeTypesPanel.setMaximumSize(new java.awt.Dimension(400, 300));
fileMimeTypesPanel.setPreferredSize(new java.awt.Dimension(500, 375)); fileMimeTypesPanel.setMinimumSize(new java.awt.Dimension(400, 300));
pieChartRow.add(fileMimeTypesPanel); fileMimeTypesPanel.setPreferredSize(new java.awt.Dimension(400, 300));
contentParent.add(fileMimeTypesPanel);
artifactTypesPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
artifactTypesPanel.setMaximumSize(new java.awt.Dimension(650, 500));
artifactTypesPanel.setMinimumSize(new java.awt.Dimension(650, 500));
artifactTypesPanel.setPreferredSize(new java.awt.Dimension(650, 500));
pieChartRow.add(artifactTypesPanel);
contentParent.add(pieChartRow);
contentParent.add(filler2); contentParent.add(filler2);
org.openide.awt.Mnemonics.setLocalizedText(filesByCategoryLabel, org.openide.util.NbBundle.getMessage(TypesPanel.class, "TypesPanel.filesByCategoryLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(filesByCategoryLabel, org.openide.util.NbBundle.getMessage(TypesPanel.class, "TypesPanel.filesByCategoryLabel.text")); // NOI18N
@ -365,6 +349,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
filesByCategoryPanel.setMinimumSize(new java.awt.Dimension(10, 107)); filesByCategoryPanel.setMinimumSize(new java.awt.Dimension(10, 107));
filesByCategoryPanel.setPreferredSize(new java.awt.Dimension(400, 107)); filesByCategoryPanel.setPreferredSize(new java.awt.Dimension(400, 107));
contentParent.add(filesByCategoryPanel); contentParent.add(filesByCategoryPanel);
contentParent.add(filler3);
scrollParent.setViewportView(contentParent); scrollParent.setViewportView(contentParent);
@ -373,6 +358,6 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel pieChartRow; private javax.swing.Box.Filler filler3;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -1,7 +1,20 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * Autopsy Forensic Browser
* To change this template file, choose Tools | Templates *
* and open the template in the editor. * 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; package org.sleuthkit.autopsy.datasourcesummary.uiutils;
@ -12,18 +25,27 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
* * Abstract class for common methods of a loadable component.
* @author gregd
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"AbstractLoadableComponent_loadingMessage_defaultText=Loading results...", "AbstractLoadableComponent_loadingMessage_defaultText=Loading results...",
"AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results.", "AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results.",
"AbstractLoadableComponent_noDataExists_defaultText=No data exists.", "AbstractLoadableComponent_noDataExists_defaultText=No data exists.",})
})
public abstract class AbstractLoadableComponent<T> extends JPanel implements LoadableComponent<T> { public abstract class AbstractLoadableComponent<T> extends JPanel implements LoadableComponent<T> {
/**
* The default loading message.
*/
public static final String DEFAULT_LOADING_MESSAGE = Bundle.AbstractLoadableComponent_loadingMessage_defaultText(); 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(); 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(); public static final String DEFAULT_NO_RESULTS_MESSAGE = Bundle.AbstractLoadableComponent_noDataExists_defaultText();
private static final Logger logger = Logger.getLogger(AbstractLoadableComponent.class.getName()); private static final Logger logger = Logger.getLogger(AbstractLoadableComponent.class.getName());

View File

@ -1,7 +1,20 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * Autopsy Forensic Browser
* To change this template file, choose Tools | Templates *
* and open the template in the editor. * 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; package org.sleuthkit.autopsy.datasourcesummary.uiutils;
@ -9,10 +22,11 @@ import java.awt.Graphics;
import javax.swing.JLabel; import javax.swing.JLabel;
/** /**
* * Base class for drawing a message overlay. Contains a paint method for
* @author gregd * painting a JLabel using a java.awt.Graphics object.
*/ */
public class BaseMessageOverlay { public class BaseMessageOverlay {
private final JLabel label; private final JLabel label;
private boolean visible = false; private boolean visible = false;
@ -54,6 +68,13 @@ public class BaseMessageOverlay {
message == null ? "" : message)); 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) { public void paintOverlay(Graphics g, int width, int height) {
if (!visible) { if (!visible) {
return; return;

View File

@ -242,7 +242,6 @@ public class JTablePanel<T> extends AbstractLoadableComponent<List<T>> {
return this; return this;
} }
@Override @Override
protected void setResults(List<T> data) { protected void setResults(List<T> data) {
// 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

View File

@ -25,8 +25,8 @@ import javax.swing.table.TableModel;
* An interface to be used with the JTablePanel that specifies a TableModel to * An interface to be used with the JTablePanel that specifies a TableModel to
* be used with the underlying JTable based on a list of object type T. * be used with the underlying JTable based on a list of object type T.
*/ */
public interface ListTableModel<T> extends TableModel { public interface ListTableModel<T> extends TableModel {
/** /**
* @return The list of objects supporting the rows to be displayed in the * @return The list of objects supporting the rows to be displayed in the
* table. * table.

View File

@ -1,13 +1,26 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * Autopsy Forensic Browser
* To change this template file, choose Tools | Templates *
* and open the template in the editor. * 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; package org.sleuthkit.autopsy.datasourcesummary.uiutils;
/** /**
* * Interface for a loadable component that can show messages, results, or a
* @author gregd * DataFetchResult.
*/ */
public interface LoadableComponent<T> { public interface LoadableComponent<T> {
@ -56,5 +69,5 @@ public interface LoadableComponent<T> {
* *
* @param result The DataFetchResult. * @param result The DataFetchResult.
*/ */
public void showDataFetchResult(DataFetchResult<T> result); void showDataFetchResult(DataFetchResult<T> result);
} }

View File

@ -1,7 +1,20 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * Autopsy Forensic Browser
* To change this template file, choose Tools | Templates *
* and open the template in the editor. * 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; package org.sleuthkit.autopsy.datasourcesummary.uiutils;
@ -22,32 +35,48 @@ import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset; import org.jfree.data.general.DefaultPieDataset;
/** /**
* * A pie chart panel.
* @author gregd
*/ */
public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.PieChartItem>> { public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.PieChartItem>> {
/** /**
* * An individual pie chart slice in the pie chart.
*/ */
public static class PieChartItem { public static class PieChartItem {
private final String label; private final String label;
private final double value; 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) { public PieChartItem(String label, double value) {
this.label = label; this.label = label;
this.value = value; this.value = value;
} }
/**
* @return The label for this item.
*/
public String getLabel() { public String getLabel() {
return label; return label;
} }
/**
* @return The value for this item.
*/
public double getValue() { public double getValue() {
return value; 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 class MessageOverlay extends AbstractOverlay implements Overlay {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -71,31 +100,38 @@ public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.
void setMessage(String message) { void setMessage(String message) {
overlay.setMessage(message); overlay.setMessage(message);
} }
@Override @Override
public void paintOverlay(Graphics2D gd, ChartPanel cp) { public void paintOverlay(Graphics2D gd, ChartPanel cp) {
overlay.paintOverlay(gd, cp.getWidth(), cp.getHeight()); overlay.paintOverlay(gd, cp.getWidth(), cp.getHeight());
} }
} }
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Font DEFAULT_FONT = new JLabel().getFont(); 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 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 = private static final PieSectionLabelGenerator DEFAULT_LABEL_GENERATOR
new StandardPieSectionLabelGenerator( = new StandardPieSectionLabelGenerator(
"{0}: {1} ({2})", new DecimalFormat("0"), new DecimalFormat("0.0%")); "{0}: {1} ({2})", new DecimalFormat("0"), new DecimalFormat("0.0%"));
private final MessageOverlay overlay = new MessageOverlay(); private final MessageOverlay overlay = new MessageOverlay();
private final DefaultPieDataset dataset = new DefaultPieDataset(); private final DefaultPieDataset dataset = new DefaultPieDataset();
private final JFreeChart chart; private final JFreeChart chart;
/**
* Main constructor.
*/
public PieChartPanel() { public PieChartPanel() {
this(null); this(null);
} }
/**
* Main constructor for the pie chart.
*
* @param title The title for this pie chart.
*/
public PieChartPanel(String title) { public PieChartPanel(String title) {
// Create chart // Create chart
this.chart = ChartFactory.createPieChart( this.chart = ChartFactory.createPieChart(
@ -109,6 +145,9 @@ public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.
chart.getLegend().setItemFont(DEFAULT_FONT); chart.getLegend().setItemFont(DEFAULT_FONT);
chart.getTitle().setFont(DEFAULT_HEADER_FONT); chart.getTitle().setFont(DEFAULT_HEADER_FONT);
// don't show a legend by default
chart.removeLegend();
PiePlot plot = ((PiePlot) chart.getPlot()); PiePlot plot = ((PiePlot) chart.getPlot());
plot.setLabelGenerator(DEFAULT_LABEL_GENERATOR); plot.setLabelGenerator(DEFAULT_LABEL_GENERATOR);
@ -123,18 +162,27 @@ public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.
this.add(panel, BorderLayout.CENTER); this.add(panel, BorderLayout.CENTER);
} }
/**
* @return The title for this chart if one exists.
*/
public String getTitle() { public String getTitle() {
return (this.chart == null || this.chart.getTitle() == null) ? return (this.chart == null || this.chart.getTitle() == null)
null : ? null
this.chart.getTitle().getText(); : 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) { public PieChartPanel setTitle(String title) {
this.chart.getTitle().setText(title); this.chart.getTitle().setText(title);
return this; return this;
} }
@Override @Override
protected void setMessage(boolean visible, String message) { protected void setMessage(boolean visible, String message) {
this.overlay.setVisible(visible); this.overlay.setVisible(visible);