revisions to pie chart

This commit is contained in:
Greg DiCristofaro 2020-09-16 13:29:19 -04:00
parent 182b1d3f71
commit 4fa32b5ad3
2 changed files with 120 additions and 13 deletions

View File

@ -23,22 +23,25 @@ import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
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.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.AbstractLoadableComponent;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
@ -115,11 +118,47 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
}
}
/**
* Data for types pie chart.
*/
private static class TypesPieChartData {
private final List<PieChartItem> pieSlices;
private final boolean usefulContent;
/**
* Main constructor.
*
* @param pieSlices The pie slices.
* @param usefulContent True if this is useful content; false if there
* is 0 mime type information.
*/
public TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
this.pieSlices = pieSlices;
this.usefulContent = usefulContent;
}
/**
* @return The pie chart data.
*/
public List<PieChartItem> getPieSlices() {
return pieSlices;
}
/**
* @return Whether or not the data is usefulContent.
*/
public boolean isUsefulContent() {
return usefulContent;
}
}
private static final long serialVersionUID = 1L;
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat("#,###");
private static final String FILE_TYPE_FACTORY = FileTypeIdModuleFactory.class.getCanonicalName();
private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName();
private static final Logger logger = Logger.getLogger(TypesPanel.class.getName());
// All file type categories.
private static final List<Pair<String, Set<String>>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
@ -219,7 +258,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
// file types worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
(result) -> showResultWithModuleCheck(fileMimeTypesChart, result, FILE_TYPE_FACTORY, FILE_TYPE_MODULE_NAME)),
this::showMimeTypeCategories),
// allocated files worker
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getStringOrZero(typeData.getCountOfAllocatedFiles(dataSource)),
@ -258,11 +297,11 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
*
* @return The pie chart items.
*/
private List<PieChartItem> getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource)
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource)
throws SQLException, SleuthkitCaseProviderException, TskCoreException {
if (dataSource == null) {
return Collections.emptyList();
return null;
}
// for each category of file types, get the counts of files
@ -287,20 +326,73 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(),
allRegularFiles - (categoryTotalCount + noMimeTypeCount)));
// check at this point to see if these are all 0, if so we don't have results; return empty list
if (!fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0)) {
return Collections.emptyList();
}
// check at this point to see if these are all 0; if so, we don't have useful content.
boolean usefulContent = fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0);
// 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()
List<PieChartItem> items = fileCategoryItems.stream()
.filter(keyCount -> keyCount.getRight() != null && keyCount.getRight() > 0)
.map(keyCount -> new PieChartItem(keyCount.getLeft(), keyCount.getRight()))
.collect(Collectors.toList());
return new TypesPieChartData(items, usefulContent);
}
/**
* Handles properly showing data for the mime type categories pie chart
* accounting for whether there are any files with mime types specified and
* whether or not the current data source has been ingested with the file
* type ingest module.
*
* @param result The result to be shown.
*/
private void showMimeTypeCategories(DataFetchResult<TypesPieChartData> result) {
// if result is null check for ingest module and show empty results.
if (result == null) {
showPieResultWithModuleCheck(null);
return;
}
// if error, show error
if (result.getResultType() == ResultType.ERROR) {
this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getErrorResult(result.getException()));
return;
}
// if no useful data, do an ingest module check and show data.
TypesPieChartData data = result.getData();
if (data == null || !data.isUsefulContent()) {
showPieResultWithModuleCheck(data.getPieSlices());
return;
}
this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getSuccessResult(data.getPieSlices()));
}
/**
* Shows a message in the fileMimeTypesChart about the data source not being
* ingested with the file type ingest module if the data source has not been
* ingested with that module. Also shows data if present.
*
* @param items The list of items to show.
*/
private void showPieResultWithModuleCheck(List<PieChartItem> items) {
boolean hasBeenIngested = false;
try {
hasBeenIngested = this.getIngestModuleCheckUtil().isModuleIngested(getDataSource(), FILE_TYPE_FACTORY);
} catch (TskCoreException | SleuthkitCaseProviderException ex) {
logger.log(Level.WARNING, "There was an error fetching whether or not the current data source has been ingested with the file type ingest module.", ex);
}
if (hasBeenIngested) {
this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getSuccessResult(items));
} else {
this.fileMimeTypesChart.showDataWithMessage(items, getDefaultNoIngestMessage(FILE_TYPE_MODULE_NAME));
}
}
/**

View File

@ -33,10 +33,14 @@ import org.jfree.chart.panel.AbstractOverlay;
import org.jfree.chart.panel.Overlay;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.openide.util.NbBundle.Messages;
/**
* A pie chart panel.
*/
@Messages({
"PieChartPanel_noDataLabel=No Data"
})
public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.PieChartItem>> {
/**
@ -192,14 +196,25 @@ public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.
@Override
protected void setResults(List<PieChartPanel.PieChartItem> data) {
this.dataset.clear();
if (data != null) {
if (data != null && !data.isEmpty()) {
for (PieChartPanel.PieChartItem slice : data) {
this.dataset.setValue(slice.getLabel(), slice.getValue());
}
} else {
// show a no data label if no data.
this.dataset.setValue(Bundle.PieChartPanel_noDataLabel(), 0);
}
}
public void showMessageWithData(String message, List<PieChartPanel.PieChartItem> data) {
/**
* Shows a message on top of data.
*
* @param data The data.
* @param message The message.
*/
public synchronized void showDataWithMessage(List<PieChartPanel.PieChartItem> data, String message) {
setResults(data);
setMessage(true, message);
repaint();
}
}