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:
parent
b3e2a14d9a
commit
e09aa6d363
@ -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>
|
<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>
|
||||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
<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="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">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>
|
<action dev="POI-DEVELOPERS" type="add">44958 - Record level support for Data Tables. (No formula parser support though)</action>
|
||||||
|
@ -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>
|
<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>
|
||||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
<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="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">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>
|
<action dev="POI-DEVELOPERS" type="add">44958 - Record level support for Data Tables. (No formula parser support though)</action>
|
||||||
|
@ -443,6 +443,17 @@ public class Workbook implements Model
|
|||||||
numfonts++;
|
numfonts++;
|
||||||
return rec;
|
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
|
* gets the number of font records
|
||||||
@ -702,6 +713,18 @@ public class Workbook implements Model
|
|||||||
|
|
||||||
return retval;
|
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
|
* creates a new Cell-type Extneded Format Record and adds it to the end of
|
||||||
|
@ -579,6 +579,31 @@ public class FontRecord
|
|||||||
result = prime * result + field_10_font_name_len;
|
result = prime * result + field_10_font_name_len;
|
||||||
return result;
|
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 -
|
* Only returns two for the same exact object -
|
||||||
|
@ -439,6 +439,23 @@ public class UnicodeString
|
|||||||
this.field_5_ext_rst = ext_rst;
|
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
|
* unlike the real records we return the same as "getString()" rather than debug info
|
||||||
* @see #getDebugInfo()
|
* @see #getDebugInfo()
|
||||||
|
@ -938,14 +938,13 @@ public class HSSFCell implements Cell
|
|||||||
* object.
|
* object.
|
||||||
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(short)
|
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(short)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public HSSFCellStyle getCellStyle()
|
public HSSFCellStyle getCellStyle()
|
||||||
{
|
{
|
||||||
short styleIndex=record.getXFIndex();
|
short styleIndex=record.getXFIndex();
|
||||||
ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex);
|
ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex);
|
||||||
return new HSSFCellStyle(styleIndex, xf, book);
|
return new HSSFCellStyle(styleIndex, xf, book);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used for internationalization, currently -1 for unchanged, 0 for compressed unicode or 1 for 16-bit
|
* used for internationalization, currently -1 for unchanged, 0 for compressed unicode or 1 for 16-bit
|
||||||
*
|
*
|
||||||
|
261
src/java/org/apache/poi/hssf/usermodel/HSSFOptimiser.java
Normal file
261
src/java/org/apache/poi/hssf/usermodel/HSSFOptimiser.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -69,7 +69,7 @@ public class HSSFRichTextString
|
|||||||
|
|
||||||
/** Called whenever the unicode string is modified. When it is modified
|
/** 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
|
* 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() {
|
private UnicodeString cloneStringIfRequired() {
|
||||||
if (book == null)
|
if (book == null)
|
||||||
@ -169,10 +169,25 @@ public class HSSFRichTextString
|
|||||||
return string.getString();
|
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() {
|
UnicodeString getUnicodeString() {
|
||||||
return cloneStringIfRequired();
|
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*/
|
/** Used internally by the HSSFCell to set the internal string value*/
|
||||||
void setUnicodeString(UnicodeString str) {
|
void setUnicodeString(UnicodeString str) {
|
||||||
|
@ -1094,6 +1094,16 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||||||
|
|
||||||
return retval;
|
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
|
* create a new Cell style and add it to the workbook's style table
|
||||||
|
@ -32,6 +32,7 @@ public final class TestWorkbook extends TestCase {
|
|||||||
Workbook wb = (new HW()).getWorkbook();
|
Workbook wb = (new HW()).getWorkbook();
|
||||||
|
|
||||||
assertEquals(4, wb.getNumberOfFontRecords());
|
assertEquals(4, wb.getNumberOfFontRecords());
|
||||||
|
assertEquals(68, wb.getRecords().size());
|
||||||
|
|
||||||
FontRecord f1 = wb.getFontRecordAt(0);
|
FontRecord f1 = wb.getFontRecordAt(0);
|
||||||
FontRecord f4 = wb.getFontRecordAt(3);
|
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
|
// There is no 4! new ones go in at 5
|
||||||
|
|
||||||
FontRecord n = wb.createNewFont();
|
FontRecord n = wb.createNewFont();
|
||||||
|
assertEquals(69, wb.getRecords().size());
|
||||||
assertEquals(5, wb.getNumberOfFontRecords());
|
assertEquals(5, wb.getNumberOfFontRecords());
|
||||||
assertEquals(5, wb.getFontIndex(n));
|
assertEquals(5, wb.getFontIndex(n));
|
||||||
assertEquals(n, wb.getFontRecordAt(5));
|
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 {
|
private class HW extends HSSFWorkbook {
|
||||||
|
@ -121,4 +121,21 @@ public class TestFontRecord
|
|||||||
for (int i = 0; i < data.length; i++)
|
for (int i = 0; i < data.length; i++)
|
||||||
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ public class AllUserModelTests {
|
|||||||
result.addTestSuite(TestHSSFDateUtil.class);
|
result.addTestSuite(TestHSSFDateUtil.class);
|
||||||
result.addTestSuite(TestHSSFHeaderFooter.class);
|
result.addTestSuite(TestHSSFHeaderFooter.class);
|
||||||
result.addTestSuite(TestHSSFHyperlink.class);
|
result.addTestSuite(TestHSSFHyperlink.class);
|
||||||
|
result.addTestSuite(TestHSSFOptimiser.class);
|
||||||
result.addTestSuite(TestHSSFPalette.class);
|
result.addTestSuite(TestHSSFPalette.class);
|
||||||
result.addTestSuite(TestHSSFPatriarch.class);
|
result.addTestSuite(TestHSSFPatriarch.class);
|
||||||
result.addTestSuite(TestHSSFPicture.class);
|
result.addTestSuite(TestHSSFPicture.class);
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user