support for headers / footers in HSLF

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@682336 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-08-04 11:40:25 +00:00
parent b73865910f
commit ee01022c01
19 changed files with 1206 additions and 19 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.1.1-alpha1" date="2008-??-??"> <release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">Support for Headers / Footers in HSLF</action>
<action dev="POI-DEVELOPERS" type="fix">44953 - Extensive fixes for data validation</action> <action dev="POI-DEVELOPERS" type="fix">44953 - Extensive fixes for data validation</action>
<action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action> <action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action>
<action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action> <action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>

View File

@ -46,6 +46,7 @@
<li><link href="#Freeform">How to create shapes of arbitrary geometry</link></li> <li><link href="#Freeform">How to create shapes of arbitrary geometry</link></li>
<li><link href="#Graphics2D">Shapes and Graphics2D</link></li> <li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
<li><link href="#Render">How to convert slides into images</link></li> <li><link href="#Render">How to convert slides into images</link></li>
<li><link href="#HeadersFooters">Headers / Footers</link></li>
</ul> </ul>
</section> </section>
<section><title>Features</title> <section><title>Features</title>
@ -620,6 +621,48 @@
</section> </section>
</section> </section>
<anchor id="HeadersFooters"/>
<section><title>How to extract Headers / Footers from an existing presentation</title>
<source>
FileInputStream is = new FileInputStream("slideshow.ppt");
SlideShow ppt = new SlideShow(is);
is.close();
Slide[] slides = ppt.getSlides();
//presentation-scope headers / footers
HeadersFooters hdd = ppt.getSlideHeadersFooters();
if(hdd.isFooterVisible()) {
String footerText = hdd.getFooterText();
}
//per-slide headers / footers
for (int i=0; i &lt; slides.length; i++){
HeadersFooters hdd2 = slides[i].getHeadersFooters();
if(hdd2.isFooterVisible()) {
String footerText = hdd2.getFooterText();
}
if(hdd2.isUserDateVisible()) {
String customDate = hdd2.getDateTimeText();
}
if(hdd2.isSlideNumberVisible()){
int slideNUm = slides[i].getSlideNumber();
}
}
</source>
</section>
<section><title>How to set Headers / Footers</title>
<source>
SlideShow ppt = new SlideShow();
//presentation-scope headers / footers
HeadersFooters hdd = ppt.getSlideHeadersFooters();
hdd.setSlideNumberVisible(true);
hdd.setFootersText("Created by POI-HSLF");
</source>
</section>
</section> </section>
</body> </body>
</document> </document>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.1.1-alpha1" date="2008-??-??"> <release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">Support for Headers / Footers in HSLF</action>
<action dev="POI-DEVELOPERS" type="fix">44953 - Extensive fixes for data validation</action> <action dev="POI-DEVELOPERS" type="fix">44953 - Extensive fixes for data validation</action>
<action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action> <action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action>
<action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action> <action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>

View File

@ -0,0 +1,51 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.examples;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.model.HeadersFooters;
import org.apache.poi.hslf.model.Slide;
import java.io.FileOutputStream;
/**
* Demonstrates how to set headers / footers
*
* @author Yegor Kozlov
*/
public class HeadersFootersDemo {
public static void main(String[] args) throws Exception {
SlideShow ppt = new SlideShow();
HeadersFooters slideHeaders = ppt.getSlideHeadersFooters();
slideHeaders.setFootersText("Created by POI-HSLF");
slideHeaders.setSlideNumberVisible(true);
slideHeaders.setDateTimeText("custom date time");
HeadersFooters notesHeaders = ppt.getNotesHeadersFooters();
notesHeaders.setFootersText("My notes footers");
notesHeaders.setHeaderText("My notes header");
Slide slide = ppt.createSlide();
FileOutputStream out = new FileOutputStream("headers_footers.ppt");
ppt.write(out);
out.close();
}
}

View File

@ -0,0 +1,226 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.SlideShow;
/**
* Header / Footer settings.
*
* @author Yegor Kozlov
*/
public class HeadersFooters {
private HeadersFootersContainer _container;
private boolean _newRecord;
private SlideShow _ppt;
public HeadersFooters(HeadersFootersContainer rec, SlideShow ppt, boolean newRecord){
_container = rec;
_newRecord = newRecord;
_ppt = ppt;
}
/**
* Headers's text
*
* @return Headers's text
*/
public String getHeaderText(){
CString cs = _container.getHeaderAtom();
return cs == null ? null : cs.getText();
}
/**
* Sets headers's text
*
* @param text headers's text
*/
public void setHeaderText(String text){
if(_newRecord) attach();
setHeaderVisible(true);
CString cs = _container.getHeaderAtom();
if(cs == null) cs = _container.addHeaderAtom();
cs.setText(text);
}
/**
* Footer's text
*
* @return Footer's text
*/
public String getFooterText(){
CString cs = _container.getFooterAtom();
return cs == null ? null : cs.getText();
}
/**
* Sets footers's text
*
* @param text footers's text
*/
public void setFootersText(String text){
if(_newRecord) attach();
setFooterVisible(true);
CString cs = _container.getFooterAtom();
if(cs == null) cs = _container.addFooterAtom();
cs.setText(text);
}
/**
* This is the date that the user wants in the footers, instead of today's date.
*
* @return custom user date
*/
public String getDateTimeText(){
CString cs = _container.getUserDateAtom();
return cs == null ? null : cs.getText();
}
/**
* Sets custom user date to be displayed instead of today's date.
*
* @param text custom user date
*/
public void setDateTimeText(String text){
if(_newRecord) attach();
setUserDateVisible(true);
setDateTimeVisible(true);
CString cs = _container.getUserDateAtom();
if(cs == null) cs = _container.addUserDateAtom();
cs.setText(text);
}
/**
* whether the footer text is displayed.
*/
public boolean isFooterVisible(){
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasFooter);
}
/**
* whether the footer text is displayed.
*/
public void setFooterVisible(boolean flag){
if(_newRecord) attach();
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasFooter, flag);
}
/**
* whether the header text is displayed.
*/
public boolean isHeaderVisible(){
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasHeader);
}
/**
* whether the header text is displayed.
*/
public void setHeaderVisible(boolean flag){
if(_newRecord) attach();
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasHeader, flag);
}
/**
* whether the date is displayed in the footer.
*/
public boolean isDateTimeVisible(){
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasDate);
}
/**
* whether the date is displayed in the footer.
*/
public void setDateTimeVisible(boolean flag){
if(_newRecord) attach();
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasDate, flag);
}
/**
* whether the custom user date is used instead of today's date.
*/
public boolean isUserDateVisible(){
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasUserDate);
}
/**
* whether the date is displayed in the footer.
*/
public void setUserDateVisible(boolean flag){
if(_newRecord) attach();
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasUserDate, flag);
}
/**
* whether the slide number is displayed in the footer.
*/
public boolean isSlideNumberVisible(){
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasSlideNumber);
}
/**
* whether the slide number is displayed in the footer.
*/
public void setSlideNumberVisible(boolean flag){
if(_newRecord) attach();
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasSlideNumber, flag);
}
/**
* An integer that specifies the format ID to be used to style the datetime.
*
* @return an integer that specifies the format ID to be used to style the datetime.
*/
public int getDateTimeFormat(){
return _container.getHeadersFootersAtom().getFormatId();
}
/**
* An integer that specifies the format ID to be used to style the datetime.
*
* @param formatId an integer that specifies the format ID to be used to style the datetime.
*/
public void setDateTimeFormat(int formatId){
if(_newRecord) attach();
_container.getHeadersFootersAtom().setFormatId(formatId);
}
/**
* Attach this HeadersFootersContainer to the parent Document record
*/
private void attach(){
Document doc = _ppt.getDocumentRecord();
Record[] ch = doc.getChildRecords();
Record lst = null;
for (int i=0; i < ch.length; i++){
if(ch[i].getRecordType() == RecordTypes.List.typeID){
lst = ch[i];
break;
}
}
doc.addChildAfter(_container, lst);
_newRecord = false;
}
}

View File

@ -24,9 +24,7 @@ import java.util.Vector;
import java.util.Iterator; import java.util.Iterator;
import java.awt.*; import java.awt.*;
import org.apache.poi.hslf.record.SlideAtom; import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
import org.apache.poi.ddf.EscherDggRecord; import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherContainerRecord;
@ -381,4 +379,22 @@ public class Slide extends Sheet
} }
} }
/**
* Header / Footer settings for this slide.
*
* @return Header / Footer settings for this slide
*/
public HeadersFooters getHeadersFooters(){
HeadersFootersContainer hdd = null;
Record[] ch = getSheetContainer().getChildRecords();
for (int i = 0; i < ch.length; i++) {
if(ch[i] instanceof HeadersFootersContainer){
hdd = (HeadersFootersContainer)ch[i];
break;
}
}
boolean newRecord = false;
if(hdd == null) return getSlideShow().getSlideHeadersFooters();
else return new HeadersFooters(hdd, getSlideShow(), newRecord);
}
} }

View File

@ -56,7 +56,7 @@ public class CString extends RecordAtom {
* Grabs the count, from the first two bytes of the header. * Grabs the count, from the first two bytes of the header.
* The meaning of the count is specific to the type of the parent record * The meaning of the count is specific to the type of the parent record
*/ */
public int getCount() { public int getOptions() {
return (int)LittleEndian.getShort(_header); return (int)LittleEndian.getShort(_header);
} }
@ -64,7 +64,7 @@ public class CString extends RecordAtom {
* Sets the count * Sets the count
* The meaning of the count is specific to the type of the parent record * The meaning of the count is specific to the type of the parent record
*/ */
public void setCount(int count) { public void setOptions(int count) {
LittleEndian.putShort(_header, (short)count); LittleEndian.putShort(_header, (short)count);
} }

View File

@ -140,9 +140,9 @@ public class Comment2000 extends RecordContainer {
CString csa = new CString(); CString csa = new CString();
CString csb = new CString(); CString csb = new CString();
CString csc = new CString(); CString csc = new CString();
csa.setCount(0x00); csa.setOptions(0x00);
csb.setCount(0x10); csb.setOptions(0x10);
csc.setCount(0x20); csc.setOptions(0x20);
_children[0] = csa; _children[0] = csa;
_children[1] = csb; _children[1] = csb;
_children[2] = csc; _children[2] = csc;

View File

@ -74,8 +74,8 @@ public class ExEmbed extends RecordContainer {
CString cs1 = new CString(); CString cs1 = new CString();
CString cs2 = new CString(); CString cs2 = new CString();
CString cs3 = new CString(); CString cs3 = new CString();
// cs1.setCount(0x00); // cs1.setOptions(0x00);
// cs2.setCount(0x10); // cs2.setOptions(0x10);
_children[0] = new ExEmbedAtom(); _children[0] = new ExEmbedAtom();
_children[1] = new ExOleObjAtom(); _children[1] = new ExOleObjAtom();
_children[2] = cs1; _children[2] = cs1;

View File

@ -136,8 +136,8 @@ public class ExHyperlink extends RecordContainer {
// Setup our child records // Setup our child records
CString csa = new CString(); CString csa = new CString();
CString csb = new CString(); CString csb = new CString();
csa.setCount(0x00); csa.setOptions(0x00);
csb.setCount(0x10); csb.setOptions(0x10);
_children[0] = new ExHyperlinkAtom(); _children[0] = new ExHyperlinkAtom();
_children[1] = csa; _children[1] = csa;
_children[2] = csb; _children[2] = csb;

View File

@ -0,0 +1,207 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import org.apache.poi.util.LittleEndian;
import java.io.IOException;
import java.io.OutputStream;
/**
* An atom record that specifies options for displaying headers and footers
* on a presentation slide or notes slide.
*
* @author Yegor Kozlov
*/
public class HeadersFootersAtom extends RecordAtom {
/**
* A bit that specifies whether the date is displayed in the footer.
* @see {@link #getMask()}, {@link #setMask(int)}},
*/
public static final int fHasDate = 1;
/**
* A bit that specifies whether the current datetime is used for displaying the datetime.
* @see {@link #getMask()}, {@link #setMask(int)}},
*/
public static final int fHasTodayDate = 2;
/**
* A bit that specifies whether the date specified in UserDateAtom record
* is used for displaying the datetime.
*
* @see {@link #getMask()}, {@link #setMask(int)}},
*/
public static final int fHasUserDate = 4;
/**
* A bit that specifies whether the slide number is displayed in the footer.
*
* @see {@link #getMask()}, {@link #setMask(int)}},
*/
public static final int fHasSlideNumber = 8;
/**
* bit that specifies whether the header text is displayed.
*
* @see {@link #getMask()}, {@link #setMask(int)}},
*/
public static final int fHasHeader = 16;
/**
* bit that specifies whether the footer text is displayed.
*
* @see {@link #getMask()}, {@link #setMask(int)}},
*/
public static final int fHasFooter = 32;
/**
* record header
*/
private byte[] _header;
/**
* record data
*/
private byte[] _recdata;
/**
* Build an instance of <code>HeadersFootersAtom</code> from on-disk data
*/
protected HeadersFootersAtom(byte[] source, int start, int len) {
// Get the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Grab the record data
_recdata = new byte[len-8];
System.arraycopy(source,start+8,_recdata,0,len-8);
}
/**
* Create a new instance of <code>HeadersFootersAtom</code>
*/
public HeadersFootersAtom() {
_recdata = new byte[4];
_header = new byte[8];
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _recdata.length);
}
public long getRecordType() {
return RecordTypes.HeadersFootersAtom.typeID;
}
/**
* Write the contents of the record back, so it can be written to disk
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
out.write(_recdata);
}
/**
* A signed integer that specifies the format ID to be used to style the datetime.
* <p>
* It MUST be in the range [0, 12]. </br>
* This value is converted into a string as specified by the index field of the DateTimeMCAtom record.
* It MUST be ignored unless fHasTodayDate is TRUE.
* </b>
*
* @return A signed integer that specifies the format ID to be used to style the datetime.
*/
public int getFormatId(){
return LittleEndian.getShort(_recdata, 0);
}
/**
* A signed integer that specifies the format ID to be used to style the datetime.
*
* @param formatId A signed integer that specifies the format ID to be used to style the datetime.
*/
public void setFormatId(int formatId){
LittleEndian.putUShort(_recdata, 0, formatId);
}
/**
* A bit mask specifying options for displaying headers and footers
*
* <li> A - {@link #fHasDate} (1 bit): A bit that specifies whether the date is displayed in the footer.
* <li> B - {@link #fHasTodayDate} (1 bit): A bit that specifies whether the current datetime is used for
* displaying the datetime.
* <li> C - {@link #fHasUserDate} (1 bit): A bit that specifies whether the date specified in UserDateAtom record
* is used for displaying the datetime.
* <li> D - {@link #fHasSlideNumber} (1 bit): A bit that specifies whether the slide number is displayed in the footer.
* <li> E - {@link #fHasHeader} (1 bit): A bit that specifies whether the header text specified by HeaderAtom
* record is displayed.
* <li> F - {@link #fHasFooter} (1 bit): A bit that specifies whether the footer text specified by FooterAtom
* record is displayed.
* <li> reserved (10 bits): MUST be zero and MUST be ignored.
*
* @return A bit mask specifying options for displaying headers and footers
*/
public int getMask(){
return LittleEndian.getShort(_recdata, 2);
}
/**
* A bit mask specifying options for displaying headers and footers
*
* @param mask A bit mask specifying options for displaying headers and footers
*/
public void setMask(int mask){
LittleEndian.putUShort(_recdata, 2, mask);
}
/**
* @param bit the bit to check
* @return whether the specified flag is set
*/
public boolean getFlag(int bit){
return (getMask() & bit) != 0;
}
/**
* @param bit the bit to set
* @param value whether the specified bit is set
*/
public void setFlag(int bit, boolean value){
int mask = getMask();
if(value) mask |= bit;
else mask &= ~bit;
setMask(mask);
}
public String toString(){
StringBuffer buf = new StringBuffer();
buf.append("HeadersFootersAtom\n");
buf.append("\tFormatId: " + getFormatId() + "\n");
buf.append("\tMask : " + getMask() + "\n");
buf.append("\t fHasDate : " + getFlag(fHasDate) + "\n");
buf.append("\t fHasTodayDate : " + getFlag(fHasTodayDate) + "\n");
buf.append("\t fHasUserDate : " + getFlag(fHasUserDate) + "\n");
buf.append("\t fHasSlideNumber : " + getFlag(fHasSlideNumber) + "\n");
buf.append("\t fHasHeader : " + getFlag(fHasHeader) + "\n");
buf.append("\t fHasFooter : " + getFlag(fHasFooter) + "\n");
return buf.toString();
}
}

View File

@ -0,0 +1,212 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
import java.io.OutputStream;
import java.io.IOException;
/**
* A container record that specifies information about the footers on a presentation slide.
* <p>
* It contains:<br>
* <li> 1. {@link HeadersFootersAtom}
* <li> 2. {@link CString }, Instance UserDate (0), optional: Stores the user's date.
* This is the date that the user wants in the footers, instead of today's date.
* <li> 3. {@link CString }, Instance Header (1), optional: Stores the Header's contents.
* <li> 4. {@link CString }, Instance Footer (2), optional: Stores the Footer's contents.
* </p>
*
* @author Yegor Kozlov
*/
public class HeadersFootersContainer extends RecordContainer {
/**
* "instance" field in the record header indicating that this HeadersFootersContaine
* is applied for slides
*/
public static final short SlideHeadersFootersContainer = 0x3F;
/**
* "instance" field in the record header indicating that this HeadersFootersContaine
* is applied for notes and handouts
*/
public static final short NotesHeadersFootersContainer = 0x4F;
public static final int USERDATEATOM = 0;
public static final int HEADERATOM = 1;
public static final int FOOTERATOM = 2;
private byte[] _header;
private HeadersFootersAtom hdAtom;
private CString csDate, csHeader, csFooter;
protected HeadersFootersContainer(byte[] source, int start, int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
_children = Record.findChildRecords(source,start+8,len-8);
for(int i=0; i < _children.length; i++){
if(_children[i] instanceof HeadersFootersAtom) hdAtom = (HeadersFootersAtom)_children[i];
else if(_children[i] instanceof CString) {
CString cs = (CString)_children[i];
int opts = cs.getOptions() >> 4;
switch(opts){
case USERDATEATOM: csDate = cs; break;
case HEADERATOM: csHeader = cs; break;
case FOOTERATOM: csFooter = cs; break;
default:
logger.log(POILogger.WARN, "Unexpected CString.Options in HeadersFootersContainer: " + opts);
break;
}
} else {
logger.log(POILogger.WARN, "Unexpected record in HeadersFootersContainer: " + _children[i]);
}
}
}
public HeadersFootersContainer(short options) {
_header = new byte[8];
LittleEndian.putShort(_header, 0, options);
LittleEndian.putShort(_header, 2, (short)getRecordType());
hdAtom = new HeadersFootersAtom();
_children = new Record[]{
hdAtom
};
csDate = csHeader = csFooter = null;
}
/**
* Return the type, which is <code>{@link RecordTypes#HeadersFooters}</code>
*/
public long getRecordType() {
return RecordTypes.HeadersFooters.typeID;
}
/**
* Must be either {@link #SlideHeadersFootersContainer} or {@link #NotesHeadersFootersContainer}
*
* @return "instance" field in the record header
*/
public int getOptions(){
return LittleEndian.getShort(_header, 0);
}
/**
* Write the contents of the record back, so it can be written to disk
*/
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],getRecordType(),_children,out);
}
/**
* HeadersFootersAtom stores the basic information of the header and footer structure.
*
* @return <code>HeadersFootersAtom</code>
*/
public HeadersFootersAtom getHeadersFootersAtom(){
return hdAtom;
}
/**
* A {@link CString} record that stores the user's date.
* <p>This is the date that the user wants in the footers, instead of today's date.</p>
*
* @return A {@link CString} record that stores the user's date or <code>null</code>
*/
public CString getUserDateAtom(){
return csDate;
}
/**
* A {@link CString} record that stores the Header's contents.
*
* @return A {@link CString} record that stores the Header's contents or <code>null</code>
*/
public CString getHeaderAtom(){
return csHeader;
}
/**
* A {@link CString} record that stores the Footers's contents.
*
* @return A {@link CString} record that stores the Footers's contents or <code>null</code>
*/
public CString getFooterAtom(){
return csFooter;
}
/**
* Insert a {@link CString} record that stores the user's date.
*
* @return the created {@link CString} record that stores the user's date.
*/
public CString addUserDateAtom(){
if(csDate != null) return csDate;
csDate = new CString();
csDate.setOptions(USERDATEATOM << 4);
addChildAfter(csDate, hdAtom);
return csDate;
}
/**
* Insert a {@link CString} record that stores the user's date.
*
* @return the created {@link CString} record that stores the user's date.
*/
public CString addHeaderAtom(){
if(csHeader != null) return csHeader;
csHeader = new CString();
csHeader.setOptions(HEADERATOM << 4);
Record r = hdAtom;
if(csDate != null) r = hdAtom;
addChildAfter(csHeader, r);
return csHeader;
}
/**
* Insert a {@link CString} record that stores the user's date.
*
* @return the created {@link CString} record that stores the user's date.
*/
public CString addFooterAtom(){
if(csFooter != null) return csFooter;
csFooter = new CString();
csFooter.setOptions(FOOTERATOM << 4);
Record r = hdAtom;
if(csHeader != null) r = csHeader;
else if(csDate != null) r = csDate;
addChildAfter(csFooter, r);
return csFooter;
}
}

View File

@ -111,8 +111,8 @@ public class RecordTypes {
public static final Type ExHyperlinkAtom = new Type(4051,ExHyperlinkAtom.class); public static final Type ExHyperlinkAtom = new Type(4051,ExHyperlinkAtom.class);
public static final Type ExHyperlink = new Type(4055,ExHyperlink.class); public static final Type ExHyperlink = new Type(4055,ExHyperlink.class);
public static final Type SlideNumberMCAtom = new Type(4056,null); public static final Type SlideNumberMCAtom = new Type(4056,null);
public static final Type HeadersFooters = new Type(4057,null); public static final Type HeadersFooters = new Type(4057,HeadersFootersContainer.class);
public static final Type HeadersFootersAtom = new Type(4058,null); public static final Type HeadersFootersAtom = new Type(4058,HeadersFootersAtom.class);
public static final Type TxInteractiveInfoAtom = new Type(4063,TxInteractiveInfoAtom.class); public static final Type TxInteractiveInfoAtom = new Type(4063,TxInteractiveInfoAtom.class);
public static final Type CharFormatAtom = new Type(4066,null); public static final Type CharFormatAtom = new Type(4066,null);
public static final Type ParaFormatAtom = new Type(4067,null); public static final Type ParaFormatAtom = new Type(4067,null);

View File

@ -811,4 +811,50 @@ public class SlideShow
public int getNumberOfFonts() { public int getNumberOfFonts() {
return getDocumentRecord().getEnvironment().getFontCollection().getNumberOfFonts(); return getDocumentRecord().getEnvironment().getFontCollection().getNumberOfFonts();
} }
/**
* Return Header / Footer settings for slides
*
* @return Header / Footer settings for slides
*/
public HeadersFooters getSlideHeadersFooters(){
HeadersFootersContainer hdd = null;
Record[] ch = _documentRecord.getChildRecords();
for (int i = 0; i < ch.length; i++) {
if(ch[i] instanceof HeadersFootersContainer &&
((HeadersFootersContainer)ch[i]).getOptions() == HeadersFootersContainer.SlideHeadersFootersContainer){
hdd = (HeadersFootersContainer)ch[i];
break;
}
}
boolean newRecord = false;
if(hdd == null) {
hdd = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);
newRecord = true;
}
return new HeadersFooters(hdd, this, newRecord);
}
/**
* Return Header / Footer settings for notes
*
* @return Header / Footer settings for notes
*/
public HeadersFooters getNotesHeadersFooters(){
HeadersFootersContainer hdd = null;
Record[] ch = _documentRecord.getChildRecords();
for (int i = 0; i < ch.length; i++) {
if(ch[i] instanceof HeadersFootersContainer &&
((HeadersFootersContainer)ch[i]).getOptions() == HeadersFootersContainer.NotesHeadersFootersContainer){
hdd = (HeadersFootersContainer)ch[i];
break;
}
}
boolean newRecord = false;
if(hdd == null) {
hdd = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer);
newRecord = true;
}
return new HeadersFooters(hdd, this, newRecord);
}
} }

View File

@ -0,0 +1,118 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import java.io.*;
import org.apache.poi.hslf.usermodel.SlideShow;
import junit.framework.TestCase;
/**
* Test {@link org.apache.poi.hslf.model.HeadersFooters} object
*/
public class TestHeadersFooters extends TestCase
{
public static final String cwd = System.getProperty("HSLF.testdata.path");
public void testRead() throws Exception
{
File file = new File(cwd, "headers_footers.ppt");
FileInputStream is = new FileInputStream(file);
SlideShow ppt = new SlideShow(is);
is.close();
HeadersFooters slideHdd = ppt.getSlideHeadersFooters();
assertTrue(slideHdd.isFooterVisible());
assertEquals("Global Slide Footer", slideHdd.getFooterText());
assertTrue(slideHdd.isSlideNumberVisible());
assertFalse(slideHdd.isHeaderVisible());
assertNull(slideHdd.getHeaderText());
assertFalse(slideHdd.isUserDateVisible());
assertNull(slideHdd.getDateTimeText());
HeadersFooters notesHdd = ppt.getNotesHeadersFooters();
assertTrue(notesHdd.isFooterVisible());
assertEquals("Notes Footer", notesHdd.getFooterText());
assertTrue(notesHdd.isHeaderVisible());
assertEquals("Notes Header", notesHdd.getHeaderText());
assertTrue(notesHdd.isUserDateVisible());
assertNull(notesHdd.getDateTimeText());
Slide[] slide = ppt.getSlides();
//the first slide uses presentation-scope headers / footers
HeadersFooters hd1 = slide[0].getHeadersFooters();
assertEquals(slideHdd.isFooterVisible(), hd1.isFooterVisible());
assertEquals(slideHdd.getFooterText(), hd1.getFooterText());
assertEquals(slideHdd.isSlideNumberVisible(), hd1.isSlideNumberVisible());
assertEquals(slideHdd.isHeaderVisible(), hd1.isHeaderVisible());
assertEquals(slideHdd.getHeaderText(), hd1.getHeaderText());
assertEquals(slideHdd.isUserDateVisible(), hd1.isUserDateVisible());
assertEquals(slideHdd.getDateTimeText(), hd1.getDateTimeText());
//the first slide uses per-slide headers / footers
HeadersFooters hd2 = slide[1].getHeadersFooters();
assertEquals(true, hd2.isFooterVisible());
assertEquals("per-slide footer", hd2.getFooterText());
assertEquals(true, hd2.isUserDateVisible());
assertEquals("custom date format", hd2.getDateTimeText());
}
public void testCreateSlideFooters() throws Exception
{
SlideShow ppt = new SlideShow();
HeadersFooters hdd = ppt.getSlideHeadersFooters();
hdd.setFootersText("My slide footer");
hdd.setSlideNumberVisible(true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
byte[] b = out.toByteArray();
SlideShow ppt2 = new SlideShow(new ByteArrayInputStream(b));
HeadersFooters hdd2 = ppt2.getSlideHeadersFooters();
assertTrue(hdd2.isSlideNumberVisible());
assertTrue(hdd2.isFooterVisible());
assertEquals("My slide footer", hdd2.getFooterText());
}
public void testCreateNotesFooters() throws Exception
{
SlideShow ppt = new SlideShow();
HeadersFooters hdd = ppt.getNotesHeadersFooters();
hdd.setFootersText("My notes footer");
hdd.setHeaderText("My notes header");
hdd.setSlideNumberVisible(true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
byte[] b = out.toByteArray();
SlideShow ppt2 = new SlideShow(new ByteArrayInputStream(b));
HeadersFooters hdd2 = ppt2.getNotesHeadersFooters();
assertTrue(hdd2.isSlideNumberVisible());
assertTrue(hdd2.isFooterVisible());
assertEquals("My notes footer", hdd2.getFooterText());
assertTrue(hdd2.isHeaderVisible());
assertEquals("My notes header", hdd2.getHeaderText());
}
}

View File

@ -46,12 +46,12 @@ public class TestCString extends TestCase {
} }
public void testCount() throws Exception { public void testCount() throws Exception {
CString ca = new CString(data_a, 0, data_a.length); CString ca = new CString(data_a, 0, data_a.length);
assertEquals(0, ca.getCount()); assertEquals(0, ca.getOptions());
CString cb = new CString(data_b, 0, data_a.length); CString cb = new CString(data_b, 0, data_a.length);
assertEquals(0x10, cb.getCount()); assertEquals(0x10, cb.getOptions());
ca.setCount(28); ca.setOptions(28);
assertEquals(28, ca.getCount()); assertEquals(28, ca.getOptions());
} }
public void testText() throws Exception { public void testText() throws Exception {
@ -90,7 +90,7 @@ public class TestCString extends TestCase {
public void testChange() throws Exception { public void testChange() throws Exception {
CString ca = new CString(data_a, 0, data_a.length); CString ca = new CString(data_a, 0, data_a.length);
ca.setText("Comments"); ca.setText("Comments");
ca.setCount(0x10); ca.setOptions(0x10);
try { try {
for(int i=0; i<data_a.length; i++) { for(int i=0; i<data_a.length; i++) {

View File

@ -0,0 +1,95 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
* Tests that {@link HeadersFootersAtom} works properly
*
* @author Yegor Kozlov
*/
public class TestHeadersFootersAtom extends TestCase {
// From a real file
private byte[] data = new byte[] {
0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 00,
0x00, 0x00, 0x23, 0x00 };
public void testRead() throws Exception {
HeadersFootersAtom record = new HeadersFootersAtom(data, 0, data.length);
assertEquals(RecordTypes.HeadersFootersAtom.typeID, record.getRecordType());
assertEquals(0, record.getFormatId());
assertEquals(0x23, record.getMask());
assertTrue(record.getFlag(HeadersFootersAtom.fHasDate));
assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));
assertFalse(record.getFlag(HeadersFootersAtom.fHasUserDate));
assertFalse(record.getFlag(HeadersFootersAtom.fHasSlideNumber));
assertFalse(record.getFlag(HeadersFootersAtom.fHasHeader));
assertTrue(record.getFlag(HeadersFootersAtom.fHasFooter));
}
public void testWrite() throws Exception {
HeadersFootersAtom record = new HeadersFootersAtom(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
HeadersFootersAtom record = new HeadersFootersAtom();
record.setFlag(HeadersFootersAtom.fHasDate, true);
record.setFlag(HeadersFootersAtom.fHasTodayDate, true);
record.setFlag(HeadersFootersAtom.fHasFooter, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testFlags() throws Exception {
HeadersFootersAtom record = new HeadersFootersAtom();
//in a new record all the bits are 0
for(int i = 0; i < 6; i++) assertFalse(record.getFlag(1 << i));
record.setFlag(HeadersFootersAtom.fHasTodayDate, true);
assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));
record.setFlag(HeadersFootersAtom.fHasTodayDate, true);
assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));
record.setFlag(HeadersFootersAtom.fHasTodayDate, false);
assertFalse(record.getFlag(HeadersFootersAtom.fHasTodayDate));
record.setFlag(HeadersFootersAtom.fHasTodayDate, false);
assertFalse(record.getFlag(HeadersFootersAtom.fHasTodayDate));
}
}

View File

@ -0,0 +1,171 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
* Tests that {@link HeadersFootersContainer} works properly
*
* @author Yegor Kozlov
*/
public class TestHeadersFootersContainer extends TestCase {
// SlideHeadersFootersContainer
private byte[] slideData = new byte[] {
0x3F, 0x00, (byte)0xD9, 0x0F, 0x2E, 0x00, 0x00, 0x00,
0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00,
0x20, 0x00, (byte)0xBA, 0x0F, 0x1A, 0x00, 0x00, 0x00,
0x4D, 0x00, 0x79, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74,
0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x2D, 0x00, 0x20, 0x00, 0x31, 0x00
};
// NotesHeadersFootersContainer
private byte[] notesData = new byte[] {
0x4F, 0x00, (byte)0xD9, 0x0F, 0x48, 0x00, 0x00, 0x00,
0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x10, 0x00, (byte)0xBA, 0x0F, 0x16, 0x00, 0x00, 0x00,
0x4E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x48, 0x00,
0x65, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00,
0x20, 0x00, (byte)0xBA, 0x0F, 0x16, 0x00, 0x00, 0x00,
0x4E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00,
0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00
};
public void testReadSlideHeadersFootersContainer() throws Exception {
HeadersFootersContainer record = new HeadersFootersContainer(slideData, 0, slideData.length);
assertEquals(RecordTypes.HeadersFooters.typeID, record.getRecordType());
assertEquals(HeadersFootersContainer.SlideHeadersFootersContainer, record.getOptions());
assertEquals(2, record.getChildRecords().length);
HeadersFootersAtom hdd = record.getHeadersFootersAtom();
assertNotNull(hdd);
CString csFooter = record.getFooterAtom();
assertNotNull(csFooter);
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
assertEquals("My Footer - 1", csFooter.getText());
assertNull(record.getUserDateAtom());
assertNull(record.getHeaderAtom());
}
public void testWriteSlideHeadersFootersContainer() throws Exception {
HeadersFootersContainer record = new HeadersFootersContainer(slideData, 0, slideData.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(slideData, b));
}
public void testNewSlideHeadersFootersContainer() throws Exception {
HeadersFootersContainer record = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);
assertNotNull(record.getHeadersFootersAtom());
assertNull(record.getUserDateAtom());
assertNull(record.getHeaderAtom());
assertNull(record.getFooterAtom());
HeadersFootersAtom hd = record.getHeadersFootersAtom();
hd.setFlag(HeadersFootersAtom.fHasDate, true);
hd.setFlag(HeadersFootersAtom.fHasTodayDate, true);
hd.setFlag(HeadersFootersAtom.fHasFooter, true);
CString csFooter = record.addFooterAtom();
assertNotNull(csFooter);
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
csFooter.setText("My Footer - 1");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(slideData, b));
}
public void testReadNotesHeadersFootersContainer() throws Exception {
HeadersFootersContainer record = new HeadersFootersContainer(notesData, 0, notesData.length);
assertEquals(RecordTypes.HeadersFooters.typeID, record.getRecordType());
assertEquals(HeadersFootersContainer.NotesHeadersFootersContainer, record.getOptions());
assertEquals(3, record.getChildRecords().length);
HeadersFootersAtom hdd = record.getHeadersFootersAtom();
assertNotNull(hdd);
CString csHeader = record.getHeaderAtom();
assertNotNull(csHeader);
assertEquals(HeadersFootersContainer.HEADERATOM, csHeader.getOptions() >> 4);
assertEquals("Note Header", csHeader.getText());
CString csFooter = record.getFooterAtom();
assertNotNull(csFooter);
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
assertEquals("Note Footer", csFooter.getText());
}
public void testWriteNotesHeadersFootersContainer() throws Exception {
HeadersFootersContainer record = new HeadersFootersContainer(notesData, 0, notesData.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(notesData, b));
}
public void testNewNotesHeadersFootersContainer() throws Exception {
HeadersFootersContainer record = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer);
assertNotNull(record.getHeadersFootersAtom());
assertNull(record.getUserDateAtom());
assertNull(record.getHeaderAtom());
assertNull(record.getFooterAtom());
HeadersFootersAtom hd = record.getHeadersFootersAtom();
hd.setFlag(HeadersFootersAtom.fHasDate, true);
hd.setFlag(HeadersFootersAtom.fHasTodayDate, false);
hd.setFlag(HeadersFootersAtom.fHasUserDate, true);
hd.setFlag(HeadersFootersAtom.fHasSlideNumber, true);
hd.setFlag(HeadersFootersAtom.fHasHeader, true);
hd.setFlag(HeadersFootersAtom.fHasFooter, true);
CString csHeader = record.addHeaderAtom();
assertNotNull(csHeader);
assertEquals(HeadersFootersContainer.HEADERATOM, csHeader.getOptions() >> 4);
csHeader.setText("Note Header");
CString csFooter = record.addFooterAtom();
assertNotNull(csFooter);
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
csFooter.setText("Note Footer");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(notesData, b));
}
}