mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
revisions to pie chart
This commit is contained in:
parent
182b1d3f71
commit
4fa32b5ad3
@ -23,22 +23,25 @@ import java.sql.SQLException;
|
|||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
|
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.TypesSummary;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.AbstractLoadableComponent;
|
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;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
|
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 long serialVersionUID = 1L;
|
||||||
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
|
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
|
||||||
private static final DecimalFormat COMMA_FORMATTER = 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_FACTORY = FileTypeIdModuleFactory.class.getCanonicalName();
|
||||||
private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName();
|
private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName();
|
||||||
|
private static final Logger logger = Logger.getLogger(TypesPanel.class.getName());
|
||||||
|
|
||||||
// All file type categories.
|
// All file type categories.
|
||||||
private static final List<Pair<String, Set<String>>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
|
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
|
// file types worker
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
new DataFetchWorker.DataFetchComponents<>(
|
||||||
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
|
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
|
||||||
(result) -> showResultWithModuleCheck(fileMimeTypesChart, result, FILE_TYPE_FACTORY, FILE_TYPE_MODULE_NAME)),
|
this::showMimeTypeCategories),
|
||||||
// allocated files worker
|
// allocated files worker
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
new DataFetchWorker.DataFetchComponents<>(
|
||||||
(dataSource) -> getStringOrZero(typeData.getCountOfAllocatedFiles(dataSource)),
|
(dataSource) -> getStringOrZero(typeData.getCountOfAllocatedFiles(dataSource)),
|
||||||
@ -258,11 +297,11 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
*
|
*
|
||||||
* @return The pie chart items.
|
* @return The pie chart items.
|
||||||
*/
|
*/
|
||||||
private List<PieChartItem> getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource)
|
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource)
|
||||||
throws SQLException, SleuthkitCaseProviderException, TskCoreException {
|
throws SQLException, SleuthkitCaseProviderException, TskCoreException {
|
||||||
|
|
||||||
if (dataSource == null) {
|
if (dataSource == null) {
|
||||||
return Collections.emptyList();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each category of file types, get the counts of files
|
// 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(),
|
fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(),
|
||||||
allRegularFiles - (categoryTotalCount + noMimeTypeCount)));
|
allRegularFiles - (categoryTotalCount + noMimeTypeCount)));
|
||||||
|
|
||||||
// check at this point to see if these are all 0, if so we don't have results; return empty list
|
// check at this point to see if these are all 0; if so, we don't have useful content.
|
||||||
if (!fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0)) {
|
boolean usefulContent = fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0);
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// create entry for not analyzed mime types category
|
// create entry for not analyzed mime types category
|
||||||
fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_notAnalyzed_title(),
|
fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_notAnalyzed_title(),
|
||||||
noMimeTypeCount));
|
noMimeTypeCount));
|
||||||
|
|
||||||
// create pie chart items to provide to pie chart
|
// 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)
|
.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());
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,10 +33,14 @@ import org.jfree.chart.panel.AbstractOverlay;
|
|||||||
import org.jfree.chart.panel.Overlay;
|
import org.jfree.chart.panel.Overlay;
|
||||||
import org.jfree.chart.plot.PiePlot;
|
import org.jfree.chart.plot.PiePlot;
|
||||||
import org.jfree.data.general.DefaultPieDataset;
|
import org.jfree.data.general.DefaultPieDataset;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pie chart panel.
|
* A pie chart panel.
|
||||||
*/
|
*/
|
||||||
|
@Messages({
|
||||||
|
"PieChartPanel_noDataLabel=No Data"
|
||||||
|
})
|
||||||
public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.PieChartItem>> {
|
public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.PieChartItem>> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,14 +196,25 @@ public class PieChartPanel extends AbstractLoadableComponent<List<PieChartPanel.
|
|||||||
@Override
|
@Override
|
||||||
protected void setResults(List<PieChartPanel.PieChartItem> data) {
|
protected void setResults(List<PieChartPanel.PieChartItem> data) {
|
||||||
this.dataset.clear();
|
this.dataset.clear();
|
||||||
if (data != null) {
|
if (data != null && !data.isEmpty()) {
|
||||||
for (PieChartPanel.PieChartItem slice : data) {
|
for (PieChartPanel.PieChartItem slice : data) {
|
||||||
this.dataset.setValue(slice.getLabel(), slice.getValue());
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user