Initial support for getting and changing chart titles and series titles

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@646854 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-04-10 15:54:02 +00:00
parent 7024f8896e
commit f8c6a52a2c
7 changed files with 245 additions and 27 deletions

View File

@ -37,6 +37,8 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.0.3-beta1" date="2008-04-??"> <release version="3.0.3-beta1" date="2008-04-??">
<action dev="POI-DEVELOPERS" type="add">Initial support for getting and changing chart and series titles</action>
<action dev="POI-DEVELOPERS" type="add">Implement a proxy HSSFListener which tracks the format records, and lets you lookup the format string for a given cell. Convert the xls to csv example to use it</action>
<action dev="POI-DEVELOPERS" type="fix">44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord.</action> <action dev="POI-DEVELOPERS" type="fix">44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord.</action>
<action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action> <action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action>
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action> <action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>

View File

@ -34,6 +34,8 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.0.3-beta1" date="2008-04-??"> <release version="3.0.3-beta1" date="2008-04-??">
<action dev="POI-DEVELOPERS" type="add">Initial support for getting and changing chart and series titles</action>
<action dev="POI-DEVELOPERS" type="add">Implement a proxy HSSFListener which tracks the format records, and lets you lookup the format string for a given cell. Convert the xls to csv example to use it</action>
<action dev="POI-DEVELOPERS" type="fix">44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord.</action> <action dev="POI-DEVELOPERS" type="fix">44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord.</action>
<action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action> <action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action>
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action> <action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>

View File

@ -17,6 +17,8 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import java.io.ByteArrayInputStream;
/** /**
* This is purely for the biff viewer. During normal operations we don't want * This is purely for the biff viewer. During normal operations we don't want
* to be seeing this. * to be seeing this.
@ -35,6 +37,21 @@ public class DrawingRecordForBiffViewer
super(in); super(in);
} }
public DrawingRecordForBiffViewer(DrawingRecord r)
{
super(convertToInputStream(r));
convertRawBytesToEscherRecords();
}
private static RecordInputStream convertToInputStream(DrawingRecord r)
{
byte[] data = r.serialize();
RecordInputStream rinp = new RecordInputStream(
new ByteArrayInputStream(data)
);
rinp.nextRecord();
return rinp;
}
protected String getRecordName() protected String getRecordName()
{ {
return "MSODRAWING"; return "MSODRAWING";

View File

@ -77,6 +77,8 @@ public class RecordFactory
NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class,
FileSharingRecord.class, ChartTitleFormatRecord.class, FileSharingRecord.class, ChartTitleFormatRecord.class,
DVRecord.class, DVALRecord.class, UncalcedRecord.class, DVRecord.class, DVALRecord.class, UncalcedRecord.class,
ChartRecord.class, LegendRecord.class, ChartTitleFormatRecord.class,
SeriesRecord.class, SeriesTextRecord.class,
HyperlinkRecord.class, HyperlinkRecord.class,
ExternalNameRecord.class, // TODO - same changes in non-@deprecated version of this class ExternalNameRecord.class, // TODO - same changes in non-@deprecated version of this class
SupBookRecord.class, SupBookRecord.class,

View File

@ -1554,18 +1554,14 @@ public final class HSSFSheet {
} }
/** /**
* Returns the top-level drawing patriach, if there is * Returns the agregate escher records for this sheet,
* one. * it there is one.
* This will hold any graphics or charts for the sheet.
* WARNING - calling this will trigger a parsing of the * WARNING - calling this will trigger a parsing of the
* associated escher records. Any that aren't supported * associated escher records. Any that aren't supported
* (such as charts and complex drawing types) will almost * (such as charts and complex drawing types) will almost
* certainly be lost or corrupted when written out. Only * certainly be lost or corrupted when written out.
* use this with simple drawings, otherwise call
* {@link HSSFSheet#createDrawingPatriarch()} and
* start from scratch!
*/ */
public HSSFPatriarch getDrawingPatriarch() { public EscherAggregate getDrawingEscherAggregate() {
book.findDrawingGroup(); book.findDrawingGroup();
// If there's now no drawing manager, then there's // If there's now no drawing manager, then there's
@ -1584,6 +1580,25 @@ public final class HSSFSheet {
// Grab our aggregate record, and wire it up // Grab our aggregate record, and wire it up
EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid); EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid);
return agg;
}
/**
* Returns the top-level drawing patriach, if there is
* one.
* This will hold any graphics or charts for the sheet.
* WARNING - calling this will trigger a parsing of the
* associated escher records. Any that aren't supported
* (such as charts and complex drawing types) will almost
* certainly be lost or corrupted when written out. Only
* use this with simple drawings, otherwise call
* {@link HSSFSheet#createDrawingPatriarch()} and
* start from scratch!
*/
public HSSFPatriarch getDrawingPatriarch() {
EscherAggregate agg = getDrawingEscherAggregate();
if(agg == null) return null;
HSSFPatriarch patriarch = new HSSFPatriarch(this, agg); HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
agg.setPatriarch(patriarch); agg.setPatriarch(patriarch);

View File

@ -19,14 +19,58 @@
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import org.apache.poi.hssf.record.AreaFormatRecord;
import org.apache.poi.hssf.record.AxisLineFormatRecord;
import org.apache.poi.hssf.record.AxisOptionsRecord;
import org.apache.poi.hssf.record.AxisParentRecord;
import org.apache.poi.hssf.record.AxisRecord;
import org.apache.poi.hssf.record.AxisUsedRecord;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BarRecord;
import org.apache.poi.hssf.record.BeginRecord;
import org.apache.poi.hssf.record.CategorySeriesAxisRecord;
import org.apache.poi.hssf.record.ChartFormatRecord;
import org.apache.poi.hssf.record.ChartRecord;
import org.apache.poi.hssf.record.ChartTitleFormatRecord;
import org.apache.poi.hssf.record.DataFormatRecord;
import org.apache.poi.hssf.record.DefaultDataLabelTextPropertiesRecord;
import org.apache.poi.hssf.record.DimensionsRecord;
import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.EndRecord;
import org.apache.poi.hssf.record.FontBasisRecord;
import org.apache.poi.hssf.record.FontIndexRecord;
import org.apache.poi.hssf.record.FooterRecord;
import org.apache.poi.hssf.record.FrameRecord;
import org.apache.poi.hssf.record.HCenterRecord;
import org.apache.poi.hssf.record.HeaderRecord;
import org.apache.poi.hssf.record.LegendRecord;
import org.apache.poi.hssf.record.LineFormatRecord;
import org.apache.poi.hssf.record.LinkedDataFormulaField;
import org.apache.poi.hssf.record.LinkedDataRecord;
import org.apache.poi.hssf.record.PlotAreaRecord;
import org.apache.poi.hssf.record.PlotGrowthRecord;
import org.apache.poi.hssf.record.PrintSetupRecord;
import org.apache.poi.hssf.record.ProtectRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SCLRecord;
import org.apache.poi.hssf.record.SeriesIndexRecord;
import org.apache.poi.hssf.record.SeriesRecord;
import org.apache.poi.hssf.record.SeriesTextRecord;
import org.apache.poi.hssf.record.SeriesToChartGroupRecord;
import org.apache.poi.hssf.record.SheetPropertiesRecord;
import org.apache.poi.hssf.record.TextRecord;
import org.apache.poi.hssf.record.TickRecord;
import org.apache.poi.hssf.record.UnitsRecord;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.ValueRangeRecord;
import org.apache.poi.hssf.record.formula.Area3DPtg;
/** /**
* Has methods for construction of a chart object. * Has methods for construction of a chart object.
* *
@ -35,11 +79,13 @@ import java.util.Stack;
public class HSSFChart public class HSSFChart
{ {
private ChartRecord chartRecord; private ChartRecord chartRecord;
private SeriesRecord seriesRecord;
private LegendRecord legendRecord;
private ChartTitleFormatRecord chartTitleFormat; private ChartTitleFormatRecord chartTitleFormat;
private SeriesTextRecord chartTitleText; private SeriesTextRecord chartTitleText;
private List series = new ArrayList();
private HSSFChart(ChartRecord chartRecord) { private HSSFChart(ChartRecord chartRecord) {
this.chartRecord = chartRecord; this.chartRecord = chartRecord;
} }
@ -121,8 +167,8 @@ public class HSSFChart
/** /**
* Returns all the charts for the given sheet. * Returns all the charts for the given sheet.
* *
* NOTE: Does not yet work... checking it in just so others * NOTE: You won't be able to do very much with
* can take a look. * these charts yet, as this is very limited support
*/ */
public static HSSFChart[] getSheetCharts(HSSFSheet sheet) { public static HSSFChart[] getSheetCharts(HSSFSheet sheet) {
List charts = new ArrayList(); List charts = new ArrayList();
@ -132,33 +178,49 @@ public class HSSFChart
List records = sheet.getSheet().getRecords(); List records = sheet.getSheet().getRecords();
for(Iterator it = records.iterator(); it.hasNext();) { for(Iterator it = records.iterator(); it.hasNext();) {
Record r = (Record)it.next(); Record r = (Record)it.next();
System.err.println(r);
if(r instanceof DrawingRecord) {
DrawingRecord dr = (DrawingRecord)r;
}
if(r instanceof ChartRecord) { if(r instanceof ChartRecord) {
lastChart = new HSSFChart((ChartRecord)r); lastChart = new HSSFChart((ChartRecord)r);
charts.add(lastChart); charts.add(lastChart);
} }
if(r instanceof LegendRecord) {
lastChart.legendRecord = (LegendRecord)r;
}
if(r instanceof SeriesRecord) { if(r instanceof SeriesRecord) {
lastChart.seriesRecord = (SeriesRecord)r; HSSFSeries series = lastChart.new HSSFSeries( (SeriesRecord)r );
lastChart.series.add(series);
} }
if(r instanceof ChartTitleFormatRecord) { if(r instanceof ChartTitleFormatRecord) {
lastChart.chartTitleFormat = lastChart.chartTitleFormat =
(ChartTitleFormatRecord)r; (ChartTitleFormatRecord)r;
} }
if(r instanceof SeriesTextRecord) { if(r instanceof SeriesTextRecord) {
lastChart.chartTitleText = // Applies to a series, unless we've seen
(SeriesTextRecord)r; // a legend already
SeriesTextRecord str = (SeriesTextRecord)r;
if(lastChart.legendRecord == null &&
lastChart.series.size() > 0) {
HSSFSeries series = (HSSFSeries)
lastChart.series.get(lastChart.series.size()-1);
series.seriesTitleText = str;
} else {
lastChart.chartTitleText = str;
}
} }
} }
return (HSSFChart[]) return (HSSFChart[])
charts.toArray( new HSSFChart[charts.size()] ); charts.toArray( new HSSFChart[charts.size()] );
} }
/**
* Returns the series of the chart
*/
public HSSFSeries[] getSeries() {
return (HSSFSeries[])
series.toArray(new HSSFSeries[series.size()]);
}
/** /**
* Returns the chart's title, if there is one, * Returns the chart's title, if there is one,
@ -184,7 +246,6 @@ public class HSSFChart
} }
} }
private EOFRecord createEOFRecord() private EOFRecord createEOFRecord()
{ {
@ -858,4 +919,51 @@ public class HSSFChart
r.setUnits( (short) 0 ); r.setUnits( (short) 0 );
return r; return r;
} }
/**
* A series in a chart
*/
public class HSSFSeries {
private SeriesRecord series;
private SeriesTextRecord seriesTitleText;
private HSSFSeries(SeriesRecord series) {
this.series = series;
}
public short getNumValues() {
return series.getNumValues();
}
/**
* See {@link SeriesRecord}
*/
public short getValueType() {
return series.getValuesDataType();
}
/**
* Returns the series' title, if there is one,
* or null if not
*/
public String getSeriesTitle() {
if(seriesTitleText != null) {
return seriesTitleText.getText();
}
return null;
}
/**
* Changes the series' title, but only if there
* was one already.
* TODO - add in the records if not
*/
public void setSeriesTitle(String title) {
if(seriesTitleText != null) {
seriesTitleText.setText(title);
} else {
throw new IllegalStateException("No series title found to change");
}
}
}
} }

View File

@ -19,6 +19,8 @@ package org.apache.poi.hssf.usermodel;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import org.apache.poi.hssf.record.SeriesRecord;
import junit.framework.TestCase; import junit.framework.TestCase;
public class TestHSSFChart extends TestCase { public class TestHSSFChart extends TestCase {
@ -29,14 +31,65 @@ public class TestHSSFChart extends TestCase {
} }
public void testSingleChart() throws Exception { public void testSingleChart() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook(
new FileInputStream(new File(dirName, "WithChart.xls"))
);
HSSFSheet s1 = wb.getSheetAt(0);
HSSFSheet s2 = wb.getSheetAt(1);
HSSFSheet s3 = wb.getSheetAt(2);
assertEquals(0, HSSFChart.getSheetCharts(s1).length);
assertEquals(1, HSSFChart.getSheetCharts(s2).length);
assertEquals(0, HSSFChart.getSheetCharts(s3).length);
HSSFChart[] charts;
// Check the chart on the 2nd sheet
charts = HSSFChart.getSheetCharts(s2);
assertEquals(1, charts.length);
assertEquals(2, charts[0].getSeries().length);
assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
assertEquals(null, charts[0].getChartTitle());
} }
public void testTwoCharts() throws Exception { public void testTwoCharts() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook(
new FileInputStream(new File(dirName, "WithTwoCharts.xls"))
);
HSSFSheet s1 = wb.getSheetAt(0);
HSSFSheet s2 = wb.getSheetAt(1);
HSSFSheet s3 = wb.getSheetAt(2);
assertEquals(0, HSSFChart.getSheetCharts(s1).length);
assertEquals(1, HSSFChart.getSheetCharts(s2).length);
assertEquals(1, HSSFChart.getSheetCharts(s3).length);
HSSFChart[] charts;
// Check the chart on the 2nd sheet
charts = HSSFChart.getSheetCharts(s2);
assertEquals(1, charts.length);
assertEquals(2, charts[0].getSeries().length);
assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
assertEquals(null, charts[0].getChartTitle());
// And the third sheet
charts = HSSFChart.getSheetCharts(s3);
assertEquals(1, charts.length);
assertEquals(2, charts[0].getSeries().length);
assertEquals("Squares", charts[0].getSeries()[0].getSeriesTitle());
assertEquals("Base Numbers", charts[0].getSeries()[1].getSeriesTitle());
assertEquals(null, charts[0].getChartTitle());
} }
public void BROKENtestThreeCharts() throws Exception { public void testThreeCharts() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook( HSSFWorkbook wb = new HSSFWorkbook(
new FileInputStream(new File(dirName, "WithThreeCharts.xls")) new FileInputStream(new File(dirName, "WithThreeCharts.xls"))
); );
@ -51,11 +104,30 @@ public class TestHSSFChart extends TestCase {
HSSFChart[] charts; HSSFChart[] charts;
// Check the charts on the 2nd sheet
charts = HSSFChart.getSheetCharts(s2); charts = HSSFChart.getSheetCharts(s2);
assertNull(charts[0].getChartTitle()); assertEquals(2, charts.length);
assertEquals(2, charts[0].getSeries().length);
assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
assertEquals(6, charts[0].getSeries()[0].getNumValues());
assertEquals(6, charts[0].getSeries()[1].getNumValues());
assertEquals(SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, charts[0].getSeries()[0].getValueType());
assertEquals(SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, charts[0].getSeries()[1].getValueType());
assertEquals(null, charts[0].getChartTitle());
assertEquals(1, charts[1].getSeries().length);
assertEquals(null, charts[1].getSeries()[0].getSeriesTitle());
assertEquals("Pie Chart Title Thingy", charts[1].getChartTitle()); assertEquals("Pie Chart Title Thingy", charts[1].getChartTitle());
// And the third sheet
charts = HSSFChart.getSheetCharts(s3); charts = HSSFChart.getSheetCharts(s3);
assertEquals("Sheet 3 Chart with Title", charts[1].getChartTitle()); assertEquals(1, charts.length);
assertEquals(2, charts[0].getSeries().length);
assertEquals("Squares", charts[0].getSeries()[0].getSeriesTitle());
assertEquals("Base Numbers", charts[0].getSeries()[1].getSeriesTitle());
assertEquals("Sheet 3 Chart with Title", charts[0].getChartTitle());
} }
} }