mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 19:14:55 +00:00
working through charts
This commit is contained in:
parent
fa66011ec1
commit
189580df63
@ -128,6 +128,7 @@ TypesPanel_fileMimeTypesChart_notAnalyzed_title=Not Analyzed
|
|||||||
TypesPanel_fileMimeTypesChart_other_title=Other
|
TypesPanel_fileMimeTypesChart_other_title=Other
|
||||||
TypesPanel_fileMimeTypesChart_title=File Types
|
TypesPanel_fileMimeTypesChart_title=File Types
|
||||||
TypesPanel_fileMimeTypesChart_unknown_title=Unknown
|
TypesPanel_fileMimeTypesChart_unknown_title=Unknown
|
||||||
|
TypesPanel_fileMimeTypesChart_valueLabel=Count
|
||||||
TypesPanel_fileMimeTypesChart_videos_title=Videos
|
TypesPanel_fileMimeTypesChart_videos_title=Videos
|
||||||
TypesPanel_filesByCategoryTable_allocatedRow_title=Allocated Files
|
TypesPanel_filesByCategoryTable_allocatedRow_title=Allocated Files
|
||||||
TypesPanel_filesByCategoryTable_directoryRow_title=Directories
|
TypesPanel_filesByCategoryTable_directoryRow_title=Directories
|
||||||
|
@ -40,9 +40,9 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary;
|
|||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData;
|
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.BarChartItem;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.BarChartSeries;
|
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||||
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;
|
||||||
|
@ -65,6 +65,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
"TypesPanel_filesByCategoryTable_slackRow_title=Slack Files",
|
"TypesPanel_filesByCategoryTable_slackRow_title=Slack Files",
|
||||||
"TypesPanel_filesByCategoryTable_directoryRow_title=Directories",
|
"TypesPanel_filesByCategoryTable_directoryRow_title=Directories",
|
||||||
"TypesPanel_fileMimeTypesChart_title=File Types",
|
"TypesPanel_fileMimeTypesChart_title=File Types",
|
||||||
|
"TypesPanel_fileMimeTypesChart_valueLabel=Count",
|
||||||
"TypesPanel_fileMimeTypesChart_audio_title=Audio",
|
"TypesPanel_fileMimeTypesChart_audio_title=Audio",
|
||||||
"TypesPanel_fileMimeTypesChart_documents_title=Documents",
|
"TypesPanel_fileMimeTypesChart_documents_title=Documents",
|
||||||
"TypesPanel_fileMimeTypesChart_executables_title=Executables",
|
"TypesPanel_fileMimeTypesChart_executables_title=Executables",
|
||||||
@ -198,6 +199,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
private final DataFetcher<DataSource, String> osFetcher;
|
private final DataFetcher<DataSource, String> osFetcher;
|
||||||
private final DataFetcher<DataSource, Long> sizeFetcher;
|
private final DataFetcher<DataSource, Long> sizeFetcher;
|
||||||
|
|
||||||
|
private final DataFetcher<DataSource, TypesPieChartData> typesFetcher;
|
||||||
|
|
||||||
private final DataFetcher<DataSource, Long> allocatedFetcher;
|
private final DataFetcher<DataSource, Long> allocatedFetcher;
|
||||||
private final DataFetcher<DataSource, Long> unallocatedFetcher;
|
private final DataFetcher<DataSource, Long> unallocatedFetcher;
|
||||||
private final DataFetcher<DataSource, Long> slackFetcher;
|
private final DataFetcher<DataSource, Long> slackFetcher;
|
||||||
@ -263,6 +266,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
|
|
||||||
this.sizeFetcher = (dataSource) -> dataSource == null ? null : dataSource.getSize();
|
this.sizeFetcher = (dataSource) -> dataSource == null ? null : dataSource.getSize();
|
||||||
|
|
||||||
|
this.typesFetcher = (dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource);
|
||||||
|
|
||||||
this.allocatedFetcher = (dataSource) -> typeData.getCountOfAllocatedFiles(dataSource);
|
this.allocatedFetcher = (dataSource) -> typeData.getCountOfAllocatedFiles(dataSource);
|
||||||
this.unallocatedFetcher = (dataSource) -> typeData.getCountOfUnallocatedFiles(dataSource);
|
this.unallocatedFetcher = (dataSource) -> typeData.getCountOfUnallocatedFiles(dataSource);
|
||||||
this.slackFetcher = (dataSource) -> typeData.getCountOfSlackFiles(dataSource);
|
this.slackFetcher = (dataSource) -> typeData.getCountOfSlackFiles(dataSource);
|
||||||
@ -275,9 +280,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
(sizeResult) -> sizeLabel.showDataFetchResult(
|
(sizeResult) -> sizeLabel.showDataFetchResult(
|
||||||
DataFetchResult.getSubResult(sizeResult,
|
DataFetchResult.getSubResult(sizeResult,
|
||||||
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
|
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
|
||||||
new DataFetchWorker.DataFetchComponents<>(
|
new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories),
|
||||||
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
|
|
||||||
this::showMimeTypeCategories),
|
|
||||||
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
|
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
|
||||||
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||||
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
|
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
|
||||||
@ -444,16 +447,22 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypesPieChartData typesData = this.getFetchResult(typesFetcher, "Types", dataSource);
|
||||||
|
PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null :
|
||||||
|
new PieChartExport(
|
||||||
|
Bundle.TypesPanel_fileMimeTypesChart_title(),
|
||||||
|
Bundle.TypesPanel_fileMimeTypesChart_valueLabel(),
|
||||||
|
"#,###",
|
||||||
|
Bundle.TypesPanel_fileMimeTypesChart_title(),
|
||||||
|
typesData.getPieSlices());
|
||||||
|
|
||||||
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.TypesPanel_excelTabName(),
|
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.TypesPanel_excelTabName(),
|
||||||
Stream.of(
|
Stream.of(
|
||||||
getStrExportable(usageFetcher, Bundle.TypesPanel_usageLabel_title(), dataSource),
|
getStrExportable(usageFetcher, Bundle.TypesPanel_usageLabel_title(), dataSource),
|
||||||
getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource),
|
getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource),
|
||||||
new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(),
|
new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(),
|
||||||
SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))),
|
SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))),
|
||||||
new PieChartExport(String keyColumnHeader,
|
typesChart,
|
||||||
String valueColumnHeader, String valueFormatString,
|
|
||||||
String chartTitle,
|
|
||||||
List<PieChartItem> slices),
|
|
||||||
getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource),
|
getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource),
|
||||||
getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), dataSource),
|
getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), dataSource),
|
||||||
getCountExportable(slackFetcher, Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), dataSource),
|
getCountExportable(slackFetcher, Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), dataSource),
|
||||||
|
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||||
|
|
||||||
|
import com.google.cloud.Tuple;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
import org.apache.poi.xddf.usermodel.XDDFColor;
|
||||||
|
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
|
||||||
|
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.BarDirection;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.BarGrouping;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFChart;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ItemDimensions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author gregd
|
||||||
|
*/
|
||||||
|
public class BarChartExport implements ExcelItemExportable, ExcelSheetExport {
|
||||||
|
private final ExcelTableExport<BarChartSeries, ? extends ExcelCellModel> tableExport;
|
||||||
|
private final int colOffset;
|
||||||
|
private final int rowPadding;
|
||||||
|
private final int colSize;
|
||||||
|
private final int rowSize;
|
||||||
|
private final String chartTitle;
|
||||||
|
private final String sheetName;
|
||||||
|
private final List<BarChartSeries> categories;
|
||||||
|
private final String keyColumnHeader;
|
||||||
|
|
||||||
|
public BarChartExport(String keyColumnHeader,
|
||||||
|
String valueFormatString,
|
||||||
|
String chartTitle,
|
||||||
|
List<BarChartSeries> categories) {
|
||||||
|
this(keyColumnHeader, valueFormatString, chartTitle, chartTitle, categories, 1, 1, 8, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BarChartExport(String keyColumnHeader, String valueFormatString,
|
||||||
|
String chartTitle, String sheetName,
|
||||||
|
List<BarChartSeries> categories,
|
||||||
|
int colOffset, int rowPadding, int colSize, int rowSize) {
|
||||||
|
|
||||||
|
this.keyColumnHeader = keyColumnHeader;
|
||||||
|
|
||||||
|
List<BarChartSeries> categoryKeys = categories.stream()
|
||||||
|
.filter(cat -> cat != null && cat.getKey() != null)
|
||||||
|
.sorted((c1, c2) -> c1.getKey().compareTo(c2.getKey()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<Comparable<?>> rowKeys = categories.stream()
|
||||||
|
.filter(cat -> cat != null && cat.getItems() != null)
|
||||||
|
.flatMap(cat -> cat.getItems().stream().map(item -> item.getKey()))
|
||||||
|
.filter(i -> i != null)
|
||||||
|
.distinct()
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<Tuple<Comparable<?>, Comparable<?>>, Double> valueMap = categories.stream()
|
||||||
|
.flatMap((cat) -> cat.getItems().stream().map((item) -> Tuple.of(Tuple.of(cat.getKey(), item.getKey()), item.getValue())))
|
||||||
|
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (v1, v2) -> v1));
|
||||||
|
|
||||||
|
List<Pair<Comparable<?>, List<Double>>> values = rowKeys.stream()
|
||||||
|
.map((rowValue))
|
||||||
|
|
||||||
|
this.tableExport = new ExcelTableExport<>(chartTitle,
|
||||||
|
Stream.concat(Stream.of(new ColumnModel<>(keyColumnHeader, (category) -> new DefaultCellModel<>(category.getLabel()))), )
|
||||||
|
Arrays.asList(
|
||||||
|
,
|
||||||
|
new ColumnModel<>(valueColumnHeader, (category) -> new DefaultCellModel<>(category.getValue(), null, valueFormatString))
|
||||||
|
),
|
||||||
|
categories);
|
||||||
|
this.colOffset = colOffset;
|
||||||
|
this.rowPadding = rowPadding;
|
||||||
|
this.colSize = colSize;
|
||||||
|
this.rowSize = rowSize;
|
||||||
|
this.chartTitle = chartTitle;
|
||||||
|
this.sheetName = sheetName;
|
||||||
|
this.categories = categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return sheetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderSheet(Sheet sheet, ExcelExport.WorksheetEnv env) throws ExcelExport.ExcelExportException {
|
||||||
|
write(sheet, 0, 0, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
|
||||||
|
if (!(sheet instanceof XSSFSheet)) {
|
||||||
|
throw new ExcelExportException("Sheet must be an XSSFSheet in order to write.");
|
||||||
|
}
|
||||||
|
|
||||||
|
XSSFSheet xssfSheet = (XSSFSheet) sheet;
|
||||||
|
|
||||||
|
// write pie chart table data
|
||||||
|
ItemDimensions tableDimensions = tableExport.write(xssfSheet, rowStart + rowPadding, colStart, env);
|
||||||
|
|
||||||
|
XSSFDrawing drawing = xssfSheet.createDrawingPatriarch();
|
||||||
|
|
||||||
|
int chartColStart = colStart + 2 + colOffset;
|
||||||
|
|
||||||
|
//createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2);
|
||||||
|
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, chartColStart, rowStart + rowPadding, chartColStart + colSize, rowStart + rowSize);
|
||||||
|
|
||||||
|
XSSFChart chart = drawing.createChart(anchor);
|
||||||
|
chart.setTitleText(chartTitle);
|
||||||
|
chart.setTitleOverlay(false);
|
||||||
|
XDDFChartLegend legend = chart.getOrAddLegend();
|
||||||
|
legend.setPosition(LegendPosition.BOTTOM);
|
||||||
|
|
||||||
|
|
||||||
|
// Use a category axis for the bottom axis.
|
||||||
|
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
|
||||||
|
bottomAxis.setTitle(keyColumnHeader);
|
||||||
|
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
|
||||||
|
// leftAxis.setTitle(valHeader);
|
||||||
|
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
|
||||||
|
leftAxis.setVisible(false);
|
||||||
|
|
||||||
|
XDDFBarChartData data = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
|
||||||
|
data.setBarGrouping(BarGrouping.STACKED);
|
||||||
|
|
||||||
|
XDDFDataSource<String> headerSource = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(1, keyVals.size(), 0, 0));
|
||||||
|
data.setBarDirection(BarDirection.COL);
|
||||||
|
|
||||||
|
for (int i = 0; i < categories.size(); i++) {
|
||||||
|
XDDFChartData.Series series = data.addSeries(headerSource,
|
||||||
|
XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, keyVals.size(), i + 1, i + 1)));
|
||||||
|
series.setTitle(categories.size() > i && categories.get(i).getIdentifier() != null ? categories.get(i).getIdentifier() : "", null);
|
||||||
|
if (categories.get(i).getColor() != null) {
|
||||||
|
Color color = categories.get(i).getColor();
|
||||||
|
byte[] colorArrARGB = ByteBuffer.allocate(4).putInt(color.getRGB()).array();
|
||||||
|
byte[] colorArrRGB = new byte[]{colorArrARGB[1], colorArrARGB[2], colorArrARGB[3]};
|
||||||
|
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(colorArrRGB)); // XDDFColor.from(color.getRed(), color.getGreen(), color.getBlue()));
|
||||||
|
XDDFShapeProperties properties = series.getShapeProperties();
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new XDDFShapeProperties();
|
||||||
|
}
|
||||||
|
properties.setFillProperties(fill);
|
||||||
|
series.setShapeProperties(properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.plot(data);
|
||||||
|
|
||||||
|
return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -19,9 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
@ -34,90 +32,13 @@ import org.jfree.chart.plot.PlotOrientation;
|
|||||||
import org.jfree.chart.renderer.category.BarRenderer;
|
import org.jfree.chart.renderer.category.BarRenderer;
|
||||||
import org.jfree.chart.renderer.category.StandardBarPainter;
|
import org.jfree.chart.renderer.category.StandardBarPainter;
|
||||||
import org.jfree.data.category.DefaultCategoryDataset;
|
import org.jfree.data.category.DefaultCategoryDataset;
|
||||||
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bar chart panel.
|
* A bar chart panel.
|
||||||
*/
|
*/
|
||||||
public class BarChartPanel extends AbstractLoadableComponent<List<BarChartPanel.BarChartSeries>> {
|
public class BarChartPanel extends AbstractLoadableComponent<List<BarChartSeries>> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a series in a bar chart where all items pertain to one
|
|
||||||
* category.
|
|
||||||
*/
|
|
||||||
public static class BarChartSeries {
|
|
||||||
|
|
||||||
private final Comparable<?> key;
|
|
||||||
private final Color color;
|
|
||||||
private final List<BarChartItem> items;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main constructor.
|
|
||||||
*
|
|
||||||
* @param key The key.
|
|
||||||
* @param color The color for this series.
|
|
||||||
* @param items The bars to be displayed for this series.
|
|
||||||
*/
|
|
||||||
public BarChartSeries(Comparable<?> key, Color color, List<BarChartItem> items) {
|
|
||||||
this.key = key;
|
|
||||||
this.color = color;
|
|
||||||
this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The color for this series.
|
|
||||||
*/
|
|
||||||
public Color getColor() {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The bars to be displayed for this series.
|
|
||||||
*/
|
|
||||||
public List<BarChartItem> getItems() {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The key for this item.
|
|
||||||
*/
|
|
||||||
public Comparable<?> getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An individual bar to be displayed in the bar chart.
|
|
||||||
*/
|
|
||||||
public static class BarChartItem {
|
|
||||||
|
|
||||||
private final Comparable<?> key;
|
|
||||||
private final double value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main constructor.
|
|
||||||
*
|
|
||||||
* @param key The key.
|
|
||||||
* @param value The value for this item.
|
|
||||||
*/
|
|
||||||
public BarChartItem(Comparable<?> key, double value) {
|
|
||||||
this.key = key;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The key for this item.
|
|
||||||
*/
|
|
||||||
public Comparable<?> getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The value for this item.
|
|
||||||
*/
|
|
||||||
public double getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JFreeChart bar charts don't preserve the order of bars provided to the
|
* JFreeChart bar charts don't preserve the order of bars provided to the
|
||||||
@ -285,12 +206,12 @@ public class BarChartPanel extends AbstractLoadableComponent<List<BarChartPanel.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setResults(List<BarChartPanel.BarChartSeries> data) {
|
protected void setResults(List<BarChartSeries> data) {
|
||||||
this.dataset.clear();
|
this.dataset.clear();
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(data)) {
|
if (CollectionUtils.isNotEmpty(data)) {
|
||||||
for (int s = 0; s < data.size(); s++) {
|
for (int s = 0; s < data.size(); s++) {
|
||||||
BarChartPanel.BarChartSeries series = data.get(s);
|
BarChartSeries series = data.get(s);
|
||||||
if (series != null && CollectionUtils.isNotEmpty(series.getItems())) {
|
if (series != null && CollectionUtils.isNotEmpty(series.getItems())) {
|
||||||
if (series.getColor() != null) {
|
if (series.getColor() != null) {
|
||||||
this.plot.getRenderer().setSeriesPaint(s, series.getColor());
|
this.plot.getRenderer().setSeriesPaint(s, series.getColor());
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.uiutils;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a series in a bar chart where all items pertain to one
|
||||||
|
* category.
|
||||||
|
*/
|
||||||
|
public class BarChartSeries {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An individual bar to be displayed in the bar chart.
|
||||||
|
*/
|
||||||
|
public static class BarChartItem {
|
||||||
|
|
||||||
|
private final Comparable<?> key;
|
||||||
|
private final double value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param key The key.
|
||||||
|
* @param value The value for this item.
|
||||||
|
*/
|
||||||
|
public BarChartItem(Comparable<?> key, double value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The key for this item.
|
||||||
|
*/
|
||||||
|
public Comparable<?> getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The value for this item.
|
||||||
|
*/
|
||||||
|
public double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private final Comparable<?> key;
|
||||||
|
private final Color color;
|
||||||
|
private final List<BarChartItem> items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param key The key.
|
||||||
|
* @param color The color for this series.
|
||||||
|
* @param items The bars to be displayed for this series.
|
||||||
|
*/
|
||||||
|
public BarChartSeries(Comparable<?> key, Color color, List<BarChartItem> items) {
|
||||||
|
this.key = key;
|
||||||
|
this.color = color;
|
||||||
|
this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The color for this series.
|
||||||
|
*/
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The bars to be displayed for this series.
|
||||||
|
*/
|
||||||
|
public List<BarChartItem> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The key for this item.
|
||||||
|
*/
|
||||||
|
public Comparable<?> getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -81,6 +81,8 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelSheet
|
|||||||
sheet.autoSizeColumn(i);
|
sheet.autoSizeColumn(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// freeze header row
|
||||||
|
sheet.createFreezePane(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -119,8 +121,7 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelSheet
|
|||||||
cell.setCellValue(columns.get(i).getHeaderTitle());
|
cell.setCellValue(columns.get(i).getHeaderTitle());
|
||||||
cell.setCellStyle(worksheetEnv.getHeaderStyle());
|
cell.setCellStyle(worksheetEnv.getHeaderStyle());
|
||||||
}
|
}
|
||||||
// freeze header row
|
|
||||||
sheet.createFreezePane(0, 1);
|
|
||||||
// Create Cell Style for each column (if one is needed)
|
// Create Cell Style for each column (if one is needed)
|
||||||
|
|
||||||
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {
|
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {
|
||||||
|
@ -9,11 +9,16 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
|
||||||
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
|
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
|
||||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
||||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
|
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
|
||||||
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
|
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
|
||||||
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
|
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFChart;
|
import org.apache.poi.xssf.usermodel.XSSFChart;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||||
@ -28,6 +33,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.
|
|||||||
* @author gregd
|
* @author gregd
|
||||||
*/
|
*/
|
||||||
public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
||||||
|
|
||||||
private final ExcelTableExport<PieChartItem, ? extends ExcelCellModel> tableExport;
|
private final ExcelTableExport<PieChartItem, ? extends ExcelCellModel> tableExport;
|
||||||
private final int colOffset;
|
private final int colOffset;
|
||||||
private final int rowPadding;
|
private final int rowPadding;
|
||||||
@ -35,13 +41,12 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
|||||||
private final int rowSize;
|
private final int rowSize;
|
||||||
private final String chartTitle;
|
private final String chartTitle;
|
||||||
private final String sheetName;
|
private final String sheetName;
|
||||||
private final List<PieChartItem> slices;
|
|
||||||
|
|
||||||
public PieChartExport(String keyColumnHeader,
|
public PieChartExport(String keyColumnHeader,
|
||||||
String valueColumnHeader, String valueFormatString,
|
String valueColumnHeader, String valueFormatString,
|
||||||
String chartTitle,
|
String chartTitle,
|
||||||
List<PieChartItem> slices) {
|
List<PieChartItem> slices) {
|
||||||
this(keyColumnHeader, valueColumnHeader, valueFormatString, chartTitle, chartTitle, slices, 1, 1, 8, 10);
|
this(keyColumnHeader, valueColumnHeader, valueFormatString, chartTitle, chartTitle, slices, 1, 1, 8, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PieChartExport(String keyColumnHeader,
|
public PieChartExport(String keyColumnHeader,
|
||||||
@ -62,11 +67,8 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
|||||||
this.rowSize = rowSize;
|
this.rowSize = rowSize;
|
||||||
this.chartTitle = chartTitle;
|
this.chartTitle = chartTitle;
|
||||||
this.sheetName = sheetName;
|
this.sheetName = sheetName;
|
||||||
this.slices = slices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSheetName() {
|
public String getSheetName() {
|
||||||
return sheetName;
|
return sheetName;
|
||||||
@ -98,19 +100,23 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
|||||||
XSSFChart chart = drawing.createChart(anchor);
|
XSSFChart chart = drawing.createChart(anchor);
|
||||||
chart.setTitleText(chartTitle);
|
chart.setTitleText(chartTitle);
|
||||||
chart.setTitleOverlay(false);
|
chart.setTitleOverlay(false);
|
||||||
// XDDFChartLegend legend = chart.getOrAddLegend();
|
XDDFChartLegend legend = chart.getOrAddLegend();
|
||||||
// legend.setPosition(LegendPosition.BOTTOM);
|
legend.setPosition(LegendPosition.RIGHT);
|
||||||
|
|
||||||
// (int firstRow, int lastRow, int firstCol, int lastCol)
|
// (int firstRow, int lastRow, int firstCol, int lastCol)
|
||||||
XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromStringCellRange(xssfSheet,
|
XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromStringCellRange(xssfSheet,
|
||||||
new CellRangeAddress(tableDimensions.getRowStart(), tableDimensions.getRowEnd(),
|
new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
|
||||||
tableDimensions.getColStart(), tableDimensions.getColStart()));
|
tableDimensions.getColStart(), tableDimensions.getColStart()));
|
||||||
|
|
||||||
XDDFNumericalDataSource<Double> val = XDDFDataSourcesFactory.fromNumericCellRange(xssfSheet,
|
XDDFNumericalDataSource<Double> val = XDDFDataSourcesFactory.fromNumericCellRange(xssfSheet,
|
||||||
new CellRangeAddress(tableDimensions.getRowStart(), tableDimensions.getRowEnd(),
|
new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
|
||||||
tableDimensions.getColStart() + 1, tableDimensions.getColStart() + 1));
|
tableDimensions.getColStart() + 1, tableDimensions.getColStart() + 1));
|
||||||
|
|
||||||
XDDFPieChartData data = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null);
|
// NOTE: these can be null parameters to chart.createData in poi >= 4.1.1
|
||||||
|
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
|
||||||
|
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
|
||||||
|
|
||||||
|
XDDFPieChartData data = (XDDFPieChartData) chart.createData(ChartTypes.PIE, bottomAxis, leftAxis);
|
||||||
|
|
||||||
data.setVaryColors(true);
|
data.setVaryColors(true);
|
||||||
data.addSeries(cat, val);
|
data.addSeries(cat, val);
|
||||||
@ -124,13 +130,11 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
|||||||
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false);
|
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false);
|
||||||
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(true);
|
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(true);
|
||||||
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(true);
|
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(true);
|
||||||
//chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
|
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
|
||||||
|
|
||||||
chart.plot(data);
|
chart.plot(data);
|
||||||
|
|
||||||
return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
|
return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user