* Description: Specifies a header for a sheet
@@ -27,49 +26,30 @@ package org.apache.poi.hssf.record; * @author Jason Height (jheight at chariot dot net dot au) */ public final class HeaderRecord extends HeaderFooterBase { - public final static short sid = 0x0014; + public final static short sid = 0x0014; - public HeaderRecord(String text) { - super(text); - } + public HeaderRecord(String text) { + super(text); + } - public HeaderRecord(RecordInputStream in) { - super(in); - } + public HeaderRecord(RecordInputStream in) { + super(in); + } - /** - * set the header string - * - * @param header string to display - */ - public void setHeader(String header) { - setText(header); - } + public String toString() { + StringBuffer buffer = new StringBuffer(); - /** - * get the header string - * - * @return header string to display - */ - public String getHeader() { - return getText(); - } + buffer.append("[HEADER]\n"); + buffer.append(" .header = ").append(getText()).append("\n"); + buffer.append("[/HEADER]\n"); + return buffer.toString(); + } - public String toString() { - StringBuffer buffer = new StringBuffer(); + public short getSid() { + return sid; + } - buffer.append("[HEADER]\n"); - buffer.append(" .header = ").append(getText()).append("\n"); - buffer.append("[/HEADER]\n"); - return buffer.toString(); - } - - - public short getSid() { - return sid; - } - - public Object clone() { - return new HeaderRecord(getText()); - } + public Object clone() { + return new HeaderRecord(getText()); + } } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java index 98b589e67e..1b9228bec8 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java @@ -239,10 +239,21 @@ public final class PageSettingsBlock extends RecordAggregate { public void visitContainedRecords(RecordVisitor rv) { + // Replicates record order from Excel 2007, though this is not critical + visitIfPresent(_rowBreaksRecord, rv); visitIfPresent(_columnBreaksRecord, rv); - visitIfPresent(_header, rv); - visitIfPresent(_footer, rv); + // Write out empty header / footer records if these are missing + 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(_vCenter, rv); visitIfPresent(_leftMargin, rv); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java index 4f10ba8c9f..da7d7403d3 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFooter.java @@ -15,10 +15,10 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.usermodel; import org.apache.poi.hssf.record.FooterRecord; +import org.apache.poi.hssf.record.aggregates.PageSettingsBlock; import org.apache.poi.ss.usermodel.Footer; /** @@ -33,59 +33,29 @@ import org.apache.poi.ss.usermodel.Footer; *
* @author Shawn Laubach (slaubach at apache dot org)
*/
-public class HSSFFooter extends HeaderFooter implements Footer {
- private FooterRecord footerRecord;
+public final class HSSFFooter extends HeaderFooter implements Footer {
+ private final PageSettingsBlock _psb;
- /**
- * Constructor. Creates a new footer interface from a footer record
- * @param footerRecord Footer record to create the footer with
- */
- protected HSSFFooter(FooterRecord footerRecord) {
- super(footerRecord.getFooter());
- this.footerRecord = footerRecord;
- }
+ protected HSSFFooter(PageSettingsBlock psb) {
+ _psb = psb;
+ }
- /**
- * Sets the left string.
- * @param newLeft The string to set as the left side.
- */
- public void setLeft(String newLeft) {
- left = newLeft;
- createFooterString();
- }
+ protected String getRawText() {
+ FooterRecord hf = _psb.getFooter();
+ if (hf == null) {
+ return "";
+ }
+ return hf.getText();
+ }
- /**
- * Sets the center string.
- * @param newCenter The string to set as the center.
- */
- public void setCenter(String newCenter) {
- center = newCenter;
- createFooterString();
- }
-
- /**
- * 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));
- }
+ @Override
+ protected void setHeaderFooterText(String text) {
+ FooterRecord hfr = _psb.getFooter();
+ if (hfr == null) {
+ hfr = new FooterRecord(text);
+ _psb.setFooter(hfr);
+ } else {
+ hfr.setText(text);
+ }
+ }
}
-
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java b/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java
index 36dfc969b0..4d706159ee 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFHeader.java
@@ -18,6 +18,7 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.HeaderRecord;
+import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
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)
*/
-public class HSSFHeader extends HeaderFooter implements Header {
- private HeaderRecord headerRecord;
+public final class HSSFHeader extends HeaderFooter implements Header {
- /**
- * 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;
- }
+ private final PageSettingsBlock _psb;
- /**
- * Sets the left string.
- *
- * @param newLeft The string to set as the left side.
- */
- public void setLeft( String newLeft )
- {
- left = newLeft;
- createHeaderString();
- }
+ protected HSSFHeader(PageSettingsBlock psb) {
+ _psb = psb;
+ }
- /**
- * Sets the center string.
- *
- * @param newCenter The string to set as the center.
- */
- public void setCenter( String newCenter )
- {
- 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 ) );
- }
+ protected String getRawText() {
+ HeaderRecord hf = _psb.getHeader();
+ if (hf == null) {
+ return "";
+ }
+ return hf.getText();
+ }
+ @Override
+ protected void setHeaderFooterText(String text) {
+ HeaderRecord hfr = _psb.getHeader();
+ if (hfr == null) {
+ hfr = new HeaderRecord(text);
+ _psb.setHeader(hfr);
+ } else {
+ hfr.setText(text);
+ }
+ }
}
-
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index 0067a6bb8c..83474957e6 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -913,20 +913,12 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
return new HSSFPrintSetup(_sheet.getPageSettings().getPrintSetup());
}
- /**
- * Gets the user model for the document header.
- * @return The Document header.
- */
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() {
- return new HSSFFooter(_sheet.getPageSettings().getFooter());
+ return new HSSFFooter(_sheet.getPageSettings());
}
/**
diff --git a/src/java/org/apache/poi/hssf/usermodel/HeaderFooter.java b/src/java/org/apache/poi/hssf/usermodel/HeaderFooter.java
index 8e091ec003..4fd7c89cc0 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HeaderFooter.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HeaderFooter.java
@@ -14,318 +14,325 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.usermodel;
-import java.util.ArrayList;
/**
- * Common class for {@link HSSFHeader} and
- * {@link HSSFFooter}.
+ * Common class for {@link HSSFHeader} and {@link HSSFFooter}.
*/
public abstract class HeaderFooter implements org.apache.poi.ss.usermodel.HeaderFooter {
- protected String left;
- protected String center;
- protected String right;
+
+ protected HeaderFooter() {
+ //
+ }
- private boolean stripFields = false;
+ /**
+ * @return the internal text representation (combining center, left and right parts).
+ * Possibly empty string if no header or footer is set. Never
+ * null
.
+ */
+ protected abstract String getRawText();
- protected HeaderFooter(String text) {
- while (text != null && text.length() > 1) {
- int pos = text.length();
- switch (text.substring(1, 2).charAt(0)) {
- case 'L' :
+ 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) {
- pos = Math.min(pos, text.indexOf("&C"));
- }
+ pos = Math.min(pos, text.indexOf("&C"));
+ }
if (text.indexOf("&R") >= 0) {
- pos = Math.min(pos, text.indexOf("&R"));
- }
- left = text.substring(2, pos);
+ pos = Math.min(pos, text.indexOf("&R"));
+ }
+ _left = text.substring(2, pos);
text = text.substring(pos);
break;
- case 'C' :
+ case 'C':
if (text.indexOf("&L") >= 0) {
- pos = Math.min(pos, text.indexOf("&L"));
- }
+ pos = Math.min(pos, text.indexOf("&L"));
+ }
if (text.indexOf("&R") >= 0) {
- pos = Math.min(pos, text.indexOf("&R"));
- }
- center = text.substring(2, pos);
+ pos = Math.min(pos, text.indexOf("&R"));
+ }
+ _center = text.substring(2, pos);
text = text.substring(pos);
break;
- case 'R' :
+ case 'R':
if (text.indexOf("&C") >= 0) {
- pos = Math.min(pos, text.indexOf("&C"));
- }
+ pos = Math.min(pos, text.indexOf("&C"));
+ }
if (text.indexOf("&L") >= 0) {
- pos = Math.min(pos, text.indexOf("&L"));
- }
- right = text.substring(2, pos);
+ pos = Math.min(pos, text.indexOf("&L"));
+ }
+ _right = text.substring(2, pos);
text = text.substring(pos);
break;
- default:
- text = null;
- }
+ default:
+ 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 null
+ */
+ 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
null
*/
Header getHeader();
/**
* Gets the user model for the default document footer.
+ *
* Note that XSSF offers more kinds of document footers than HSSF does.
*
- * @return the document footer.
+ * @return the document footer. Never null
*/
Footer getFooter();
@@ -473,7 +474,7 @@ public interface Sheet extends Iterable