mirror of https://github.com/apache/poi.git
Bugzilla 47244 - Fixed HSSFSheet to handle missing header / footer records
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@781645 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
279211b52d
commit
40e6ccd12e
|
@ -35,6 +35,7 @@
|
||||||
<release version="3.5-beta7" date="2009-??-??">
|
<release version="3.5-beta7" date="2009-??-??">
|
||||||
</release>
|
</release>
|
||||||
<release version="3.5-beta6" date="2009-06-11">
|
<release version="3.5-beta6" date="2009-06-11">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">47244 - Fixed HSSFSheet to handle missing header / footer records</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">47312 - Fixed formula parser to properly reject cell references with a '0' row component</action>
|
<action dev="POI-DEVELOPERS" type="fix">47312 - Fixed formula parser to properly reject cell references with a '0' row component</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">47199 - Fixed PageSettingsBlock/Sheet to tolerate margin records after other non-PSB records</action>
|
<action dev="POI-DEVELOPERS" type="fix">47199 - Fixed PageSettingsBlock/Sheet to tolerate margin records after other non-PSB records</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">47069 - Fixed HSSFSheet#getFirstRowNum and HSSFSheet#getLastRowNum to return correct values after removal of all rows</action>
|
<action dev="POI-DEVELOPERS" type="fix">47069 - Fixed HSSFSheet#getFirstRowNum and HSSFSheet#getLastRowNum to return correct values after removal of all rows</action>
|
||||||
|
|
|
@ -293,10 +293,8 @@ public class ExcelExtractor extends POIOLE2TextExtractor implements org.apache.p
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header text, if there is any
|
// Header text, if there is any
|
||||||
if(_includeHeadersFooters && sheet.getHeader() != null) {
|
if(_includeHeadersFooters) {
|
||||||
text.append(
|
text.append(_extractHeaderFooter(sheet.getHeader()));
|
||||||
_extractHeaderFooter(sheet.getHeader())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int firstRow = sheet.getFirstRowNum();
|
int firstRow = sheet.getFirstRowNum();
|
||||||
|
@ -382,11 +380,9 @@ public class ExcelExtractor extends POIOLE2TextExtractor implements org.apache.p
|
||||||
text.append("\n");
|
text.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally Feader text, if there is any
|
// Finally Footer text, if there is any
|
||||||
if(_includeHeadersFooters && sheet.getFooter() != null) {
|
if(_includeHeadersFooters) {
|
||||||
text.append(
|
text.append(_extractHeaderFooter(sheet.getFooter()));
|
||||||
_extractHeaderFooter(sheet.getFooter())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,48 +27,30 @@ package org.apache.poi.hssf.record;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final class FooterRecord extends HeaderFooterBase {
|
public final class FooterRecord extends HeaderFooterBase {
|
||||||
public final static short sid = 0x0015;
|
public final static short sid = 0x0015;
|
||||||
|
|
||||||
public FooterRecord(String text) {
|
public FooterRecord(String text) {
|
||||||
super(text);
|
super(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FooterRecord(RecordInputStream in) {
|
public FooterRecord(RecordInputStream in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String toString() {
|
||||||
* set the footer string
|
StringBuffer buffer = new StringBuffer();
|
||||||
*
|
|
||||||
* @param footer string to display
|
|
||||||
*/
|
|
||||||
public void setFooter(String footer) {
|
|
||||||
setText(footer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
buffer.append("[FOOTER]\n");
|
||||||
* get the footer string
|
buffer.append(" .footer = ").append(getText()).append("\n");
|
||||||
*
|
buffer.append("[/FOOTER]\n");
|
||||||
* @return footer string to display
|
return buffer.toString();
|
||||||
*/
|
}
|
||||||
public String getFooter() {
|
|
||||||
return getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public short getSid() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
buffer.append("[FOOTER]\n");
|
public Object clone() {
|
||||||
buffer.append(" .footer = ").append(getText()).append("\n");
|
return new FooterRecord(getText());
|
||||||
buffer.append("[/FOOTER]\n");
|
}
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSid() {
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone() {
|
|
||||||
return new FooterRecord(getText());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.apache.poi.util.StringUtil;
|
||||||
*
|
*
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
abstract class HeaderFooterBase extends StandardRecord {
|
public abstract class HeaderFooterBase extends StandardRecord {
|
||||||
private boolean field_2_hasMultibyte;
|
private boolean field_2_hasMultibyte;
|
||||||
private String field_3_text;
|
private String field_3_text;
|
||||||
|
|
||||||
|
@ -44,7 +44,8 @@ abstract class HeaderFooterBase extends StandardRecord {
|
||||||
field_3_text = in.readCompressedUnicode(field_1_footer_len);
|
field_3_text = in.readCompressedUnicode(field_1_footer_len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Note - this is unusual: when the text is empty string, the whole record is empty (just the 4 byte BIFF header)
|
// Note - this is unusual for BIFF records in general, but normal for header / footer records:
|
||||||
|
// when the text is empty string, the whole record is empty (just the 4 byte BIFF header)
|
||||||
field_3_text = "";
|
field_3_text = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,16 +63,9 @@ abstract class HeaderFooterBase extends StandardRecord {
|
||||||
field_3_text = text;
|
field_3_text = text;
|
||||||
|
|
||||||
// Check it'll fit into the space in the record
|
// Check it'll fit into the space in the record
|
||||||
if (field_2_hasMultibyte) {
|
if (getDataSize() > RecordInputStream.MAX_RECORD_DATA_SIZE) {
|
||||||
if (field_3_text.length() > 127) {
|
throw new IllegalArgumentException("Header/Footer string too long (limit is "
|
||||||
throw new IllegalArgumentException(
|
+ RecordInputStream.MAX_RECORD_DATA_SIZE + " bytes)");
|
||||||
"Footer string too long (limit is 127 for unicode strings)");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (field_3_text.length() > 255) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Footer string too long (limit is 255 for non-unicode strings)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title: Header Record<P>
|
* Title: Header Record<P>
|
||||||
* Description: Specifies a header for a sheet<P>
|
* Description: Specifies a header for a sheet<P>
|
||||||
|
@ -27,49 +26,30 @@ package org.apache.poi.hssf.record;
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public final class HeaderRecord extends HeaderFooterBase {
|
public final class HeaderRecord extends HeaderFooterBase {
|
||||||
public final static short sid = 0x0014;
|
public final static short sid = 0x0014;
|
||||||
|
|
||||||
public HeaderRecord(String text) {
|
public HeaderRecord(String text) {
|
||||||
super(text);
|
super(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeaderRecord(RecordInputStream in) {
|
public HeaderRecord(RecordInputStream in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String toString() {
|
||||||
* set the header string
|
StringBuffer buffer = new StringBuffer();
|
||||||
*
|
|
||||||
* @param header string to display
|
|
||||||
*/
|
|
||||||
public void setHeader(String header) {
|
|
||||||
setText(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
buffer.append("[HEADER]\n");
|
||||||
* get the header string
|
buffer.append(" .header = ").append(getText()).append("\n");
|
||||||
*
|
buffer.append("[/HEADER]\n");
|
||||||
* @return header string to display
|
return buffer.toString();
|
||||||
*/
|
}
|
||||||
public String getHeader() {
|
|
||||||
return getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public short getSid() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
buffer.append("[HEADER]\n");
|
public Object clone() {
|
||||||
buffer.append(" .header = ").append(getText()).append("\n");
|
return new HeaderRecord(getText());
|
||||||
buffer.append("[/HEADER]\n");
|
}
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public short getSid() {
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone() {
|
|
||||||
return new HeaderRecord(getText());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,10 +239,21 @@ public final class PageSettingsBlock extends RecordAggregate {
|
||||||
|
|
||||||
|
|
||||||
public void visitContainedRecords(RecordVisitor rv) {
|
public void visitContainedRecords(RecordVisitor rv) {
|
||||||
|
// Replicates record order from Excel 2007, though this is not critical
|
||||||
|
|
||||||
visitIfPresent(_rowBreaksRecord, rv);
|
visitIfPresent(_rowBreaksRecord, rv);
|
||||||
visitIfPresent(_columnBreaksRecord, rv);
|
visitIfPresent(_columnBreaksRecord, rv);
|
||||||
visitIfPresent(_header, rv);
|
// Write out empty header / footer records if these are missing
|
||||||
visitIfPresent(_footer, rv);
|
if (_header == null) {
|
||||||
|
rv.visitRecord(new HeaderRecord(""));
|
||||||
|
} else {
|
||||||
|
rv.visitRecord(_header);
|
||||||
|
}
|
||||||
|
if (_footer == null) {
|
||||||
|
rv.visitRecord(new FooterRecord(""));
|
||||||
|
} else {
|
||||||
|
rv.visitRecord(_footer);
|
||||||
|
}
|
||||||
visitIfPresent(_hCenter, rv);
|
visitIfPresent(_hCenter, rv);
|
||||||
visitIfPresent(_vCenter, rv);
|
visitIfPresent(_vCenter, rv);
|
||||||
visitIfPresent(_leftMargin, rv);
|
visitIfPresent(_leftMargin, rv);
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.FooterRecord;
|
import org.apache.poi.hssf.record.FooterRecord;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||||
import org.apache.poi.ss.usermodel.Footer;
|
import org.apache.poi.ss.usermodel.Footer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,59 +33,29 @@ import org.apache.poi.ss.usermodel.Footer;
|
||||||
* <P>
|
* <P>
|
||||||
* @author Shawn Laubach (slaubach at apache dot org)
|
* @author Shawn Laubach (slaubach at apache dot org)
|
||||||
*/
|
*/
|
||||||
public class HSSFFooter extends HeaderFooter implements Footer {
|
public final class HSSFFooter extends HeaderFooter implements Footer {
|
||||||
private FooterRecord footerRecord;
|
private final PageSettingsBlock _psb;
|
||||||
|
|
||||||
/**
|
protected HSSFFooter(PageSettingsBlock psb) {
|
||||||
* Constructor. Creates a new footer interface from a footer record
|
_psb = psb;
|
||||||
* @param footerRecord Footer record to create the footer with
|
}
|
||||||
*/
|
|
||||||
protected HSSFFooter(FooterRecord footerRecord) {
|
|
||||||
super(footerRecord.getFooter());
|
|
||||||
this.footerRecord = footerRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
protected String getRawText() {
|
||||||
* Sets the left string.
|
FooterRecord hf = _psb.getFooter();
|
||||||
* @param newLeft The string to set as the left side.
|
if (hf == null) {
|
||||||
*/
|
return "";
|
||||||
public void setLeft(String newLeft) {
|
}
|
||||||
left = newLeft;
|
return hf.getText();
|
||||||
createFooterString();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the center string.
|
protected void setHeaderFooterText(String text) {
|
||||||
* @param newCenter The string to set as the center.
|
FooterRecord hfr = _psb.getFooter();
|
||||||
*/
|
if (hfr == null) {
|
||||||
public void setCenter(String newCenter) {
|
hfr = new FooterRecord(text);
|
||||||
center = newCenter;
|
_psb.setFooter(hfr);
|
||||||
createFooterString();
|
} else {
|
||||||
}
|
hfr.setText(text);
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Sets the right string.
|
|
||||||
* @param newRight The string to set as the right side.
|
|
||||||
*/
|
|
||||||
public void setRight(String newRight) {
|
|
||||||
right = newRight;
|
|
||||||
createFooterString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getRawFooter() {
|
|
||||||
return footerRecord.getFooter();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the complete footer string based on the left, center, and middle
|
|
||||||
* strings.
|
|
||||||
*/
|
|
||||||
private void createFooterString() {
|
|
||||||
footerRecord.setFooter(
|
|
||||||
"&C" + (center == null ? "" : center) +
|
|
||||||
"&L" + (left == null ? "" : left) +
|
|
||||||
"&R" + (right == null ? "" : right));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.HeaderRecord;
|
import org.apache.poi.hssf.record.HeaderRecord;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||||
import org.apache.poi.ss.usermodel.Header;
|
import org.apache.poi.ss.usermodel.Header;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,66 +34,30 @@ import org.apache.poi.ss.usermodel.Header;
|
||||||
*
|
*
|
||||||
* @author Shawn Laubach (slaubach at apache dot org)
|
* @author Shawn Laubach (slaubach at apache dot org)
|
||||||
*/
|
*/
|
||||||
public class HSSFHeader extends HeaderFooter implements Header {
|
public final class HSSFHeader extends HeaderFooter implements Header {
|
||||||
private HeaderRecord headerRecord;
|
|
||||||
|
|
||||||
/**
|
private final PageSettingsBlock _psb;
|
||||||
* Constructor. Creates a new header interface from a header record
|
|
||||||
*
|
|
||||||
* @param headerRecord Header record to create the header with
|
|
||||||
*/
|
|
||||||
protected HSSFHeader( HeaderRecord headerRecord ) {
|
|
||||||
super(headerRecord.getHeader());
|
|
||||||
this.headerRecord = headerRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
protected HSSFHeader(PageSettingsBlock psb) {
|
||||||
* Sets the left string.
|
_psb = psb;
|
||||||
*
|
}
|
||||||
* @param newLeft The string to set as the left side.
|
|
||||||
*/
|
|
||||||
public void setLeft( String newLeft )
|
|
||||||
{
|
|
||||||
left = newLeft;
|
|
||||||
createHeaderString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
protected String getRawText() {
|
||||||
* Sets the center string.
|
HeaderRecord hf = _psb.getHeader();
|
||||||
*
|
if (hf == null) {
|
||||||
* @param newCenter The string to set as the center.
|
return "";
|
||||||
*/
|
}
|
||||||
public void setCenter( String newCenter )
|
return hf.getText();
|
||||||
{
|
}
|
||||||
center = newCenter;
|
|
||||||
createHeaderString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the right string.
|
|
||||||
*
|
|
||||||
* @param newRight The string to set as the right side.
|
|
||||||
*/
|
|
||||||
public void setRight( String newRight )
|
|
||||||
{
|
|
||||||
right = newRight;
|
|
||||||
createHeaderString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getRawHeader() {
|
|
||||||
return headerRecord.getHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the complete header string based on the left, center, and middle
|
|
||||||
* strings.
|
|
||||||
*/
|
|
||||||
private void createHeaderString()
|
|
||||||
{
|
|
||||||
headerRecord.setHeader( "&C" + ( center == null ? "" : center ) +
|
|
||||||
"&L" + ( left == null ? "" : left ) +
|
|
||||||
"&R" + ( right == null ? "" : right ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setHeaderFooterText(String text) {
|
||||||
|
HeaderRecord hfr = _psb.getHeader();
|
||||||
|
if (hfr == null) {
|
||||||
|
hfr = new HeaderRecord(text);
|
||||||
|
_psb.setHeader(hfr);
|
||||||
|
} else {
|
||||||
|
hfr.setText(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -913,20 +913,12 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
||||||
return new HSSFPrintSetup(_sheet.getPageSettings().getPrintSetup());
|
return new HSSFPrintSetup(_sheet.getPageSettings().getPrintSetup());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the user model for the document header.
|
|
||||||
* @return The Document header.
|
|
||||||
*/
|
|
||||||
public HSSFHeader getHeader() {
|
public HSSFHeader getHeader() {
|
||||||
return new HSSFHeader(_sheet.getPageSettings().getHeader());
|
return new HSSFHeader(_sheet.getPageSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the user model for the document footer.
|
|
||||||
* @return The Document footer.
|
|
||||||
*/
|
|
||||||
public HSSFFooter getFooter() {
|
public HSSFFooter getFooter() {
|
||||||
return new HSSFFooter(_sheet.getPageSettings().getFooter());
|
return new HSSFFooter(_sheet.getPageSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,318 +14,325 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common class for {@link HSSFHeader} and
|
* Common class for {@link HSSFHeader} and {@link HSSFFooter}.
|
||||||
* {@link HSSFFooter}.
|
|
||||||
*/
|
*/
|
||||||
public abstract class HeaderFooter implements org.apache.poi.ss.usermodel.HeaderFooter {
|
public abstract class HeaderFooter implements org.apache.poi.ss.usermodel.HeaderFooter {
|
||||||
protected String left;
|
|
||||||
protected String center;
|
|
||||||
protected String right;
|
|
||||||
|
|
||||||
private boolean stripFields = false;
|
protected HeaderFooter() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
protected HeaderFooter(String text) {
|
/**
|
||||||
while (text != null && text.length() > 1) {
|
* @return the internal text representation (combining center, left and right parts).
|
||||||
int pos = text.length();
|
* Possibly empty string if no header or footer is set. Never <code>null</code>.
|
||||||
switch (text.substring(1, 2).charAt(0)) {
|
*/
|
||||||
case 'L' :
|
protected abstract String getRawText();
|
||||||
|
|
||||||
|
private String[] splitParts() {
|
||||||
|
String text = getRawText();
|
||||||
|
// default values
|
||||||
|
String _left = "";
|
||||||
|
String _center = "";
|
||||||
|
String _right = "";
|
||||||
|
|
||||||
|
while (text.length() > 1) {
|
||||||
|
int pos = text.length();
|
||||||
|
switch (text.charAt(1)) {
|
||||||
|
case 'L':
|
||||||
if (text.indexOf("&C") >= 0) {
|
if (text.indexOf("&C") >= 0) {
|
||||||
pos = Math.min(pos, text.indexOf("&C"));
|
pos = Math.min(pos, text.indexOf("&C"));
|
||||||
}
|
}
|
||||||
if (text.indexOf("&R") >= 0) {
|
if (text.indexOf("&R") >= 0) {
|
||||||
pos = Math.min(pos, text.indexOf("&R"));
|
pos = Math.min(pos, text.indexOf("&R"));
|
||||||
}
|
}
|
||||||
left = text.substring(2, pos);
|
_left = text.substring(2, pos);
|
||||||
text = text.substring(pos);
|
text = text.substring(pos);
|
||||||
break;
|
break;
|
||||||
case 'C' :
|
case 'C':
|
||||||
if (text.indexOf("&L") >= 0) {
|
if (text.indexOf("&L") >= 0) {
|
||||||
pos = Math.min(pos, text.indexOf("&L"));
|
pos = Math.min(pos, text.indexOf("&L"));
|
||||||
}
|
}
|
||||||
if (text.indexOf("&R") >= 0) {
|
if (text.indexOf("&R") >= 0) {
|
||||||
pos = Math.min(pos, text.indexOf("&R"));
|
pos = Math.min(pos, text.indexOf("&R"));
|
||||||
}
|
}
|
||||||
center = text.substring(2, pos);
|
_center = text.substring(2, pos);
|
||||||
text = text.substring(pos);
|
text = text.substring(pos);
|
||||||
break;
|
break;
|
||||||
case 'R' :
|
case 'R':
|
||||||
if (text.indexOf("&C") >= 0) {
|
if (text.indexOf("&C") >= 0) {
|
||||||
pos = Math.min(pos, text.indexOf("&C"));
|
pos = Math.min(pos, text.indexOf("&C"));
|
||||||
}
|
}
|
||||||
if (text.indexOf("&L") >= 0) {
|
if (text.indexOf("&L") >= 0) {
|
||||||
pos = Math.min(pos, text.indexOf("&L"));
|
pos = Math.min(pos, text.indexOf("&L"));
|
||||||
}
|
}
|
||||||
right = text.substring(2, pos);
|
_right = text.substring(2, pos);
|
||||||
text = text.substring(pos);
|
text = text.substring(pos);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
text = null;
|
throw new IllegalStateException("bad text '" + getRawText() + "'.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return new String[] { _left, _center, _right, };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the left side of the header or footer.
|
||||||
|
*/
|
||||||
|
public final String getLeft() {
|
||||||
|
return splitParts()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param newLeft The string to set as the left side.
|
||||||
|
*/
|
||||||
|
public final void setLeft(String newLeft) {
|
||||||
|
updatePart(0, newLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the center of the header or footer.
|
||||||
|
*/
|
||||||
|
public final String getCenter() {
|
||||||
|
return splitParts()[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param newCenter The string to set as the center.
|
||||||
|
*/
|
||||||
|
public final void setCenter(String newCenter) {
|
||||||
|
updatePart(1, newCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The right side of the header or footer.
|
||||||
|
*/
|
||||||
|
public final String getRight() {
|
||||||
|
return splitParts()[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param newRight The string to set as the right side.
|
||||||
|
*/
|
||||||
|
public final void setRight(String newRight) {
|
||||||
|
updatePart(2, newRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePart(int partIndex, String newValue) {
|
||||||
|
String[] parts = splitParts();
|
||||||
|
parts[partIndex] = newValue == null ? "" : newValue;
|
||||||
|
updateHeaderFooterText(parts);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates the complete footer string based on the left, center, and middle
|
||||||
|
* strings.
|
||||||
|
*/
|
||||||
|
private void updateHeaderFooterText(String[] parts) {
|
||||||
|
String _left = parts[0];
|
||||||
|
String _center = parts[1];
|
||||||
|
String _right = parts[2];
|
||||||
|
|
||||||
|
if (_center.length() < 1 && _left.length() < 1 && _right.length() < 1) {
|
||||||
|
setHeaderFooterText("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder(64);
|
||||||
|
sb.append("&C");
|
||||||
|
sb.append(_center);
|
||||||
|
sb.append("&L");
|
||||||
|
sb.append(_left);
|
||||||
|
sb.append("&R");
|
||||||
|
sb.append(_right);
|
||||||
|
String text = sb.toString();
|
||||||
|
setHeaderFooterText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param text the new header footer text (contains mark-up tags). Possibly
|
||||||
|
* empty string never <code>null</code>
|
||||||
|
*/
|
||||||
|
protected abstract void setHeaderFooterText(String text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param size
|
||||||
|
* the new font size
|
||||||
|
* @return The mark-up tag representing a new font size
|
||||||
|
*/
|
||||||
|
public static String fontSize(short size) {
|
||||||
|
return "&" + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param font
|
||||||
|
* the new font
|
||||||
|
* @param style
|
||||||
|
* the fonts style, one of regular, italic, bold, italic bold or
|
||||||
|
* bold italic
|
||||||
|
* @return The mark-up tag representing a new font size
|
||||||
|
*/
|
||||||
|
public static String font(String font, String style) {
|
||||||
|
return "&\"" + font + "," + style + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag representing the current page number
|
||||||
|
*/
|
||||||
|
public static String page() {
|
||||||
|
return MarkupTag.PAGE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag representing the number of pages
|
||||||
|
*/
|
||||||
|
public static String numPages() {
|
||||||
|
return MarkupTag.NUM_PAGES_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag representing the current date date
|
||||||
|
*/
|
||||||
|
public static String date() {
|
||||||
|
return MarkupTag.DATE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag representing current time
|
||||||
|
*/
|
||||||
|
public static String time() {
|
||||||
|
return MarkupTag.TIME_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag representing the current file name
|
||||||
|
*/
|
||||||
|
public static String file() {
|
||||||
|
return MarkupTag.FILE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag representing the current tab (sheet) name
|
||||||
|
*/
|
||||||
|
public static String tab() {
|
||||||
|
return MarkupTag.SHEET_NAME_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag for start bold
|
||||||
|
*/
|
||||||
|
public static String startBold() {
|
||||||
|
return MarkupTag.BOLD_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag for end bold
|
||||||
|
*/
|
||||||
|
public static String endBold() {
|
||||||
|
return MarkupTag.BOLD_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag for start underline
|
||||||
|
*/
|
||||||
|
public static String startUnderline() {
|
||||||
|
return MarkupTag.UNDERLINE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag for end underline
|
||||||
|
*/
|
||||||
|
public static String endUnderline() {
|
||||||
|
return MarkupTag.UNDERLINE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag for start double underline
|
||||||
|
*/
|
||||||
|
public static String startDoubleUnderline() {
|
||||||
|
return MarkupTag.DOUBLE_UNDERLINE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The mark-up tag for end double underline
|
||||||
|
*/
|
||||||
|
public static String endDoubleUnderline() {
|
||||||
|
return MarkupTag.DOUBLE_UNDERLINE_FIELD.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes any fields (eg macros, page markers etc) from the string.
|
||||||
|
* Normally used to make some text suitable for showing to humans, and the
|
||||||
|
* resultant text should not normally be saved back into the document!
|
||||||
|
*/
|
||||||
|
public static String stripFields(String pText) {
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
// Check we really got something to work on
|
||||||
|
if (pText == null || pText.length() == 0) {
|
||||||
|
return pText;
|
||||||
|
}
|
||||||
|
|
||||||
|
String text = pText;
|
||||||
|
|
||||||
|
// Firstly, do the easy ones which are static
|
||||||
|
for (MarkupTag mt : MarkupTag.values()) {
|
||||||
|
String seq = mt.getRepresentation();
|
||||||
|
while ((pos = text.indexOf(seq)) > -1) {
|
||||||
|
text = text.substring(0, pos) + text.substring(pos + seq.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now do the tricky, dynamic ones
|
||||||
|
// These are things like font sizes and font names
|
||||||
|
text = text.replaceAll("\\&\\d+", "");
|
||||||
|
text = text.replaceAll("\\&\".*?,.*?\"", "");
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum MarkupTag {
|
||||||
|
SHEET_NAME_FIELD ("&A", false),
|
||||||
|
DATE_FIELD ("&D", false),
|
||||||
|
FILE_FIELD ("&F", false),
|
||||||
|
FULL_FILE_FIELD ("&Z", false),
|
||||||
|
PAGE_FIELD ("&P", false),
|
||||||
|
TIME_FIELD ("&T", false),
|
||||||
|
NUM_PAGES_FIELD ("&N", false),
|
||||||
|
|
||||||
|
PICTURE_FIELD ("&G", false),
|
||||||
|
|
||||||
|
BOLD_FIELD ("&B", true),
|
||||||
|
ITALIC_FIELD ("&I", true),
|
||||||
|
STRIKETHROUGH_FIELD ("&S", true),
|
||||||
|
SUBSCRIPT_FIELD ("&Y", true),
|
||||||
|
SUPERSCRIPT_FIELD ("&X", true),
|
||||||
|
UNDERLINE_FIELD ("&U", true),
|
||||||
|
DOUBLE_UNDERLINE_FIELD ("&E", true),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String _representation;
|
||||||
|
private final boolean _occursInPairs;
|
||||||
|
private MarkupTag(String sequence, boolean occursInPairs) {
|
||||||
|
_representation = sequence;
|
||||||
|
_occursInPairs = occursInPairs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return The character sequence that marks this field
|
||||||
|
*/
|
||||||
|
public String getRepresentation() {
|
||||||
|
return _representation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this markup tag normally comes in a pair, eg turn on
|
||||||
|
* underline / turn off underline
|
||||||
|
*/
|
||||||
|
public boolean occursPairs() {
|
||||||
|
return _occursInPairs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the left side of the header or footer.
|
|
||||||
* @return The string representing the left side.
|
|
||||||
*/
|
|
||||||
public String getLeft() {
|
|
||||||
if(stripFields)
|
|
||||||
return stripFields(left);
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
public abstract void setLeft( String newLeft );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the center of the header or footer.
|
|
||||||
* @return The string representing the center.
|
|
||||||
*/
|
|
||||||
public String getCenter() {
|
|
||||||
if(stripFields)
|
|
||||||
return stripFields(center);
|
|
||||||
return center;
|
|
||||||
}
|
|
||||||
public abstract void setCenter( String newCenter );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the right side of the header or footer.
|
|
||||||
* @return The string representing the right side.
|
|
||||||
*/
|
|
||||||
public String getRight() {
|
|
||||||
if(stripFields)
|
|
||||||
return stripFields(right);
|
|
||||||
return right;
|
|
||||||
}
|
|
||||||
public abstract void setRight( String newRight );
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string that represents the change in font size.
|
|
||||||
*
|
|
||||||
* @param size the new font size
|
|
||||||
* @return The special string to represent a new font size
|
|
||||||
*/
|
|
||||||
public static String fontSize( short size )
|
|
||||||
{
|
|
||||||
return "&" + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string that represents the change in font.
|
|
||||||
*
|
|
||||||
* @param font the new font
|
|
||||||
* @param style the fonts style, one of regular, italic, bold, italic bold or bold italic
|
|
||||||
* @return The special string to represent a new font size
|
|
||||||
*/
|
|
||||||
public static String font( String font, String style )
|
|
||||||
{
|
|
||||||
return "&\"" + font + "," + style + "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the current page number
|
|
||||||
*
|
|
||||||
* @return The special string for page number
|
|
||||||
*/
|
|
||||||
public static String page() {
|
|
||||||
return PAGE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the number of pages.
|
|
||||||
*
|
|
||||||
* @return The special string for the number of pages
|
|
||||||
*/
|
|
||||||
public static String numPages() {
|
|
||||||
return NUM_PAGES_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the current date
|
|
||||||
*
|
|
||||||
* @return The special string for the date
|
|
||||||
*/
|
|
||||||
public static String date() {
|
|
||||||
return DATE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the current time
|
|
||||||
*
|
|
||||||
* @return The special string for the time
|
|
||||||
*/
|
|
||||||
public static String time() {
|
|
||||||
return TIME_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the current file name
|
|
||||||
*
|
|
||||||
* @return The special string for the file name
|
|
||||||
*/
|
|
||||||
public static String file() {
|
|
||||||
return FILE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the current tab (sheet) name
|
|
||||||
*
|
|
||||||
* @return The special string for tab name
|
|
||||||
*/
|
|
||||||
public static String tab() {
|
|
||||||
return SHEET_NAME_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the start bold
|
|
||||||
*
|
|
||||||
* @return The special string for start bold
|
|
||||||
*/
|
|
||||||
public static String startBold() {
|
|
||||||
return BOLD_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the end bold
|
|
||||||
*
|
|
||||||
* @return The special string for end bold
|
|
||||||
*/
|
|
||||||
public static String endBold() {
|
|
||||||
return BOLD_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the start underline
|
|
||||||
*
|
|
||||||
* @return The special string for start underline
|
|
||||||
*/
|
|
||||||
public static String startUnderline() {
|
|
||||||
return UNDERLINE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the end underline
|
|
||||||
*
|
|
||||||
* @return The special string for end underline
|
|
||||||
*/
|
|
||||||
public static String endUnderline() {
|
|
||||||
return UNDERLINE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the start double underline
|
|
||||||
*
|
|
||||||
* @return The special string for start double underline
|
|
||||||
*/
|
|
||||||
public static String startDoubleUnderline() {
|
|
||||||
return DOUBLE_UNDERLINE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representing the end double underline
|
|
||||||
*
|
|
||||||
* @return The special string for end double underline
|
|
||||||
*/
|
|
||||||
public static String endDoubleUnderline() {
|
|
||||||
return DOUBLE_UNDERLINE_FIELD.sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes any fields (eg macros, page markers etc)
|
|
||||||
* from the string.
|
|
||||||
* Normally used to make some text suitable for showing
|
|
||||||
* to humans, and the resultant text should not normally
|
|
||||||
* be saved back into the document!
|
|
||||||
*/
|
|
||||||
public static String stripFields(String text) {
|
|
||||||
int pos;
|
|
||||||
|
|
||||||
// Check we really got something to work on
|
|
||||||
if(text == null || text.length() == 0) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firstly, do the easy ones which are static
|
|
||||||
for(int i=0; i<Field.ALL_FIELDS.size(); i++) {
|
|
||||||
String seq = ((Field)Field.ALL_FIELDS.get(i)).sequence;
|
|
||||||
while((pos = text.indexOf(seq)) > -1) {
|
|
||||||
text = text.substring(0, pos) +
|
|
||||||
text.substring(pos+seq.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now do the tricky, dynamic ones
|
|
||||||
// These are things like font sizes and font names
|
|
||||||
text = text.replaceAll("\\&\\d+", "");
|
|
||||||
text = text.replaceAll("\\&\".*?,.*?\"", "");
|
|
||||||
|
|
||||||
// All done
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are fields currently being stripped from
|
|
||||||
* the text that this {@link HeaderFooter} returns?
|
|
||||||
* Default is false, but can be changed
|
|
||||||
*/
|
|
||||||
public boolean areFieldsStripped() {
|
|
||||||
return stripFields;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Should fields (eg macros) be stripped from
|
|
||||||
* the text that this class returns?
|
|
||||||
* Default is not to strip.
|
|
||||||
* @param stripFields
|
|
||||||
*/
|
|
||||||
public void setAreFieldsStripped(boolean stripFields) {
|
|
||||||
this.stripFields = stripFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final Field SHEET_NAME_FIELD = new Field("&A");
|
|
||||||
public static final Field DATE_FIELD = new Field("&D");
|
|
||||||
public static final Field FILE_FIELD = new Field("&F");
|
|
||||||
public static final Field FULL_FILE_FIELD = new Field("&Z");
|
|
||||||
public static final Field PAGE_FIELD = new Field("&P");
|
|
||||||
public static final Field TIME_FIELD = new Field("&T");
|
|
||||||
public static final Field NUM_PAGES_FIELD = new Field("&N");
|
|
||||||
|
|
||||||
public static final Field PICTURE_FIELD = new Field("&G");
|
|
||||||
|
|
||||||
public static final PairField BOLD_FIELD = new PairField("&B");
|
|
||||||
public static final PairField ITALIC_FIELD = new PairField("&I");
|
|
||||||
public static final PairField STRIKETHROUGH_FIELD = new PairField("&S");
|
|
||||||
public static final PairField SUBSCRIPT_FIELD = new PairField("&Y");
|
|
||||||
public static final PairField SUPERSCRIPT_FIELD = new PairField("&X");
|
|
||||||
public static final PairField UNDERLINE_FIELD = new PairField("&U");
|
|
||||||
public static final PairField DOUBLE_UNDERLINE_FIELD = new PairField("&E");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a special field in a header or footer,
|
|
||||||
* eg the page number
|
|
||||||
*/
|
|
||||||
public static class Field {
|
|
||||||
private static ArrayList ALL_FIELDS = new ArrayList();
|
|
||||||
/** The character sequence that marks this field */
|
|
||||||
public final String sequence;
|
|
||||||
private Field(String sequence) {
|
|
||||||
this.sequence = sequence;
|
|
||||||
ALL_FIELDS.add(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* A special field that normally comes in a pair, eg
|
|
||||||
* turn on underline / turn off underline
|
|
||||||
*/
|
|
||||||
public static class PairField extends Field {
|
|
||||||
private PairField(String sequence) {
|
|
||||||
super(sequence);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,18 +407,19 @@ public interface Sheet extends Iterable<Row> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the user model for the default document header.
|
* Gets the user model for the default document header.
|
||||||
* <p>
|
* <p/>
|
||||||
* Note that XSSF offers more kinds of document headers than HSSF does
|
* Note that XSSF offers more kinds of document headers than HSSF does
|
||||||
* </p>
|
* </p>
|
||||||
* @return the document header.
|
* @return the document header. Never <code>null</code>
|
||||||
*/
|
*/
|
||||||
Header getHeader();
|
Header getHeader();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the user model for the default document footer.
|
* Gets the user model for the default document footer.
|
||||||
|
* <p/>
|
||||||
* Note that XSSF offers more kinds of document footers than HSSF does.
|
* Note that XSSF offers more kinds of document footers than HSSF does.
|
||||||
*
|
*
|
||||||
* @return the document footer.
|
* @return the document footer. Never <code>null</code>
|
||||||
*/
|
*/
|
||||||
Footer getFooter();
|
Footer getFooter();
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -30,12 +30,14 @@ import org.apache.poi.hssf.record.BottomMarginRecord;
|
||||||
import org.apache.poi.hssf.record.DimensionsRecord;
|
import org.apache.poi.hssf.record.DimensionsRecord;
|
||||||
import org.apache.poi.hssf.record.EOFRecord;
|
import org.apache.poi.hssf.record.EOFRecord;
|
||||||
import org.apache.poi.hssf.record.FooterRecord;
|
import org.apache.poi.hssf.record.FooterRecord;
|
||||||
|
import org.apache.poi.hssf.record.HCenterRecord;
|
||||||
import org.apache.poi.hssf.record.HeaderRecord;
|
import org.apache.poi.hssf.record.HeaderRecord;
|
||||||
import org.apache.poi.hssf.record.IndexRecord;
|
import org.apache.poi.hssf.record.IndexRecord;
|
||||||
import org.apache.poi.hssf.record.NumberRecord;
|
import org.apache.poi.hssf.record.NumberRecord;
|
||||||
import org.apache.poi.hssf.record.Record;
|
import org.apache.poi.hssf.record.Record;
|
||||||
import org.apache.poi.hssf.record.RecordFormatException;
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
import org.apache.poi.hssf.record.UnknownRecord;
|
import org.apache.poi.hssf.record.UnknownRecord;
|
||||||
|
import org.apache.poi.hssf.record.VCenterRecord;
|
||||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
|
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
|
@ -236,4 +238,39 @@ public final class TestPageSettingsBlock extends TestCase {
|
||||||
private static UnknownRecord ur(int sid, String hexData) {
|
private static UnknownRecord ur(int sid, String hexData) {
|
||||||
return new UnknownRecord(sid, HexRead.readFromString(hexData));
|
return new UnknownRecord(sid, HexRead.readFromString(hexData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excel tolerates missing header / footer records, but adds them (empty) in when re-saving.
|
||||||
|
* This is not critical functionality but it has been decided to keep POI consistent with
|
||||||
|
* Excel in this regard.
|
||||||
|
*/
|
||||||
|
public void testMissingHeaderFooter() {
|
||||||
|
// initialise PSB with some records, but not the header / footer
|
||||||
|
Record[] recs = {
|
||||||
|
new HCenterRecord(),
|
||||||
|
new VCenterRecord(),
|
||||||
|
};
|
||||||
|
RecordStream rs = new RecordStream(Arrays.asList(recs), 0);
|
||||||
|
PageSettingsBlock psb = new PageSettingsBlock(rs);
|
||||||
|
|
||||||
|
// serialize the PSB to see what records come out
|
||||||
|
RecordCollector rc = new RecordCollector();
|
||||||
|
psb.visitContainedRecords(rc);
|
||||||
|
Record[] outRecs = rc.getRecords();
|
||||||
|
|
||||||
|
if (outRecs.length == 2) {
|
||||||
|
throw new AssertionFailedError("PageSettingsBlock didn't add missing header/footer records");
|
||||||
|
}
|
||||||
|
assertEquals(4, outRecs.length);
|
||||||
|
assertEquals(HeaderRecord.class, outRecs[0].getClass());
|
||||||
|
assertEquals(FooterRecord.class, outRecs[1].getClass());
|
||||||
|
assertEquals(HCenterRecord.class, outRecs[2].getClass());
|
||||||
|
assertEquals(VCenterRecord.class, outRecs[3].getClass());
|
||||||
|
|
||||||
|
// make sure the added header / footer records are empty
|
||||||
|
HeaderRecord hr = (HeaderRecord) outRecs[0];
|
||||||
|
assertEquals("", hr.getText());
|
||||||
|
FooterRecord fr = (FooterRecord) outRecs[1];
|
||||||
|
assertEquals("", fr.getText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,16 +17,20 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import junit.framework.AssertionFailedError;
|
import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFITestDataProvider;
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.OldExcelFormatException;
|
import org.apache.poi.hssf.OldExcelFormatException;
|
||||||
import org.apache.poi.hssf.HSSFITestDataProvider;
|
|
||||||
import org.apache.poi.hssf.model.Workbook;
|
import org.apache.poi.hssf.model.Workbook;
|
||||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||||
import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
|
import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
|
||||||
|
@ -34,11 +38,7 @@ import org.apache.poi.hssf.record.NameRecord;
|
||||||
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
||||||
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
|
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
|
||||||
import org.apache.poi.hssf.record.formula.Ptg;
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.RichTextString;
|
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
|
||||||
import org.apache.poi.ss.usermodel.BaseTestBugzillaIssues;
|
import org.apache.poi.ss.usermodel.BaseTestBugzillaIssues;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1247,16 +1247,18 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* header / footer text too long
|
* The resolution for bug 45777 assumed that the maximum text length in a header / footer
|
||||||
|
* record was 256 bytes. This assumption appears to be wrong. Since the fix for bug 47244,
|
||||||
|
* POI now supports header / footer text lengths beyond 256 bytes.
|
||||||
*/
|
*/
|
||||||
public void test45777() {
|
public void test45777() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
HSSFSheet s = wb.createSheet();
|
HSSFSheet s = wb.createSheet();
|
||||||
|
|
||||||
String s248 = "";
|
char[] cc248 = new char[248];
|
||||||
for(int i=0; i<248; i++) {
|
Arrays.fill(cc248, 'x');
|
||||||
s248 += "x";
|
String s248 = new String(cc248);
|
||||||
}
|
|
||||||
String s249 = s248 + "1";
|
String s249 = s248 + "1";
|
||||||
String s250 = s248 + "12";
|
String s250 = s248 + "12";
|
||||||
String s251 = s248 + "123";
|
String s251 = s248 + "123";
|
||||||
|
@ -1268,42 +1270,45 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
||||||
|
|
||||||
// Try on headers
|
// Try on headers
|
||||||
s.getHeader().setCenter(s248);
|
s.getHeader().setCenter(s248);
|
||||||
assertEquals(254, s.getHeader().getRawHeader().length());
|
assertEquals(254, s.getHeader().getRawText().length());
|
||||||
writeOutAndReadBack(wb);
|
writeOutAndReadBack(wb);
|
||||||
|
|
||||||
s.getHeader().setCenter(s249);
|
s.getHeader().setCenter(s251);
|
||||||
assertEquals(255, s.getHeader().getRawHeader().length());
|
assertEquals(257, s.getHeader().getRawText().length());
|
||||||
writeOutAndReadBack(wb);
|
writeOutAndReadBack(wb);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s.getHeader().setCenter(s250); // 256
|
s.getHeader().setCenter(s250); // 256 bytes required
|
||||||
fail();
|
} catch(IllegalArgumentException e) {
|
||||||
} catch(IllegalArgumentException e) {}
|
throw new AssertionFailedError("Identified bug 47244b - header can be more than 256 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s.getHeader().setCenter(s251); // 257
|
s.getHeader().setCenter(s251); // 257 bytes required
|
||||||
fail();
|
} catch(IllegalArgumentException e) {
|
||||||
} catch(IllegalArgumentException e) {}
|
throw new AssertionFailedError("Identified bug 47244b - header can be more than 256 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
// Now try on footers
|
// Now try on footers
|
||||||
s.getFooter().setCenter(s248);
|
s.getFooter().setCenter(s248);
|
||||||
assertEquals(254, s.getFooter().getRawFooter().length());
|
assertEquals(254, s.getFooter().getRawText().length());
|
||||||
writeOutAndReadBack(wb);
|
writeOutAndReadBack(wb);
|
||||||
|
|
||||||
s.getFooter().setCenter(s249);
|
s.getFooter().setCenter(s251);
|
||||||
assertEquals(255, s.getFooter().getRawFooter().length());
|
assertEquals(257, s.getFooter().getRawText().length());
|
||||||
writeOutAndReadBack(wb);
|
writeOutAndReadBack(wb);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s.getFooter().setCenter(s250); // 256
|
s.getFooter().setCenter(s250); // 256 bytes required
|
||||||
fail();
|
} catch(IllegalArgumentException e) {
|
||||||
} catch(IllegalArgumentException e) {}
|
throw new AssertionFailedError("Identified bug 47244b - footer can be more than 256 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s.getFooter().setCenter(s251); // 257
|
s.getFooter().setCenter(s251); // 257 bytes required
|
||||||
fail();
|
} catch(IllegalArgumentException e) {
|
||||||
} catch(IllegalArgumentException e) {}
|
throw new AssertionFailedError("Identified bug 47244b - footer can be more than 256 bytes");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1469,24 +1474,24 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
||||||
* java.io.IOException: block[ 0 ] already removed
|
* java.io.IOException: block[ 0 ] already removed
|
||||||
* (is an excel 95 file though)
|
* (is an excel 95 file though)
|
||||||
*/
|
*/
|
||||||
public void test46904() throws IOException {
|
public void test46904() {
|
||||||
try {
|
try {
|
||||||
HSSFWorkbook wb = openSample("46904.xls");
|
openSample("46904.xls");
|
||||||
fail();
|
fail();
|
||||||
} catch(OldExcelFormatException e) {
|
} catch(OldExcelFormatException e) {
|
||||||
assertTrue(e.getMessage().startsWith(
|
assertTrue(e.getMessage().startsWith(
|
||||||
"The supplied spreadsheet seems to be Excel"
|
"The supplied spreadsheet seems to be Excel"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* java.lang.NegativeArraySizeException reading long
|
* java.lang.NegativeArraySizeException reading long
|
||||||
* non-unicode data for a name record
|
* non-unicode data for a name record
|
||||||
*/
|
*/
|
||||||
public void test47034() throws IOException {
|
public void test47034() {
|
||||||
HSSFWorkbook wb = openSample("47034.xls");
|
HSSFWorkbook wb = openSample("47034.xls");
|
||||||
assertEquals(893, wb.getNumberOfNames());
|
assertEquals(893, wb.getNumberOfNames());
|
||||||
assertEquals("Matthew\\Matthew11_1\\Matthew2331_1\\Matthew2351_1\\Matthew2361_1___lab", wb.getNameName(300));
|
assertEquals("Matthew\\Matthew11_1\\Matthew2331_1\\Matthew2351_1\\Matthew2361_1___lab", wb.getNameName(300));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,32 +17,32 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests row shifting capabilities.
|
* Tests for {@link HSSFHeader} / {@link HSSFFooter}
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @author Shawn Laubach (slaubach at apache dot com)
|
* @author Shawn Laubach (slaubach at apache dot com)
|
||||||
*/
|
*/
|
||||||
public final class TestHSSFHeaderFooter extends TestCase {
|
public final class TestHSSFHeaderFooter extends TestCase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that get header retreives the proper values.
|
* Tests that get header retrieves the proper values.
|
||||||
*
|
*
|
||||||
* @author Shawn Laubach (slaubach at apache dot org)
|
* @author Shawn Laubach (slaubach at apache dot org)
|
||||||
*/
|
*/
|
||||||
public void testRetrieveCorrectHeader() {
|
public void testRetrieveCorrectHeader() {
|
||||||
// Read initial file in
|
|
||||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
|
||||||
HSSFSheet s = wb.getSheetAt( 0 );
|
HSSFSheet s = wb.getSheetAt( 0 );
|
||||||
HSSFHeader head = s.getHeader();
|
HSSFHeader head = s.getHeader();
|
||||||
|
|
||||||
assertEquals("Top Left", head.getLeft());
|
assertEquals("Top Left", head.getLeft());
|
||||||
assertEquals("Top Center", head.getCenter());
|
assertEquals("Top Center", head.getCenter());
|
||||||
assertEquals("Top Right", head.getRight());
|
assertEquals("Top Right", head.getRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSpecialChars() {
|
public void testSpecialChars() {
|
||||||
|
@ -72,43 +72,40 @@ public final class TestHSSFHeaderFooter extends TestCase {
|
||||||
// Now test the default strip flag
|
// Now test the default strip flag
|
||||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
|
||||||
HSSFSheet s = wb.getSheetAt( 0 );
|
HSSFSheet s = wb.getSheetAt( 0 );
|
||||||
HSSFHeader head = s.getHeader();
|
HSSFHeader head = s.getHeader();
|
||||||
|
|
||||||
assertEquals("Top Left", head.getLeft());
|
assertEquals("Top Left", head.getLeft());
|
||||||
assertEquals("Top Center", head.getCenter());
|
assertEquals("Top Center", head.getCenter());
|
||||||
assertEquals("Top Right", head.getRight());
|
assertEquals("Top Right", head.getRight());
|
||||||
|
|
||||||
head.setLeft("Top &P&F&D Left");
|
head.setLeft("Top &P&F&D Left");
|
||||||
assertEquals("Top &P&F&D Left", head.getLeft());
|
assertEquals("Top &P&F&D Left", head.getLeft());
|
||||||
assertFalse(head.areFieldsStripped());
|
|
||||||
|
|
||||||
head.setAreFieldsStripped(true);
|
assertEquals("Top Left", HeaderFooter.stripFields(head.getLeft()));
|
||||||
assertEquals("Top Left", head.getLeft());
|
|
||||||
assertTrue(head.areFieldsStripped());
|
|
||||||
|
|
||||||
// Now even more complex
|
// Now even more complex
|
||||||
head.setCenter("HEADER TEXT &P&N&D&T&Z&F&F&A&G&X END");
|
head.setCenter("HEADER TEXT &P&N&D&T&Z&F&F&A&G&X END");
|
||||||
assertEquals("HEADER TEXT END", head.getCenter());
|
assertEquals("HEADER TEXT END", HeaderFooter.stripFields(head.getCenter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that get header retreives the proper values.
|
* Tests that get header retrieves the proper values.
|
||||||
*
|
*
|
||||||
* @author Shawn Laubach (slaubach at apache dot org)
|
* @author Shawn Laubach (slaubach at apache dot org)
|
||||||
*/
|
*/
|
||||||
public void testRetrieveCorrectFooter() {
|
public void testRetrieveCorrectFooter() {
|
||||||
// Read initial file in
|
|
||||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
|
|
||||||
HSSFSheet s = wb.getSheetAt( 0 );
|
|
||||||
HSSFFooter foot = s.getFooter();
|
|
||||||
|
|
||||||
assertEquals("Bottom Left", foot.getLeft());
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
|
||||||
assertEquals("Bottom Center", foot.getCenter());
|
HSSFSheet s = wb.getSheetAt(0);
|
||||||
assertEquals("Bottom Right", foot.getRight());
|
HSSFFooter foot = s.getFooter();
|
||||||
|
|
||||||
|
assertEquals("Bottom Left", foot.getLeft());
|
||||||
|
assertEquals("Bottom Center", foot.getCenter());
|
||||||
|
assertEquals("Bottom Right", foot.getRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Testcase for Bug 17039 HSSFHeader doesnot support DBCS
|
* Testcase for Bug 17039 HSSFHeader does not support DBCS
|
||||||
*/
|
*/
|
||||||
public void testHeaderHas16bitCharacter() {
|
public void testHeaderHas16bitCharacter() {
|
||||||
HSSFWorkbook b = new HSSFWorkbook();
|
HSSFWorkbook b = new HSSFWorkbook();
|
||||||
|
@ -127,7 +124,7 @@ public final class TestHSSFHeaderFooter extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Testcase for Bug 17039 HSSFFooter doesnot support DBCS
|
* Testcase for Bug 17039 HSSFFooter does not support DBCS
|
||||||
*/
|
*/
|
||||||
public void testFooterHas16bitCharacter() {
|
public void testFooterHas16bitCharacter() {
|
||||||
HSSFWorkbook b = new HSSFWorkbook();
|
HSSFWorkbook b = new HSSFWorkbook();
|
||||||
|
@ -158,5 +155,32 @@ public final class TestHSSFHeaderFooter extends TestCase {
|
||||||
assertEquals("Footer Center " ,f.getCenter(),"\u091c\u093e");
|
assertEquals("Footer Center " ,f.getCenter(),"\u091c\u093e");
|
||||||
assertEquals("Footer Right " ,f.getRight(),"\u091c\u093e");
|
assertEquals("Footer Right " ,f.getRight(),"\u091c\u093e");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excel tolerates files with missing HEADER/FOOTER records. POI should do the same.
|
||||||
|
*/
|
||||||
|
public void testMissingHeaderFooterRecord_bug47244() {
|
||||||
|
// noHeaderFooter47244.xls was created by a slightly modified POI
|
||||||
|
// which omitted the HEADER/FOOTER records
|
||||||
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("noHeaderFooter47244.xls");
|
||||||
|
HSSFSheet sheet = wb.getSheetAt(0);
|
||||||
|
HSSFFooter footer;
|
||||||
|
try {
|
||||||
|
footer = sheet.getFooter();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
throw new AssertionFailedError("Identified bug 47244a");
|
||||||
|
}
|
||||||
|
assertEquals("", footer.getRawText());
|
||||||
|
HSSFHeader header = sheet.getHeader();
|
||||||
|
assertEquals("", header.getRawText());
|
||||||
|
|
||||||
|
// make sure header / footer is properly linked to underlying data
|
||||||
|
HSSFHeader header2 = sheet.getHeader();
|
||||||
|
header.setCenter("foo");
|
||||||
|
assertEquals("foo", header2.getCenter());
|
||||||
|
|
||||||
|
HSSFFooter footer2 = sheet.getFooter();
|
||||||
|
footer.setCenter("bar");
|
||||||
|
assertEquals("bar", footer2.getCenter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue