mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +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_title=File Types
|
||||
TypesPanel_fileMimeTypesChart_unknown_title=Unknown
|
||||
TypesPanel_fileMimeTypesChart_valueLabel=Count
|
||||
TypesPanel_fileMimeTypesChart_videos_title=Videos
|
||||
TypesPanel_filesByCategoryTable_allocatedRow_title=Allocated Files
|
||||
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.TimelineSummaryData;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.BarChartItem;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.BarChartSeries;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries;
|
||||
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.DataFetchWorker;
|
||||
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_directoryRow_title=Directories",
|
||||
"TypesPanel_fileMimeTypesChart_title=File Types",
|
||||
"TypesPanel_fileMimeTypesChart_valueLabel=Count",
|
||||
"TypesPanel_fileMimeTypesChart_audio_title=Audio",
|
||||
"TypesPanel_fileMimeTypesChart_documents_title=Documents",
|
||||
"TypesPanel_fileMimeTypesChart_executables_title=Executables",
|
||||
@ -198,6 +199,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
private final DataFetcher<DataSource, String> osFetcher;
|
||||
private final DataFetcher<DataSource, Long> sizeFetcher;
|
||||
|
||||
private final DataFetcher<DataSource, TypesPieChartData> typesFetcher;
|
||||
|
||||
private final DataFetcher<DataSource, Long> allocatedFetcher;
|
||||
private final DataFetcher<DataSource, Long> unallocatedFetcher;
|
||||
private final DataFetcher<DataSource, Long> slackFetcher;
|
||||
@ -262,6 +265,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
this.osFetcher = containerData::getOperatingSystems;
|
||||
|
||||
this.sizeFetcher = (dataSource) -> dataSource == null ? null : dataSource.getSize();
|
||||
|
||||
this.typesFetcher = (dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource);
|
||||
|
||||
this.allocatedFetcher = (dataSource) -> typeData.getCountOfAllocatedFiles(dataSource);
|
||||
this.unallocatedFetcher = (dataSource) -> typeData.getCountOfUnallocatedFiles(dataSource);
|
||||
@ -275,9 +280,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
(sizeResult) -> sizeLabel.showDataFetchResult(
|
||||
DataFetchResult.getSubResult(sizeResult,
|
||||
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
|
||||
new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
|
||||
this::showMimeTypeCategories),
|
||||
new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories),
|
||||
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
|
||||
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
|
||||
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
|
||||
@ -443,6 +446,15 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
if (dataSource == null) {
|
||||
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(),
|
||||
Stream.of(
|
||||
@ -450,10 +462,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
|
||||
getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource),
|
||||
new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(),
|
||||
SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))),
|
||||
new PieChartExport(String keyColumnHeader,
|
||||
String valueColumnHeader, String valueFormatString,
|
||||
String chartTitle,
|
||||
List<PieChartItem> slices),
|
||||
typesChart,
|
||||
getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource),
|
||||
getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_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;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.swing.JLabel;
|
||||
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.StandardBarPainter;
|
||||
import org.jfree.data.category.DefaultCategoryDataset;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -285,12 +206,12 @@ public class BarChartPanel extends AbstractLoadableComponent<List<BarChartPanel.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setResults(List<BarChartPanel.BarChartSeries> data) {
|
||||
protected void setResults(List<BarChartSeries> data) {
|
||||
this.dataset.clear();
|
||||
|
||||
if (CollectionUtils.isNotEmpty(data)) {
|
||||
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.getColor() != null) {
|
||||
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);
|
||||
}
|
||||
|
||||
// freeze header row
|
||||
sheet.createFreezePane(0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -119,8 +121,7 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelSheet
|
||||
cell.setCellValue(columns.get(i).getHeaderTitle());
|
||||
cell.setCellStyle(worksheetEnv.getHeaderStyle());
|
||||
}
|
||||
// freeze header row
|
||||
sheet.createFreezePane(0, 1);
|
||||
|
||||
// Create Cell Style for each column (if one is needed)
|
||||
|
||||
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {
|
||||
|
@ -9,11 +9,16 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
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.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.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;
|
||||
@ -28,6 +33,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.
|
||||
* @author gregd
|
||||
*/
|
||||
public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
||||
|
||||
private final ExcelTableExport<PieChartItem, ? extends ExcelCellModel> tableExport;
|
||||
private final int colOffset;
|
||||
private final int rowPadding;
|
||||
@ -35,26 +41,25 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
||||
private final int rowSize;
|
||||
private final String chartTitle;
|
||||
private final String sheetName;
|
||||
private final List<PieChartItem> slices;
|
||||
|
||||
public PieChartExport(String keyColumnHeader,
|
||||
|
||||
public PieChartExport(String keyColumnHeader,
|
||||
String valueColumnHeader, String valueFormatString,
|
||||
String chartTitle,
|
||||
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,
|
||||
String valueColumnHeader, String valueFormatString,
|
||||
String chartTitle, String sheetName,
|
||||
List<PieChartItem> slices,
|
||||
String chartTitle, String sheetName,
|
||||
List<PieChartItem> slices,
|
||||
int colOffset, int rowPadding, int colSize, int rowSize) {
|
||||
|
||||
|
||||
this.tableExport = new ExcelTableExport<>(chartTitle,
|
||||
Arrays.asList(
|
||||
new ColumnModel<>(keyColumnHeader, (slice) -> new DefaultCellModel<>(slice.getLabel())),
|
||||
new ColumnModel<>(valueColumnHeader, (slice) -> new DefaultCellModel<>(slice.getValue(), null, valueFormatString))
|
||||
),
|
||||
),
|
||||
slices);
|
||||
this.colOffset = colOffset;
|
||||
this.rowPadding = rowPadding;
|
||||
@ -62,11 +67,8 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
||||
this.rowSize = rowSize;
|
||||
this.chartTitle = chartTitle;
|
||||
this.sheetName = sheetName;
|
||||
this.slices = slices;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getSheetName() {
|
||||
return sheetName;
|
||||
@ -82,35 +84,39 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
|
||||
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);
|
||||
XDDFChartLegend legend = chart.getOrAddLegend();
|
||||
legend.setPosition(LegendPosition.RIGHT);
|
||||
|
||||
// (int firstRow, int lastRow, int firstCol, int lastCol)
|
||||
XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromStringCellRange(xssfSheet,
|
||||
new CellRangeAddress(tableDimensions.getRowStart(), tableDimensions.getRowEnd(),
|
||||
new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
|
||||
tableDimensions.getColStart(), tableDimensions.getColStart()));
|
||||
|
||||
|
||||
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));
|
||||
|
||||
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.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().addNewShowCatName().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);
|
||||
|
||||
|
||||
return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user