<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
- <action dev="POI-DEVELOPERS" type="fix">45622 - Support stripping HWPF fields (eg macros) out of text, via Range.stripFields(text)</action>
+ <action dev="POI-DEVELOPERS" type="add">45623 - Support for additional HSSF header and footer fields, including bold and full file path</action>
+ <action dev="POI-DEVELOPERS" type="add">45623 - Support stripping HSSF header and footer fields (eg page number) out of header and footer text if required</action>
+ <action dev="POI-DEVELOPERS" type="add">45622 - Support stripping HWPF fields (eg macros) out of text, via Range.stripFields(text)</action>
<action dev="POI-DEVELOPERS" type="add">New HPSF based TextExtractor for document metadata, org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor</action>
<action dev="POI-DEVELOPERS" type="fix">Properly update the array of Slide's text runs in HSLF when new text shapes are added</action>
<action dev="POI-DEVELOPERS" type="fix">45590 - Fix for Header/footer extraction for .ppt files saved in Office 2007</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 version="3.1.1-alpha1" date="2008-??-??">
- <action dev="POI-DEVELOPERS" type="fix">45622 - Support stripping HWPF fields (eg macros) out of text, via Range.stripFields(text)</action>
+ <action dev="POI-DEVELOPERS" type="add">45623 - Support for additional HSSF header and footer fields, including bold and full file path</action>
+ <action dev="POI-DEVELOPERS" type="add">45623 - Support stripping HSSF header and footer fields (eg page number) out of header and footer text if required</action>
+ <action dev="POI-DEVELOPERS" type="add">45622 - Support stripping HWPF fields (eg macros) out of text, via Range.stripFields(text)</action>
<action dev="POI-DEVELOPERS" type="add">New HPSF based TextExtractor for document metadata, org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor</action>
<action dev="POI-DEVELOPERS" type="fix">Properly update the array of Slide's text runs in HSLF when new text shapes are added</action>
<action dev="POI-DEVELOPERS" type="fix">45590 - Fix for Header/footer extraction for .ppt files saved in Office 2007</action>
* <P>
* @author Shawn Laubach (slaubach at apache dot org)
*/
-public class HSSFFooter implements Footer, HeaderFooter {
- FooterRecord footerRecord;
- String left;
- String center;
- String right;
+public class HSSFFooter extends HeaderFooter implements Footer {
+ private FooterRecord footerRecord;
/**
* Constructor. Creates a new footer interface from a footer record
* @param footerRecord Footer record to create the footer with
*/
protected HSSFFooter(FooterRecord footerRecord) {
- this.footerRecord = footerRecord;
- String foot = footerRecord.getFooter();
- while (foot != null && foot.length() > 1) {
- int pos = foot.length();
- switch (foot.substring(1, 2).charAt(0)) {
- case 'L' :
- if (foot.indexOf("&C") >= 0) {
- pos = Math.min(pos, foot.indexOf("&C"));
- }
- if (foot.indexOf("&R") >= 0) {
- pos = Math.min(pos, foot.indexOf("&R"));
- }
- left = foot.substring(2, pos);
- foot = foot.substring(pos);
- break;
- case 'C' :
- if (foot.indexOf("&L") >= 0) {
- pos = Math.min(pos, foot.indexOf("&L"));
- }
- if (foot.indexOf("&R") >= 0) {
- pos = Math.min(pos, foot.indexOf("&R"));
- }
- center = foot.substring(2, pos);
- foot = foot.substring(pos);
- break;
- case 'R' :
- if (foot.indexOf("&C") >= 0) {
- pos = Math.min(pos, foot.indexOf("&C"));
- }
- if (foot.indexOf("&L") >= 0) {
- pos = Math.min(pos, foot.indexOf("&L"));
- }
- right = foot.substring(2, pos);
- foot = foot.substring(pos);
- break;
- default : foot = null;
- }
- }
- }
-
- /**
- * Get the left side of the footer.
- * @return The string representing the left side.
- */
- public String getLeft() {
- return left;
+ super(footerRecord.getFooter());
+ this.footerRecord = footerRecord;
}
/**
createFooterString();
}
- /**
- * Get the center of the footer.
- * @return The string representing the center.
- */
- public String getCenter() {
- return center;
- }
-
/**
* Sets the center string.
* @param newCenter The string to set as the center.
createFooterString();
}
- /**
- * Get the right side of the footer.
- * @return The string representing the right side.
- */
- public String getRight() {
- return right;
- }
-
/**
* Sets the right string.
* @param newRight The string to set as the right side.
"&R" + (right == null ? "" : right));
footerRecord.setFooterLength((byte)footerRecord.getFooter().length());
}
-
- /**
- * 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
- * @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 "&P";
- }
-
- /**
- * Returns the string representing the number of pages.
- * @return The special string for the number of pages
- */
- public static String numPages() {
- return "&N";
- }
-
- /**
- * Returns the string representing the current date
- * @return The special string for the date
- */
- public static String date() {
- return "&D";
- }
-
- /**
- * Returns the string representing the current time
- * @return The special string for the time
- */
- public static String time() {
- return "&T";
- }
-
- /**
- * Returns the string representing the current file name
- * @return The special string for the file name
- */
- public static String file() {
- return "&F";
- }
-
- /**
- * Returns the string representing the current tab (sheet) name
- * @return The special string for tab name
- */
- public static String tab() {
- return "&A";
- }
-
- /**
- * Returns the string representing the start underline
- *
- * @return The special string for start underline
- */
- public static String startUnderline()
- {
- return "&U";
- }
-
- /**
- * Returns the string representing the end underline
- *
- * @return The special string for end underline
- */
- public static String endUnderline()
- {
- return "&U";
- }
-
- /**
- * Returns the string representing the start double underline
- *
- * @return The special string for start double underline
- */
- public static String startDoubleUnderline()
- {
- return "&E";
- }
-
- /**
- * Returns the string representing the end double underline
- *
- * @return The special string for end double underline
- */
- public static String endDoubleUnderline()
- {
- return "&E";
- }
}
*
* @author Shawn Laubach (slaubach at apache dot org)
*/
-public class HSSFHeader implements Header, HeaderFooter
-{
-
- HeaderRecord headerRecord;
- String left;
- String center;
- String right;
+public class HSSFHeader extends HeaderFooter implements Header {
+ private HeaderRecord headerRecord;
/**
* Constructor. Creates a new header interface from a header record
*
* @param headerRecord Header record to create the header with
*/
- protected HSSFHeader( HeaderRecord headerRecord )
- {
+ protected HSSFHeader( HeaderRecord headerRecord ) {
+ super(headerRecord.getHeader());
this.headerRecord = headerRecord;
- String head = headerRecord.getHeader();
- while ( head != null && head.length() > 1 )
- {
- int pos = head.length();
- switch ( head.substring( 1, 2 ).charAt( 0 ) )
- {
- case 'L':
- if ( head.indexOf( "&C" ) >= 0 )
- {
- pos = Math.min( pos, head.indexOf( "&C" ) );
- }
- if ( head.indexOf( "&R" ) >= 0 )
- {
- pos = Math.min( pos, head.indexOf( "&R" ) );
- }
- left = head.substring( 2, pos );
- head = head.substring( pos );
- break;
- case 'C':
- if ( head.indexOf( "&L" ) >= 0 )
- {
- pos = Math.min( pos, head.indexOf( "&L" ) );
- }
- if ( head.indexOf( "&R" ) >= 0 )
- {
- pos = Math.min( pos, head.indexOf( "&R" ) );
- }
- center = head.substring( 2, pos );
- head = head.substring( pos );
- break;
- case 'R':
- if ( head.indexOf( "&C" ) >= 0 )
- {
- pos = Math.min( pos, head.indexOf( "&C" ) );
- }
- if ( head.indexOf( "&L" ) >= 0 )
- {
- pos = Math.min( pos, head.indexOf( "&L" ) );
- }
- right = head.substring( 2, pos );
- head = head.substring( pos );
- break;
- default :
- head = null;
- }
- }
- }
-
- /**
- * Get the left side of the header.
- *
- * @return The string representing the left side.
- */
- public String getLeft()
- {
- return left;
}
/**
createHeaderString();
}
- /**
- * Get the center of the header.
- *
- * @return The string representing the center.
- */
- public String getCenter()
- {
- return center;
- }
-
/**
* Sets the center string.
*
createHeaderString();
}
- /**
- * Get the right side of the header.
- *
- * @return The string representing the right side.
- */
- public String getRight()
- {
- return right;
- }
-
/**
* Sets the right string.
*
headerRecord.setHeaderLength( (byte) headerRecord.getHeader().length() );
}
- /**
- * 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
- * @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 "&P";
- }
-
- /**
- * Returns the string representing the number of pages.
- *
- * @return The special string for the number of pages
- */
- public static String numPages()
- {
- return "&N";
- }
-
- /**
- * Returns the string representing the current date
- *
- * @return The special string for the date
- */
- public static String date()
- {
- return "&D";
- }
-
- /**
- * Returns the string representing the current time
- *
- * @return The special string for the time
- */
- public static String time()
- {
- return "&T";
- }
-
- /**
- * Returns the string representing the current file name
- *
- * @return The special string for the file name
- */
- public static String file()
- {
- return "&F";
- }
-
- /**
- * Returns the string representing the current tab (sheet) name
- *
- * @return The special string for tab name
- */
- public static String tab()
- {
- return "&A";
- }
-
- /**
- * Returns the string representing the start underline
- *
- * @return The special string for start underline
- */
- public static String startUnderline()
- {
- return "&U";
- }
-
- /**
- * Returns the string representing the end underline
- *
- * @return The special string for end underline
- */
- public static String endUnderline()
- {
- return "&U";
- }
-
- /**
- * Returns the string representing the start double underline
- *
- * @return The special string for start double underline
- */
- public static String startDoubleUnderline()
- {
- return "&E";
- }
-
- /**
- * Returns the string representing the end double underline
- *
- * @return The special string for end double underline
- */
- public static String endDoubleUnderline()
- {
- return "&E";
- }
}
==================================================================== */
package org.apache.poi.hssf.usermodel;
+import java.util.ArrayList;
+
/**
- * Common interface for {@link HSSFHeader} and
+ * Common class for {@link HSSFHeader} and
* {@link HSSFFooter}.
*/
-public interface HeaderFooter extends 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(String text) {
+ while (text != null && text.length() > 1) {
+ int pos = text.length();
+ switch (text.substring(1, 2).charAt(0)) {
+ case 'L' :
+ if (text.indexOf("&C") >= 0) {
+ pos = Math.min(pos, text.indexOf("&C"));
+ }
+ if (text.indexOf("&R") >= 0) {
+ pos = Math.min(pos, text.indexOf("&R"));
+ }
+ left = text.substring(2, pos);
+ text = text.substring(pos);
+ break;
+ case 'C' :
+ if (text.indexOf("&L") >= 0) {
+ pos = Math.min(pos, text.indexOf("&L"));
+ }
+ if (text.indexOf("&R") >= 0) {
+ pos = Math.min(pos, text.indexOf("&R"));
+ }
+ center = text.substring(2, pos);
+ text = text.substring(pos);
+ break;
+ case 'R' :
+ if (text.indexOf("&C") >= 0) {
+ pos = Math.min(pos, text.indexOf("&C"));
+ }
+ if (text.indexOf("&L") >= 0) {
+ pos = Math.min(pos, text.indexOf("&L"));
+ }
+ right = text.substring(2, pos);
+ text = text.substring(pos);
+ break;
+ default:
+ text = null;
+ }
+ }
+ }
+
+ /**
+ * 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;
+
+ // 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
+ text = text.replaceAll("\\&\\d+", "");
+ text = text.replaceAll("\\&\".*?,.*?\"", "");
+
+ // All done
+ return text;
+ }
+
+
+ /**
+ * Are fields currently being stripped from
+ * the text that this {@link HeaderStories} 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("&P");
+
+ public static final PairField BOLD_FIELD = new PairField("&B"); // PAID
+ 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);
+ }
+ }
}
package org.apache.poi.hssf.usermodel;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
assertEquals("Top Center", head.getCenter());
assertEquals("Top Right", head.getRight());
}
+
+ public void testSpecialChars() {
+ assertEquals("&U", HSSFHeader.startUnderline());
+ assertEquals("&U", HSSFHeader.endUnderline());
+ assertEquals("&P", HSSFHeader.page());
+
+ assertEquals("&22", HSSFFooter.fontSize((short)22));
+ assertEquals("&\"Arial,bold\"", HSSFFooter.font("Arial", "bold"));
+ }
+
+ public void testStripFields() {
+ String simple = "I am a test header";
+ String withPage = "I am a&P test header";
+ String withLots = "I&A am&N a&P test&T header&U";
+ String withFont = "I&22 am a&\"Arial,bold\" test header";
+ String withOtherAnds = "I am a&P test header&&";
+ String withOtherAnds2 = "I am a&P test header&a&b";
+
+ assertEquals(simple, HSSFHeader.stripFields(simple));
+ assertEquals(simple, HSSFHeader.stripFields(withPage));
+ assertEquals(simple, HSSFHeader.stripFields(withLots));
+ assertEquals(simple, HSSFHeader.stripFields(withFont));
+ assertEquals(simple + "&&", HSSFHeader.stripFields(withOtherAnds));
+ assertEquals(simple + "&a&b", HSSFHeader.stripFields(withOtherAnds2));
+
+ // Now test the default strip flag
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("EmbeddedChartHeaderTest.xls");
+ HSSFSheet s = wb.getSheetAt( 0 );
+ HSSFHeader head = s.getHeader();
+
+ assertEquals("Top Left", head.getLeft());
+ assertEquals("Top Center", head.getCenter());
+ assertEquals("Top Right", head.getRight());
+
+ head.setLeft("Top &P&F&D Left");
+ assertEquals("Top &P&F&D Left", head.getLeft());
+ assertFalse(head.areFieldsStripped());
+
+ head.setAreFieldsStripped(true);
+ assertEquals("Top Left", head.getLeft());
+ assertTrue(head.areFieldsStripped());
+
+ // Now even more complex
+ head.setCenter("HEADER TEXT &P&N&D&T&Z&F&F&A&G");
+ assertEquals("HEADER TEXT &G", head.getCenter());
+ }
/**
* Tests that get header retreives the proper values.