Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677064 via svnmerge from

https://svn.apache.org:443/repos/asf/poi/trunk

........
  r677028 | nick | 2008-07-15 21:19:06 +0100 (Tue, 15 Jul 2008) | 1 line
  
  Method to check if two fonts have the same contents
........
  r677029 | nick | 2008-07-15 21:24:53 +0100 (Tue, 15 Jul 2008) | 1 line
  
  Support for removing low level font records
........
  r677041 | nick | 2008-07-15 22:15:16 +0100 (Tue, 15 Jul 2008) | 1 line
  
  Start on HSSFOptimiser, which removes un-needed cell styles and fonts, fixing up references as it does so
........
  r677057 | nick | 2008-07-15 22:38:38 +0100 (Tue, 15 Jul 2008) | 1 line
  
  Cell Style optimisations too
........


git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@677103 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-07-15 23:40:09 +00:00
parent b3e2a14d9a
commit e09aa6d363
13 changed files with 647 additions and 4 deletions

View File

@ -50,6 +50,7 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">New helper, HSSFOptimiser, which handles removing duplicated font and style records, to avoid going over the limits in Excel</action>
<action dev="POI-DEVELOPERS" type="fix">45322 - Fixed NPE in HSSFSheet.autoSizeColumn() when cell number format was not found</action>
<action dev="POI-DEVELOPERS" type="add">45380 - Missing return keyword in ArrayPtg.toFormulaString()</action>
<action dev="POI-DEVELOPERS" type="add">44958 - Record level support for Data Tables. (No formula parser support though)</action>

View File

@ -47,6 +47,7 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">New helper, HSSFOptimiser, which handles removing duplicated font and style records, to avoid going over the limits in Excel</action>
<action dev="POI-DEVELOPERS" type="fix">45322 - Fixed NPE in HSSFSheet.autoSizeColumn() when cell number format was not found</action>
<action dev="POI-DEVELOPERS" type="add">45380 - Missing return keyword in ArrayPtg.toFormulaString()</action>
<action dev="POI-DEVELOPERS" type="add">44958 - Record level support for Data Tables. (No formula parser support though)</action>

View File

@ -443,6 +443,17 @@ public class Workbook implements Model
numfonts++;
return rec;
}
/**
* Removes the given font record from the
* file's list. This will make all
* subsequent font indicies drop by one,
* so you'll need to update those yourself!
*/
public void removeFontRecord(FontRecord rec) {
records.remove(rec); // this updates FontPos for us
numfonts--;
}
/**
* gets the number of font records
@ -702,6 +713,18 @@ public class Workbook implements Model
return retval;
}
/**
* Removes the given ExtendedFormatRecord record from the
* file's list. This will make all
* subsequent font indicies drop by one,
* so you'll need to update those yourself!
*/
public void removeExFormatRecord(ExtendedFormatRecord rec) {
records.remove(rec); // this updates XfPos for us
numxfs--;
}
/**
* creates a new Cell-type Extneded Format Record and adds it to the end of

View File

@ -579,6 +579,31 @@ public class FontRecord
result = prime * result + field_10_font_name_len;
return result;
}
/**
* Does this FontRecord have all the same font
* properties as the supplied FontRecord?
* Note that {@link #equals(Object)} will check
* for exact objects, while this will check
* for exact contents, because normally the
* font record's position makes a big
* difference too.
*/
public boolean sameProperties(FontRecord other) {
return
field_1_font_height == other.field_1_font_height &&
field_2_attributes == other.field_2_attributes &&
field_3_color_palette_index == other.field_3_color_palette_index &&
field_4_bold_weight == other.field_4_bold_weight &&
field_5_super_sub_script == other.field_5_super_sub_script &&
field_6_underline == other.field_6_underline &&
field_7_family == other.field_7_family &&
field_8_charset == other.field_8_charset &&
field_9_zero == other.field_9_zero &&
field_10_font_name_len == other.field_10_font_name_len &&
field_11_font_name.equals(other.field_11_font_name)
;
}
/**
* Only returns two for the same exact object -

View File

@ -439,6 +439,23 @@ public class UnicodeString
this.field_5_ext_rst = ext_rst;
}
/**
* Swaps all use in the string of one font index
* for use of a different font index.
* Normally only called when fonts have been
* removed / re-ordered
*/
public void swapFontUse(short oldFontIndex, short newFontIndex) {
Iterator i = field_4_format_runs.iterator();
while(i.hasNext()) {
FormatRun run = (FormatRun)i.next();
if(run.fontIndex == oldFontIndex) {
run.fontIndex = newFontIndex;
}
}
}
/**
* unlike the real records we return the same as "getString()" rather than debug info
* @see #getDebugInfo()

View File

@ -938,14 +938,13 @@ public class HSSFCell implements Cell
* object.
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(short)
*/
public HSSFCellStyle getCellStyle()
{
short styleIndex=record.getXFIndex();
ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex);
return new HSSFCellStyle(styleIndex, xf, book);
}
/**
* used for internationalization, currently -1 for unchanged, 0 for compressed unicode or 1 for 16-bit
*

View File

@ -0,0 +1,261 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
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.apache.poi.hssf.usermodel;
import java.util.HashSet;
import java.util.Iterator;
import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.FontRecord;
import org.apache.poi.hssf.record.UnicodeString;
/**
* Excel can get cranky if you give it files containing too
* many (especially duplicate) objects, and this class can
* help to avoid those.
* In general, it's much better to make sure you don't
* duplicate the objects in your code, as this is likely
* to be much faster than creating lots and lots of
* excel objects+records, only to optimise them down to
* many fewer at a later stage.
* However, sometimes this is too hard / tricky to do, which
* is where the use of this class comes in.
*/
public class HSSFOptimiser {
/**
* Goes through the Workbook, optimising the fonts by
* removing duplicate ones.
* For now, only works on fonts used in {@link HSSFCellStyle}
* and {@link HSSFRichTextString}. Any other font uses
* (eg charts, pictures) may well end up broken!
* This can be a slow operation, especially if you have
* lots of cells, cell styles or rich text strings
* @param workbook The workbook in which to optimise the fonts
*/
public static void optimiseFonts(HSSFWorkbook workbook) {
// Where each font has ended up, and if we need to
// delete the record for it. Start off with no change
short[] newPos =
new short[workbook.getWorkbook().getNumberOfFontRecords()+1];
boolean[] zapRecords = new boolean[newPos.length];
for(int i=0; i<newPos.length; i++) {
newPos[i] = (short)i;
zapRecords[i] = false;
}
// Get each font record, so we can do deletes
// without getting confused
FontRecord[] frecs = new FontRecord[newPos.length];
for(int i=0; i<newPos.length; i++) {
// There is no 4!
if(i == 4) continue;
frecs[i] = workbook.getWorkbook().getFontRecordAt(i);
}
// Loop over each font, seeing if it is the same
// as an earlier one. If it is, point users of the
// later duplicate copy to the earlier one, and
// mark the later one as needing deleting
// Note - don't change built in fonts (those before 5)
for(int i=5; i<newPos.length; i++) {
// Check this one for being a duplicate
// of an earlier one
int earlierDuplicate = -1;
for(int j=0; j<i && earlierDuplicate == -1; j++) {
if(j == 4) continue;
FontRecord frCheck = workbook.getWorkbook().getFontRecordAt(j);
if(frCheck.sameProperties(frecs[i])) {
earlierDuplicate = j;
}
}
// If we got a duplicate, mark it as such
if(earlierDuplicate != -1) {
newPos[i] = (short)earlierDuplicate;
zapRecords[i] = true;
}
}
// Update the new positions based on
// deletes that have occurred between
// the start and them
// Only need to worry about user fonts
for(int i=5; i<newPos.length; i++) {
// Find the number deleted to that
// point, and adjust
short preDeletePos = newPos[i];
short newPosition = preDeletePos;
for(int j=0; j<preDeletePos; j++) {
if(zapRecords[j]) newPosition--;
}
// Update the new position
newPos[i] = newPosition;
}
// Zap the un-needed user font records
for(int i=5; i<newPos.length; i++) {
if(zapRecords[i]) {
workbook.getWorkbook().removeFontRecord(
frecs[i]
);
}
}
// Tell HSSFWorkbook that it needs to
// re-start its HSSFFontCache
workbook.resetFontCache();
// Update the cell styles to point at the
// new locations of the fonts
for(int i=0; i<workbook.getWorkbook().getNumExFormats(); i++) {
ExtendedFormatRecord xfr = workbook.getWorkbook().getExFormatAt(i);
xfr.setFontIndex(
newPos[ xfr.getFontIndex() ]
);
}
// Update the rich text strings to point at
// the new locations of the fonts
// Remember that one underlying unicode string
// may be shared by multiple RichTextStrings!
HashSet doneUnicodeStrings = new HashSet();
for(int sheetNum=0; sheetNum<workbook.getNumberOfSheets(); sheetNum++) {
HSSFSheet s = workbook.getSheetAt(sheetNum);
Iterator rIt = s.rowIterator();
while(rIt.hasNext()) {
HSSFRow row = (HSSFRow)rIt.next();
Iterator cIt = row.cellIterator();
while(cIt.hasNext()) {
HSSFCell cell = (HSSFCell)cIt.next();
if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
HSSFRichTextString rtr = cell.getRichStringCellValue();
UnicodeString u = rtr.getRawUnicodeString();
// Have we done this string already?
if(! doneUnicodeStrings.contains(u)) {
// Update for each new position
for(short i=5; i<newPos.length; i++) {
if(i != newPos[i]) {
u.swapFontUse(i, newPos[i]);
}
}
// Mark as done
doneUnicodeStrings.add(u);
}
}
}
}
}
}
/**
* Goes through the Wokrbook, optimising the cell styles
* by removing duplicate ones.
* For best results, optimise the fonts via a call to
* {@link #optimiseFonts(HSSFWorkbook)} first.
* @param workbook The workbook in which to optimise the cell styles
*/
public static void optimiseCellStyles(HSSFWorkbook workbook) {
// Where each style has ended up, and if we need to
// delete the record for it. Start off with no change
short[] newPos =
new short[workbook.getWorkbook().getNumExFormats()];
boolean[] zapRecords = new boolean[newPos.length];
for(int i=0; i<newPos.length; i++) {
newPos[i] = (short)i;
zapRecords[i] = false;
}
// Get each style record, so we can do deletes
// without getting confused
ExtendedFormatRecord[] xfrs = new ExtendedFormatRecord[newPos.length];
for(int i=0; i<newPos.length; i++) {
xfrs[i] = workbook.getWorkbook().getExFormatAt(i);
}
// Loop over each style, seeing if it is the same
// as an earlier one. If it is, point users of the
// later duplicate copy to the earlier one, and
// mark the later one as needing deleting
// Only work on user added ones, which come after 20
for(int i=21; i<newPos.length; i++) {
// Check this one for being a duplicate
// of an earlier one
int earlierDuplicate = -1;
for(int j=0; j<i && earlierDuplicate == -1; j++) {
ExtendedFormatRecord xfCheck = workbook.getWorkbook().getExFormatAt(j);
if(xfCheck.equals(xfrs[i])) {
earlierDuplicate = j;
}
}
// If we got a duplicate, mark it as such
if(earlierDuplicate != -1) {
newPos[i] = (short)earlierDuplicate;
zapRecords[i] = true;
}
}
// Update the new positions based on
// deletes that have occurred between
// the start and them
// Only work on user added ones, which come after 20
for(int i=21; i<newPos.length; i++) {
// Find the number deleted to that
// point, and adjust
short preDeletePos = newPos[i];
short newPosition = preDeletePos;
for(int j=0; j<preDeletePos; j++) {
if(zapRecords[j]) newPosition--;
}
// Update the new position
newPos[i] = newPosition;
}
// Zap the un-needed user style records
for(int i=21; i<newPos.length; i++) {
if(zapRecords[i]) {
workbook.getWorkbook().removeExFormatRecord(
xfrs[i]
);
}
}
// Finally, update the cells to point at
// their new extended format records
for(int sheetNum=0; sheetNum<workbook.getNumberOfSheets(); sheetNum++) {
HSSFSheet s = workbook.getSheetAt(sheetNum);
Iterator rIt = s.rowIterator();
while(rIt.hasNext()) {
HSSFRow row = (HSSFRow)rIt.next();
Iterator cIt = row.cellIterator();
while(cIt.hasNext()) {
HSSFCell cell = (HSSFCell)cIt.next();
short oldXf = cell.getCellValueRecord().getXFIndex();
HSSFCellStyle newStyle = workbook.getCellStyleAt(
newPos[oldXf]
);
cell.setCellStyle(newStyle);
}
}
}
}
}

View File

@ -69,7 +69,7 @@ public class HSSFRichTextString
/** Called whenever the unicode string is modified. When it is modified
* we need to create a new SST index, so that other LabelSSTRecords will not
* be affected by changes tat we make to this string.
* be affected by changes that we make to this string.
*/
private UnicodeString cloneStringIfRequired() {
if (book == null)
@ -169,10 +169,25 @@ public class HSSFRichTextString
return string.getString();
}
/** Used internally by the HSSFCell to get the internal string value*/
/**
* Used internally by the HSSFCell to get the internal
* string value.
* Will ensure the string is not shared
*/
UnicodeString getUnicodeString() {
return cloneStringIfRequired();
}
/**
* Returns the raw, probably shared Unicode String.
* Used when tweaking the styles, eg updating font
* positions.
* Changes to this string may well effect
* other RichTextStrings too!
*/
UnicodeString getRawUnicodeString() {
return string;
}
/** Used internally by the HSSFCell to set the internal string value*/
void setUnicodeString(UnicodeString str) {

View File

@ -1094,6 +1094,16 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
return retval;
}
/**
* Reset the fonts cache, causing all new calls
* to getFontAt() to create new objects.
* Should only be called after deleting fonts,
* and that's not something you should normally do
*/
protected void resetFontCache() {
fonts = new Hashtable();
}
/**
* create a new Cell style and add it to the workbook's style table

View File

@ -32,6 +32,7 @@ public final class TestWorkbook extends TestCase {
Workbook wb = (new HW()).getWorkbook();
assertEquals(4, wb.getNumberOfFontRecords());
assertEquals(68, wb.getRecords().size());
FontRecord f1 = wb.getFontRecordAt(0);
FontRecord f4 = wb.getFontRecordAt(3);
@ -45,9 +46,41 @@ public final class TestWorkbook extends TestCase {
// There is no 4! new ones go in at 5
FontRecord n = wb.createNewFont();
assertEquals(69, wb.getRecords().size());
assertEquals(5, wb.getNumberOfFontRecords());
assertEquals(5, wb.getFontIndex(n));
assertEquals(n, wb.getFontRecordAt(5));
// And another
FontRecord n6 = wb.createNewFont();
assertEquals(70, wb.getRecords().size());
assertEquals(6, wb.getNumberOfFontRecords());
assertEquals(6, wb.getFontIndex(n6));
assertEquals(n6, wb.getFontRecordAt(6));
// Now remove the one formerly at 5
assertEquals(70, wb.getRecords().size());
wb.removeFontRecord(n);
// Check that 6 has gone to 5
assertEquals(69, wb.getRecords().size());
assertEquals(5, wb.getNumberOfFontRecords());
assertEquals(5, wb.getFontIndex(n6));
assertEquals(n6, wb.getFontRecordAt(5));
// Check that the earlier ones are unchanged
assertEquals(0, wb.getFontIndex(f1));
assertEquals(3, wb.getFontIndex(f4));
assertEquals(f1, wb.getFontRecordAt(0));
assertEquals(f4, wb.getFontRecordAt(3));
// Finally, add another one
FontRecord n7 = wb.createNewFont();
assertEquals(70, wb.getRecords().size());
assertEquals(6, wb.getNumberOfFontRecords());
assertEquals(6, wb.getFontIndex(n7));
assertEquals(n7, wb.getFontRecordAt(6));
}
private class HW extends HSSFWorkbook {

View File

@ -121,4 +121,21 @@ public class TestFontRecord
for (int i = 0; i < data.length; i++)
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
}
public void testSameProperties() throws Exception {
FontRecord f1 = new FontRecord(new TestcaseRecordInputStream((short)0x31, (short)data.length, data));
FontRecord f2 = new FontRecord(new TestcaseRecordInputStream((short)0x31, (short)data.length, data));
assertTrue(f1.sameProperties(f2));
f2.setFontName("Arial2");
assertFalse(f1.sameProperties(f2));
f2.setFontName("Arial");
assertTrue(f1.sameProperties(f2));
f2.setFontHeight((short)11);
assertFalse(f1.sameProperties(f2));
f2.setFontHeight((short)0xc8);
assertTrue(f1.sameProperties(f2));
}
}

View File

@ -47,6 +47,7 @@ public class AllUserModelTests {
result.addTestSuite(TestHSSFDateUtil.class);
result.addTestSuite(TestHSSFHeaderFooter.class);
result.addTestSuite(TestHSSFHyperlink.class);
result.addTestSuite(TestHSSFOptimiser.class);
result.addTestSuite(TestHSSFPalette.class);
result.addTestSuite(TestHSSFPatriarch.class);
result.addTestSuite(TestHSSFPicture.class);

View File

@ -0,0 +1,240 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
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.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.model.Workbook;
import junit.framework.TestCase;
public class TestHSSFOptimiser extends TestCase {
public void testDoesNoHarmIfNothingToDo() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFFont f = wb.createFont();
f.setFontName("Testing");
HSSFCellStyle s = wb.createCellStyle();
s.setFont(f);
assertEquals(5, wb.getNumberOfFonts());
assertEquals(22, wb.getNumCellStyles());
// Optimise fonts
HSSFOptimiser.optimiseFonts(wb);
assertEquals(5, wb.getNumberOfFonts());
assertEquals(22, wb.getNumCellStyles());
assertEquals(f, s.getFont(wb));
// Optimise styles
HSSFOptimiser.optimiseCellStyles(wb);
assertEquals(5, wb.getNumberOfFonts());
assertEquals(22, wb.getNumCellStyles());
assertEquals(f, s.getFont(wb));
}
public void testOptimiseFonts() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook();
// Add 6 fonts, some duplicates
HSSFFont f1 = wb.createFont();
f1.setFontHeight((short)11);
f1.setFontName("Testing");
HSSFFont f2 = wb.createFont();
f2.setFontHeight((short)22);
f2.setFontName("Also Testing");
HSSFFont f3 = wb.createFont();
f3.setFontHeight((short)33);
f3.setFontName("Unique");
HSSFFont f4 = wb.createFont();
f4.setFontHeight((short)11);
f4.setFontName("Testing");
HSSFFont f5 = wb.createFont();
f5.setFontHeight((short)22);
f5.setFontName("Also Testing");
HSSFFont f6 = wb.createFont();
f6.setFontHeight((short)66);
f6.setFontName("Also Unique");
// Use all three of the four in cell styles
assertEquals(21, wb.getNumCellStyles());
HSSFCellStyle cs1 = wb.createCellStyle();
cs1.setFont(f1);
assertEquals(5, cs1.getFontIndex());
HSSFCellStyle cs2 = wb.createCellStyle();
cs2.setFont(f4);
assertEquals(8, cs2.getFontIndex());
HSSFCellStyle cs3 = wb.createCellStyle();
cs3.setFont(f5);
assertEquals(9, cs3.getFontIndex());
HSSFCellStyle cs4 = wb.createCellStyle();
cs4.setFont(f6);
assertEquals(10, cs4.getFontIndex());
assertEquals(25, wb.getNumCellStyles());
// And three in rich text
HSSFSheet s = wb.createSheet();
HSSFRow r = s.createRow(0);
HSSFRichTextString rtr1 = new HSSFRichTextString("Test");
rtr1.applyFont(0, 2, f1);
rtr1.applyFont(3, 4, f2);
r.createCell((short)0).setCellValue(rtr1);
HSSFRichTextString rtr2 = new HSSFRichTextString("AlsoTest");
rtr2.applyFont(0, 2, f3);
rtr2.applyFont(3, 5, f5);
rtr2.applyFont(6, 8, f6);
r.createCell((short)1).setCellValue(rtr2);
// Check what we have now
assertEquals(10, wb.getNumberOfFonts());
assertEquals(25, wb.getNumCellStyles());
// Optimise
HSSFOptimiser.optimiseFonts(wb);
// Check font count
assertEquals(8, wb.getNumberOfFonts());
assertEquals(25, wb.getNumCellStyles());
// Check font use in cell styles
assertEquals(5, cs1.getFontIndex());
assertEquals(5, cs2.getFontIndex()); // duplicate of 1
assertEquals(6, cs3.getFontIndex()); // duplicate of 2
assertEquals(8, cs4.getFontIndex()); // two have gone
// And in rich text
// RTR 1 had f1 and f2, unchanged
assertEquals(5, r.getCell(0).getRichStringCellValue().getFontAtIndex(0));
assertEquals(5, r.getCell(0).getRichStringCellValue().getFontAtIndex(1));
assertEquals(6, r.getCell(0).getRichStringCellValue().getFontAtIndex(3));
assertEquals(6, r.getCell(0).getRichStringCellValue().getFontAtIndex(4));
// RTR 2 had f3 (unchanged), f5 (=f2) and f6 (moved down)
assertEquals(7, r.getCell(1).getRichStringCellValue().getFontAtIndex(0));
assertEquals(7, r.getCell(1).getRichStringCellValue().getFontAtIndex(1));
assertEquals(6, r.getCell(1).getRichStringCellValue().getFontAtIndex(3));
assertEquals(6, r.getCell(1).getRichStringCellValue().getFontAtIndex(4));
assertEquals(8, r.getCell(1).getRichStringCellValue().getFontAtIndex(6));
assertEquals(8, r.getCell(1).getRichStringCellValue().getFontAtIndex(7));
}
public void testOptimiseStyles() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook();
// Two fonts
assertEquals(4, wb.getNumberOfFonts());
HSSFFont f1 = wb.createFont();
f1.setFontHeight((short)11);
f1.setFontName("Testing");
HSSFFont f2 = wb.createFont();
f2.setFontHeight((short)22);
f2.setFontName("Also Testing");
assertEquals(6, wb.getNumberOfFonts());
// Several styles
assertEquals(21, wb.getNumCellStyles());
HSSFCellStyle cs1 = wb.createCellStyle();
cs1.setFont(f1);
HSSFCellStyle cs2 = wb.createCellStyle();
cs2.setFont(f2);
HSSFCellStyle cs3 = wb.createCellStyle();
cs3.setFont(f1);
HSSFCellStyle cs4 = wb.createCellStyle();
cs4.setFont(f1);
cs4.setAlignment((short)22);
HSSFCellStyle cs5 = wb.createCellStyle();
cs5.setFont(f2);
cs5.setAlignment((short)111);
HSSFCellStyle cs6 = wb.createCellStyle();
cs6.setFont(f2);
assertEquals(27, wb.getNumCellStyles());
// Use them
HSSFSheet s = wb.createSheet();
HSSFRow r = s.createRow(0);
r.createCell((short)0).setCellStyle(cs1);
r.createCell((short)1).setCellStyle(cs2);
r.createCell((short)2).setCellStyle(cs3);
r.createCell((short)3).setCellStyle(cs4);
r.createCell((short)4).setCellStyle(cs5);
r.createCell((short)5).setCellStyle(cs6);
r.createCell((short)6).setCellStyle(cs1);
r.createCell((short)7).setCellStyle(cs2);
assertEquals(21, r.getCell(0).getCellValueRecord().getXFIndex());
assertEquals(26, r.getCell(5).getCellValueRecord().getXFIndex());
assertEquals(21, r.getCell(6).getCellValueRecord().getXFIndex());
// Optimise
HSSFOptimiser.optimiseCellStyles(wb);
// Check
assertEquals(6, wb.getNumberOfFonts());
assertEquals(25, wb.getNumCellStyles());
// cs1 -> 21
assertEquals(21, r.getCell(0).getCellValueRecord().getXFIndex());
// cs2 -> 22
assertEquals(22, r.getCell(1).getCellValueRecord().getXFIndex());
// cs3 = cs1 -> 21
assertEquals(21, r.getCell(2).getCellValueRecord().getXFIndex());
// cs4 --> 24 -> 23
assertEquals(23, r.getCell(3).getCellValueRecord().getXFIndex());
// cs5 --> 25 -> 24
assertEquals(24, r.getCell(4).getCellValueRecord().getXFIndex());
// cs6 = cs2 -> 22
assertEquals(22, r.getCell(5).getCellValueRecord().getXFIndex());
// cs1 -> 21
assertEquals(21, r.getCell(6).getCellValueRecord().getXFIndex());
// cs2 -> 22
assertEquals(22, r.getCell(7).getCellValueRecord().getXFIndex());
}
}