Autopsy  4.19.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
PieChartExport.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport;
20 
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.InvocationTargetException;
23 import java.util.Arrays;
24 import java.util.List;
25 import org.apache.poi.ss.usermodel.Sheet;
26 import org.apache.poi.ss.util.CellRangeAddress;
27 import org.apache.poi.xddf.usermodel.chart.LegendPosition;
28 import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
29 import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
30 import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
31 import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
32 import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
33 import org.apache.poi.xssf.usermodel.XSSFChart;
34 import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
35 import org.apache.poi.xssf.usermodel.XSSFDrawing;
36 import org.apache.poi.xssf.usermodel.XSSFSheet;
37 import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart;
43 
48 class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
49 
50  private static final int DEFAULT_ROW_SIZE = 20;
51  private static final int DEFAULT_COL_SIZE = 10;
52  private static final int DEFAULT_ROW_PADDING = 1;
53  private static final int DEFAULT_COL_OFFSET = 1;
54 
55  private final ExcelTableExport<PieChartItem, ? extends CellModel> tableExport;
56  private final int colOffset;
57  private final int rowPadding;
58  private final int colSize;
59  private final int rowSize;
60  private final String chartTitle;
61  private final String sheetName;
62 
73  PieChartExport(String keyColumnHeader,
74  String valueColumnHeader, String valueFormatString,
75  String chartTitle,
76  List<PieChartItem> slices) {
77  this(keyColumnHeader, valueColumnHeader, valueFormatString, chartTitle, chartTitle, slices,
78  DEFAULT_COL_OFFSET, DEFAULT_ROW_PADDING, DEFAULT_COL_SIZE, DEFAULT_ROW_SIZE);
79  }
80 
97  PieChartExport(String keyColumnHeader,
98  String valueColumnHeader, String valueFormatString,
99  String chartTitle, String sheetName,
100  List<PieChartItem> slices,
101  int colOffset, int rowPadding, int colSize, int rowSize) {
102 
103  this.tableExport = new ExcelTableExport<>(chartTitle,
104  Arrays.asList(
105  new ColumnModel<>(keyColumnHeader, (slice) -> new DefaultCellModel<>(slice.getLabel())),
106  new ColumnModel<>(valueColumnHeader, (slice) -> new DefaultCellModel<>(slice.getValue(), null, valueFormatString))
107  ),
108  slices);
109  this.colOffset = colOffset;
110  this.rowPadding = rowPadding;
111  this.colSize = colSize;
112  this.rowSize = rowSize;
113  this.chartTitle = chartTitle;
114  this.sheetName = sheetName;
115  }
116 
117  @Override
118  public String getSheetName() {
119  return sheetName;
120  }
121 
122  @Override
123  public void renderSheet(Sheet sheet, ExcelExport.WorksheetEnv env) throws ExcelExport.ExcelExportException {
124  write(sheet, 0, 0, env);
125  }
126 
127  @Override
128  public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
129  if (!(sheet instanceof XSSFSheet)) {
130  throw new ExcelExportException("Sheet must be an XSSFSheet in order to write.");
131  }
132 
133  XSSFSheet xssfSheet = (XSSFSheet) sheet;
134 
135  // write pie chart table data
136  ItemDimensions tableDimensions = tableExport.write(xssfSheet, rowStart + rowPadding, colStart, env);
137 
138  XSSFDrawing drawing = xssfSheet.createDrawingPatriarch();
139 
140  int chartColStart = colStart + 2 + colOffset;
141 
142  //createAnchor has arguments of (int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2);
143  XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, chartColStart, rowStart + rowPadding, chartColStart + colSize + 1, rowStart + rowSize + 1);
144 
145  XSSFChart chart = drawing.createChart(anchor);
146  chart.setTitleText(chartTitle);
147  chart.setTitleOverlay(false);
148  XDDFChartLegend legend = chart.getOrAddLegend();
149  legend.setPosition(LegendPosition.RIGHT);
150 
151  // CellRangeAddress has arguments of (int firstRow, int lastRow, int firstCol, int lastCol)
152  XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromStringCellRange(xssfSheet,
153  new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
154  tableDimensions.getColStart(), tableDimensions.getColStart()));
155 
156  XDDFNumericalDataSource<Double> val = XDDFDataSourcesFactory.fromNumericCellRange(xssfSheet,
157  new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
158  tableDimensions.getColStart() + 1, tableDimensions.getColStart() + 1));
159 
160  // NOTE: There appears to be a classpath issue with POI (a version of 4.0.1 and 4.1.1 simultaneously)
161  // that is causing conflicts for XDDFPieChartData creation (i.e. the compiler thinks its using 4.1.1
162  // and the runtime thinks its using 4.0.1) Reflection is used below to use the 4.0.1 method while
163  // sidestepping compiler issues.
164  // XDDFPieChartData creation that can be used in poi >= 4.1.1:
165  // XDDFPieChartData data = (XDDFPieChartData) chart.createData(ChartTypes.PIE, bottomAxis, leftAxis);
166  // XDDFPieChartData creation that can be used in 4.0.1:
167  // XDDFPieChartData data = new XDDFPieChartData(chart.getCTChart().getPlotArea().addNewPieChart());
168  XDDFPieChartData data;
169  try {
170  Constructor<XDDFPieChartData> constructor = XDDFPieChartData.class.getConstructor(CTPieChart.class);
171  constructor.setAccessible(true);
172  data = constructor.newInstance(chart.getCTChart().getPlotArea().addNewPieChart());
173  } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException | IllegalArgumentException ex) {
174  throw new ExcelExportException("Error while instantiating chart data.", ex);
175  }
176 
177  data.setVaryColors(true);
178  data.addSeries(cat, val);
179 
180  // Add data labels
181  if (!chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).isSetDLbls()) {
182  chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDLbls();
183  }
184 
185  chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowVal().setVal(true);
186  chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false);
187  chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(true);
188  chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(true);
189  chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
190 
191  chart.plot(data);
192 
193  return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
194  }
195 
196 }

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.