]> source.dussan.org Git - poi.git/commitdiff
support for headers / footers in HSLF
authorYegor Kozlov <yegor@apache.org>
Mon, 4 Aug 2008 11:40:25 +0000 (11:40 +0000)
committerYegor Kozlov <yegor@apache.org>
Mon, 4 Aug 2008 11:40:25 +0000 (11:40 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@682336 13f79535-47bb-0310-9956-ffa450edef68

19 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/hslf/how-to-shapes.xml
src/documentation/content/xdocs/status.xml
src/scratchpad/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
src/scratchpad/src/org/apache/poi/hslf/record/CString.java
src/scratchpad/src/org/apache/poi/hslf/record/Comment2000.java
src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
src/scratchpad/src/org/apache/poi/hslf/record/ExHyperlink.java
src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersAtom.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers.ppt [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/record/TestCString.java
src/scratchpad/testcases/org/apache/poi/hslf/record/TestHeadersFootersAtom.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/record/TestHeadersFootersContainer.java [new file with mode: 0644]

index 77f9608e60bfd822dde478456a79913d7221b584..b4515d39c6612f978778d6b0a828f3a689cad291 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <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">45519 - Fixed to keep datavalidation records together</action>
            <action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
index 7959eedaf60539eeb30a5f00df5d1b18ff3cd8fe..40ef32aa75e9616432d43fe7a734500f33b2e9c1 100644 (file)
@@ -46,6 +46,7 @@
                     <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="#Render">How to convert slides into images</link></li>
+                    <li><link href="#HeadersFooters">Headers / Footers</link></li>
                 </ul>
             </section>
             <section><title>Features</title>
                   </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>
     </body>
 </document>
index ef4274eeacc7be133a289ac3033a0264e3054f5b..7dbddb6f8aac1f5e048d861ddb026b9df88457a7 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <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">45519 - Fixed to keep datavalidation records together</action>
            <action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java
new file mode 100644 (file)
index 0000000..3ebcecc
--- /dev/null
@@ -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();
+
+    }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java b/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java
new file mode 100644 (file)
index 0000000..e94bcb9
--- /dev/null
@@ -0,0 +1,226 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.hslf.record.*;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+\r
+/**\r
+ * Header / Footer settings.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class HeadersFooters {\r
+\r
+    private HeadersFootersContainer _container;\r
+    private boolean _newRecord;\r
+    private SlideShow _ppt;\r
+\r
+    public HeadersFooters(HeadersFootersContainer rec, SlideShow ppt, boolean newRecord){\r
+        _container = rec;\r
+        _newRecord = newRecord;\r
+        _ppt = ppt;\r
+    }\r
+\r
+    /**\r
+     * Headers's text\r
+     *\r
+     * @return Headers's text\r
+     */\r
+    public String getHeaderText(){\r
+       CString cs = _container.getHeaderAtom();\r
+       return cs == null ? null : cs.getText();\r
+    }\r
+\r
+    /**\r
+     * Sets headers's text\r
+     *\r
+     * @param text headers's text\r
+     */\r
+    public void setHeaderText(String text){\r
+        if(_newRecord) attach();\r
+\r
+        setHeaderVisible(true);\r
+        CString cs = _container.getHeaderAtom();\r
+        if(cs == null) cs = _container.addHeaderAtom();\r
+\r
+        cs.setText(text);\r
+    }\r
+\r
+    /**\r
+     * Footer's text\r
+     *\r
+     * @return Footer's text\r
+     */\r
+    public String getFooterText(){\r
+        CString cs = _container.getFooterAtom();\r
+        return cs == null ? null : cs.getText();\r
+    }\r
+\r
+    /**\r
+     * Sets footers's text\r
+     *\r
+     * @param text footers's text\r
+     */\r
+    public void setFootersText(String text){\r
+        if(_newRecord) attach();\r
+\r
+        setFooterVisible(true);\r
+        CString cs = _container.getFooterAtom();\r
+        if(cs == null) cs = _container.addFooterAtom();\r
+\r
+        cs.setText(text);\r
+    }\r
+\r
+    /**\r
+     * This is the date that the user wants in the footers, instead of today's date.\r
+     *\r
+     * @return custom user date\r
+     */\r
+    public String getDateTimeText(){\r
+        CString cs = _container.getUserDateAtom();\r
+        return cs == null ? null : cs.getText();\r
+    }\r
+\r
+    /**\r
+     * Sets custom user date to be displayed instead of today's date.\r
+     *\r
+     * @param text custom user date\r
+     */\r
+    public void setDateTimeText(String text){\r
+        if(_newRecord) attach();\r
+\r
+        setUserDateVisible(true);\r
+        setDateTimeVisible(true);\r
+        CString cs = _container.getUserDateAtom();\r
+        if(cs == null) cs = _container.addUserDateAtom();\r
+\r
+        cs.setText(text);\r
+    }\r
+\r
+    /**\r
+     * whether the footer text is displayed.\r
+     */\r
+    public boolean isFooterVisible(){\r
+        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasFooter);\r
+    }\r
+\r
+    /**\r
+     * whether the footer text is displayed.\r
+     */\r
+    public void setFooterVisible(boolean flag){\r
+        if(_newRecord) attach();\r
+        _container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasFooter, flag);\r
+    }\r
+\r
+    /**\r
+     * whether the header text is displayed.\r
+     */\r
+    public boolean isHeaderVisible(){\r
+        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasHeader);\r
+    }\r
+\r
+    /**\r
+     * whether the header text is displayed.\r
+     */\r
+    public void setHeaderVisible(boolean flag){\r
+        if(_newRecord) attach();\r
+        _container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasHeader, flag);\r
+    }\r
+\r
+    /**\r
+     * whether the date is displayed in the footer.\r
+     */\r
+    public boolean isDateTimeVisible(){\r
+        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasDate);\r
+    }\r
+\r
+    /**\r
+     * whether the date is displayed in the footer.\r
+     */\r
+    public void setDateTimeVisible(boolean flag){\r
+        if(_newRecord) attach();\r
+        _container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasDate, flag);\r
+    }\r
+\r
+    /**\r
+     * whether the custom user date is used instead of today's date.\r
+     */\r
+    public boolean isUserDateVisible(){\r
+        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasUserDate);\r
+    }\r
+\r
+    /**\r
+     * whether the date is displayed in the footer.\r
+     */\r
+    public void setUserDateVisible(boolean flag){\r
+        if(_newRecord) attach();\r
+        _container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasUserDate, flag);\r
+    }\r
+\r
+    /**\r
+     * whether the slide number is displayed in the footer.\r
+     */\r
+    public boolean isSlideNumberVisible(){\r
+        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasSlideNumber);\r
+    }\r
+\r
+    /**\r
+     * whether the slide number is displayed in the footer.\r
+     */\r
+    public void setSlideNumberVisible(boolean flag){\r
+        if(_newRecord) attach();\r
+        _container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasSlideNumber, flag);\r
+    }\r
+\r
+    /**\r
+     *  An integer that specifies the format ID to be used to style the datetime.\r
+     *\r
+     * @return an integer that specifies the format ID to be used to style the datetime.\r
+     */\r
+    public int getDateTimeFormat(){\r
+        return _container.getHeadersFootersAtom().getFormatId();\r
+    }\r
+\r
+    /**\r
+     *  An integer that specifies the format ID to be used to style the datetime.\r
+     *\r
+     * @param formatId an integer that specifies the format ID to be used to style the datetime.\r
+     */\r
+    public void setDateTimeFormat(int formatId){\r
+        if(_newRecord) attach();\r
+        _container.getHeadersFootersAtom().setFormatId(formatId);\r
+    }\r
+\r
+    /**\r
+     * Attach this HeadersFootersContainer to the parent Document record\r
+     */\r
+    private void attach(){\r
+        Document doc = _ppt.getDocumentRecord();\r
+        Record[] ch = doc.getChildRecords();\r
+        Record lst = null;\r
+        for (int i=0; i < ch.length; i++){\r
+            if(ch[i].getRecordType() == RecordTypes.List.typeID){\r
+                lst = ch[i];\r
+                break;\r
+            }\r
+        }\r
+        doc.addChildAfter(_container, lst);\r
+        _newRecord = false;\r
+    }\r
+}\r
index ee32868eb6353020659d5c889f7013ffcbdf41a2..670a86655a4465de55746ea2384b6997561a907d 100644 (file)
@@ -24,9 +24,7 @@ import java.util.Vector;
 import java.util.Iterator;
 import java.awt.*;
 
-import org.apache.poi.hslf.record.SlideAtom;
-import org.apache.poi.hslf.record.TextHeaderAtom;
-import org.apache.poi.hslf.record.ColorSchemeAtom;
+import org.apache.poi.hslf.record.*;
 import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
 import org.apache.poi.ddf.EscherDggRecord;
 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);
+    }
 }
index b17efc40bd42a6ec7d8586e93c11b1c75ac38c88..e7e46baa00b2409f0e0ee289770e234f09091dc4 100644 (file)
@@ -56,7 +56,7 @@ public class CString extends RecordAtom {
         * 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 
         */
-       public int getCount() {
+       public int getOptions() {
                return (int)LittleEndian.getShort(_header);
        }
        
@@ -64,7 +64,7 @@ public class CString extends RecordAtom {
         * Sets the count
         * 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);
        }
 
index 91ee8ea3a23fa1ae6a4e17a484f907499fd95e6a..31ef11a66c6ef8c7a86ca629278cac62f63c65d2 100644 (file)
@@ -140,9 +140,9 @@ public class Comment2000 extends RecordContainer {
                CString csa = new CString();
                CString csb = new CString();
                CString csc = new CString();
-               csa.setCount(0x00);
-               csb.setCount(0x10);
-               csc.setCount(0x20);
+               csa.setOptions(0x00);
+               csb.setOptions(0x10);
+               csc.setOptions(0x20);
                _children[0] = csa;
                _children[1] = csb;
                _children[2] = csc;
index 501712e9d5f410f7a81e7c5d880fe5ccb60a0bea..6d61f2ef71097bb5f554eae75cd20898fbbb3e0f 100644 (file)
@@ -74,8 +74,8 @@ public class ExEmbed extends RecordContainer {
         CString cs1 = new CString();
         CString cs2 = new CString();
         CString cs3 = new CString();
-//        cs1.setCount(0x00);
-//        cs2.setCount(0x10);
+//        cs1.setOptions(0x00);
+//        cs2.setOptions(0x10);
         _children[0] = new ExEmbedAtom();
         _children[1] = new ExOleObjAtom();
         _children[2] = cs1;
index 8ba58cdb61efaef31b13eee0da202a0cebd5f01c..b0bc1e191fbc6b5d583ab4c0ffd2fe4bbda8ea30 100644 (file)
@@ -136,8 +136,8 @@ public class ExHyperlink extends RecordContainer {
                // Setup our child records
                CString csa = new CString();
                CString csb = new CString();
-               csa.setCount(0x00);
-               csb.setCount(0x10);
+               csa.setOptions(0x00);
+               csb.setOptions(0x10);
                _children[0] = new ExHyperlinkAtom();
                _children[1] = csa;
                _children[2] = csb;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersAtom.java
new file mode 100644 (file)
index 0000000..a9457a6
--- /dev/null
@@ -0,0 +1,207 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+        \r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+/**\r
+ * An atom record that specifies options for displaying headers and footers\r
+ * on a presentation slide or notes slide.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+\r
+public class HeadersFootersAtom extends RecordAtom {\r
+\r
+    /**\r
+     * A bit that specifies whether the date is displayed in the footer.\r
+     * @see {@link #getMask()}, {@link #setMask(int)}},\r
+     */\r
+    public static final int fHasDate = 1;\r
+\r
+    /**\r
+     * A bit that specifies whether the current datetime is used for displaying the datetime.\r
+     * @see {@link #getMask()}, {@link #setMask(int)}},\r
+     */\r
+    public static final int fHasTodayDate = 2;\r
+\r
+    /**\r
+     * A bit that specifies whether the date specified in UserDateAtom record\r
+     * is used for displaying the datetime.\r
+     *\r
+     * @see {@link #getMask()}, {@link #setMask(int)}},\r
+     */\r
+     public static final int fHasUserDate = 4;\r
+\r
+    /**\r
+     * A bit that specifies whether the slide number is displayed in the footer.\r
+     * \r
+     * @see {@link #getMask()}, {@link #setMask(int)}},\r
+     */\r
+    public static final int fHasSlideNumber = 8;\r
+\r
+    /**\r
+     * bit that specifies whether the header text is displayed.\r
+     *\r
+     * @see {@link #getMask()}, {@link #setMask(int)}},\r
+     */\r
+    public static final int fHasHeader = 16;\r
+\r
+    /**\r
+     * bit that specifies whether the footer text is displayed.\r
+     *\r
+     * @see {@link #getMask()}, {@link #setMask(int)}},\r
+     */\r
+    public static final int fHasFooter = 32;\r
+\r
+    /**\r
+     * record header\r
+     */\r
+    private byte[] _header;\r
+\r
+       /**\r
+     * record data\r
+     */\r
+       private byte[] _recdata;\r
+\r
+    /**\r
+     * Build an instance of <code>HeadersFootersAtom</code> from on-disk data\r
+     */\r
+       protected HeadersFootersAtom(byte[] source, int start, int len) {\r
+               // Get the header\r
+               _header = new byte[8];\r
+               System.arraycopy(source,start,_header,0,8);\r
+\r
+               // Grab the record data\r
+               _recdata = new byte[len-8];\r
+               System.arraycopy(source,start+8,_recdata,0,len-8);\r
+       }\r
+\r
+    /**\r
+     * Create a new instance of <code>HeadersFootersAtom</code>\r
+     */\r
+    public HeadersFootersAtom() {\r
+        _recdata = new byte[4];\r
+\r
+        _header = new byte[8];\r
+        LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+        LittleEndian.putInt(_header, 4, _recdata.length);\r
+    }\r
+\r
+    public long getRecordType() {\r
+        return RecordTypes.HeadersFootersAtom.typeID;\r
+    }\r
+\r
+    /**\r
+        * Write the contents of the record back, so it can be written to disk\r
+        */\r
+       public void writeOut(OutputStream out) throws IOException {\r
+               out.write(_header);\r
+               out.write(_recdata);\r
+       }\r
+\r
+    /**\r
+     * A signed integer that specifies the format ID to be used to style the datetime.\r
+     * <p>\r
+     * It MUST be in the range [0, 12]. </br>\r
+     * This value is converted into a string as specified by the index field of the DateTimeMCAtom record.\r
+     * It MUST be ignored unless fHasTodayDate is TRUE.\r
+     * </b>\r
+     *\r
+     * @return  A signed integer that specifies the format ID to be used to style the datetime.\r
+     */\r
+    public int getFormatId(){\r
+        return LittleEndian.getShort(_recdata, 0);\r
+    }\r
+\r
+    /**\r
+     * A signed integer that specifies the format ID to be used to style the datetime.\r
+     *\r
+     * @param formatId  A signed integer that specifies the format ID to be used to style the datetime.\r
+     */\r
+    public void setFormatId(int formatId){\r
+         LittleEndian.putUShort(_recdata, 0, formatId);\r
+    }\r
+\r
+    /**\r
+     *  A bit mask specifying options for displaying headers and footers\r
+     *\r
+     * <li> A - {@link #fHasDate} (1 bit): A bit that specifies whether the date is displayed in the footer.\r
+     * <li> B - {@link #fHasTodayDate} (1 bit): A bit that specifies whether the current datetime is used for\r
+     *      displaying the datetime.\r
+     * <li> C - {@link #fHasUserDate} (1 bit): A bit that specifies whether the date specified in UserDateAtom record\r
+     *      is used for displaying the datetime.\r
+     * <li> D - {@link #fHasSlideNumber} (1 bit): A bit that specifies whether the slide number is displayed in the footer.\r
+     * <li> E - {@link #fHasHeader} (1 bit): A bit that specifies whether the header text specified by HeaderAtom\r
+     *      record is displayed.\r
+     * <li> F - {@link #fHasFooter} (1 bit): A bit that specifies whether the footer text specified by FooterAtom\r
+     *      record is displayed.\r
+     * <li> reserved (10 bits): MUST be zero and MUST be ignored.\r
+     *\r
+     * @return A bit mask specifying options for displaying headers and footers\r
+     */\r
+    public int getMask(){\r
+        return LittleEndian.getShort(_recdata, 2);\r
+    }\r
+\r
+    /**\r
+     *  A bit mask specifying options for displaying headers and footers\r
+     *\r
+     * @param mask A bit mask specifying options for displaying headers and footers\r
+     */\r
+    public void setMask(int mask){\r
+        LittleEndian.putUShort(_recdata, 2, mask);\r
+    }\r
+\r
+    /**\r
+     * @param bit the bit to check\r
+     * @return whether the specified flag is set\r
+     */\r
+    public boolean getFlag(int bit){\r
+        return (getMask() & bit) != 0;\r
+    }\r
+\r
+    /**\r
+     * @param  bit the bit to set\r
+     * @param  value whether the specified bit is set\r
+     */\r
+    public void setFlag(int bit, boolean value){\r
+        int mask = getMask();\r
+        if(value) mask |= bit;\r
+        else mask &= ~bit;\r
+        setMask(mask);\r
+    }\r
+\r
+    public String toString(){\r
+        StringBuffer buf = new StringBuffer();\r
+        buf.append("HeadersFootersAtom\n");\r
+        buf.append("\tFormatId: " + getFormatId() + "\n");\r
+        buf.append("\tMask    : " + getMask() + "\n");\r
+        buf.append("\t  fHasDate        : " + getFlag(fHasDate) + "\n");\r
+        buf.append("\t  fHasTodayDate   : " + getFlag(fHasTodayDate) + "\n");\r
+        buf.append("\t  fHasUserDate    : " + getFlag(fHasUserDate) + "\n");\r
+        buf.append("\t  fHasSlideNumber : " + getFlag(fHasSlideNumber) + "\n");\r
+        buf.append("\t  fHasHeader      : " + getFlag(fHasHeader) + "\n");\r
+        buf.append("\t  fHasFooter      : " + getFlag(fHasFooter) + "\n");\r
+        return buf.toString();\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java b/src/scratchpad/src/org/apache/poi/hslf/record/HeadersFootersContainer.java
new file mode 100644 (file)
index 0000000..e121574
--- /dev/null
@@ -0,0 +1,212 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.POILogger;\r
+\r
+import java.io.OutputStream;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * A container record that specifies information about the footers on a presentation slide.\r
+ * <p>\r
+ * It contains:<br>\r
+ * <li> 1. {@link HeadersFootersAtom}\r
+ * <li> 2. {@link CString }, Instance UserDate (0), optional: Stores the user's date.\r
+ *    This is the date that the user wants in the footers, instead of today's date.\r
+ * <li> 3. {@link CString }, Instance Header (1), optional: Stores the Header's contents.\r
+ * <li> 4. {@link CString }, Instance Footer (2), optional: Stores the Footer's contents.\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class HeadersFootersContainer extends RecordContainer {\r
+\r
+    /**\r
+     * "instance" field in the record header indicating that this HeadersFootersContaine\r
+     *  is applied for slides\r
+     */\r
+    public static final short SlideHeadersFootersContainer = 0x3F;\r
+    /**\r
+      * "instance" field in the record header indicating that this HeadersFootersContaine\r
+     *   is applied for notes and handouts\r
+      */\r
+    public static final short NotesHeadersFootersContainer = 0x4F;\r
+\r
+    public static final int USERDATEATOM    = 0;\r
+    public static final int HEADERATOM      = 1;\r
+    public static final int FOOTERATOM      = 2;\r
+\r
+    private byte[] _header;\r
+    private HeadersFootersAtom hdAtom;\r
+    private CString csDate, csHeader, csFooter;\r
+\r
+    protected HeadersFootersContainer(byte[] source, int start, int len) {\r
+        // Grab the header\r
+        _header = new byte[8];\r
+        System.arraycopy(source,start,_header,0,8);\r
+\r
+        _children = Record.findChildRecords(source,start+8,len-8);\r
+        for(int i=0; i < _children.length; i++){\r
+            if(_children[i] instanceof HeadersFootersAtom) hdAtom = (HeadersFootersAtom)_children[i];\r
+            else if(_children[i] instanceof CString) {\r
+                CString cs = (CString)_children[i];\r
+                int opts = cs.getOptions() >> 4;\r
+                switch(opts){\r
+                    case USERDATEATOM: csDate = cs; break;\r
+                    case HEADERATOM: csHeader = cs; break;\r
+                    case FOOTERATOM: csFooter = cs; break;\r
+                    default:\r
+                        logger.log(POILogger.WARN, "Unexpected CString.Options in HeadersFootersContainer: " + opts);\r
+                        break;\r
+                }\r
+            } else {\r
+                logger.log(POILogger.WARN, "Unexpected record in HeadersFootersContainer: " + _children[i]);\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    public HeadersFootersContainer(short options) {\r
+        _header = new byte[8];\r
+        LittleEndian.putShort(_header, 0, options);\r
+        LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+\r
+        hdAtom = new HeadersFootersAtom();\r
+        _children = new Record[]{\r
+            hdAtom\r
+        };\r
+        csDate = csHeader = csFooter = null;\r
+\r
+    }\r
+\r
+    /**\r
+     * Return the type, which is <code>{@link RecordTypes#HeadersFooters}</code>\r
+     */\r
+    public long getRecordType() {\r
+        return RecordTypes.HeadersFooters.typeID;\r
+    }\r
+\r
+    /**\r
+     * Must be either {@link #SlideHeadersFootersContainer} or {@link #NotesHeadersFootersContainer}\r
+     *\r
+     * @return "instance" field in the record header\r
+     */\r
+    public int getOptions(){\r
+        return LittleEndian.getShort(_header, 0);\r
+    }\r
+\r
+    /**\r
+     * Write the contents of the record back, so it can be written to disk\r
+     */\r
+    public void writeOut(OutputStream out) throws IOException {\r
+        writeOut(_header[0],_header[1],getRecordType(),_children,out);\r
+    }\r
+\r
+    /**\r
+     * HeadersFootersAtom stores the basic information of the header and footer structure.\r
+     *\r
+     * @return <code>HeadersFootersAtom</code>\r
+     */\r
+    public HeadersFootersAtom getHeadersFootersAtom(){\r
+        return hdAtom;\r
+    }\r
+\r
+    /**\r
+     * A {@link CString} record that stores the user's date.\r
+     * <p>This is the date that the user wants in the footers, instead of today's date.</p>\r
+     *\r
+     * @return A {@link CString} record that stores the user's date or <code>null</code>\r
+     */\r
+    public CString getUserDateAtom(){\r
+        return csDate;\r
+    }\r
+\r
+    /**\r
+     * A {@link CString} record that stores the Header's contents.\r
+     *\r
+     * @return A {@link CString} record that stores the Header's contents or <code>null</code>\r
+     */\r
+    public CString getHeaderAtom(){\r
+        return csHeader;\r
+    }\r
+\r
+    /**\r
+     * A {@link CString} record that stores the Footers's contents.\r
+     *\r
+     * @return A {@link CString} record that stores the Footers's contents or <code>null</code>\r
+     */\r
+    public CString getFooterAtom(){\r
+        return csFooter;\r
+    }\r
+\r
+    /**\r
+     * Insert a {@link CString} record that stores the user's date.\r
+     *\r
+     * @return  the created {@link CString} record that stores the user's date.\r
+     */\r
+    public CString addUserDateAtom(){\r
+        if(csDate != null) return csDate;\r
+\r
+        csDate = new CString();\r
+        csDate.setOptions(USERDATEATOM << 4);\r
+\r
+        addChildAfter(csDate, hdAtom);\r
+\r
+        return csDate;\r
+    }\r
+\r
+    /**\r
+     * Insert a {@link CString} record that stores the user's date.\r
+     *\r
+     * @return  the created {@link CString} record that stores the user's date.\r
+     */\r
+    public CString addHeaderAtom(){\r
+        if(csHeader != null) return csHeader;\r
+\r
+        csHeader = new CString();\r
+        csHeader.setOptions(HEADERATOM << 4);\r
+\r
+        Record r = hdAtom;\r
+        if(csDate != null) r = hdAtom;\r
+        addChildAfter(csHeader, r);\r
+\r
+        return csHeader;\r
+    }\r
+\r
+    /**\r
+     * Insert a {@link CString} record that stores the user's date.\r
+     *\r
+     * @return  the created {@link CString} record that stores the user's date.\r
+     */\r
+    public CString addFooterAtom(){\r
+        if(csFooter != null) return csFooter;\r
+\r
+        csFooter = new CString();\r
+        csFooter.setOptions(FOOTERATOM << 4);\r
+\r
+        Record r = hdAtom;\r
+        if(csHeader != null) r = csHeader;\r
+        else if(csDate != null) r = csDate;\r
+        addChildAfter(csFooter, r);\r
+\r
+        return csFooter;\r
+    }\r
+}\r
index a6f00da124da26cb05072dce6a74d2d9cb89642b..d7a664725e9e12097ecf52d45d212aec33ed8c38 100644 (file)
@@ -111,8 +111,8 @@ public class RecordTypes {
     public static final Type ExHyperlinkAtom = new Type(4051,ExHyperlinkAtom.class);
     public static final Type ExHyperlink = new Type(4055,ExHyperlink.class);
     public static final Type SlideNumberMCAtom = new Type(4056,null);
-    public static final Type HeadersFooters = new Type(4057,null);
-    public static final Type HeadersFootersAtom = new Type(4058,null);
+    public static final Type HeadersFooters = new Type(4057,HeadersFootersContainer.class);
+    public static final Type HeadersFootersAtom = new Type(4058,HeadersFootersAtom.class);
     public static final Type TxInteractiveInfoAtom = new Type(4063,TxInteractiveInfoAtom.class);
     public static final Type CharFormatAtom = new Type(4066,null);
     public static final Type ParaFormatAtom = new Type(4067,null);
index 56e94431ec1cbbb30aca50d0c23d62134e463333..f38cc7716d05f40a2cd83ee72a7fa0c67f903d24 100644 (file)
@@ -811,4 +811,50 @@ public class SlideShow
     public int 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);
+    }
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers.ppt
new file mode 100644 (file)
index 0000000..891d73f
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers.ppt differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java
new file mode 100644 (file)
index 0000000..8b1cdbe
--- /dev/null
@@ -0,0 +1,118 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+        \r
+\r
+\r
+package org.apache.poi.hslf.model;\r
+\r
+import java.io.*;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+\r
+import junit.framework.TestCase;\r
+\r
+/**\r
+ * Test {@link org.apache.poi.hslf.model.HeadersFooters} object\r
+ */\r
+public class TestHeadersFooters extends TestCase\r
+{\r
+\r
+    public static final String cwd = System.getProperty("HSLF.testdata.path");\r
+\r
+    public void testRead() throws Exception\r
+    {\r
+        File file = new File(cwd, "headers_footers.ppt");\r
+        FileInputStream is = new FileInputStream(file);\r
+        SlideShow ppt = new SlideShow(is);\r
+        is.close();\r
+\r
+        HeadersFooters slideHdd = ppt.getSlideHeadersFooters();\r
+        assertTrue(slideHdd.isFooterVisible());\r
+        assertEquals("Global Slide Footer", slideHdd.getFooterText());\r
+        assertTrue(slideHdd.isSlideNumberVisible());\r
+        assertFalse(slideHdd.isHeaderVisible());\r
+        assertNull(slideHdd.getHeaderText());\r
+        assertFalse(slideHdd.isUserDateVisible());\r
+        assertNull(slideHdd.getDateTimeText());\r
+\r
+\r
+        HeadersFooters notesHdd = ppt.getNotesHeadersFooters();\r
+        assertTrue(notesHdd.isFooterVisible());\r
+        assertEquals("Notes Footer", notesHdd.getFooterText());\r
+        assertTrue(notesHdd.isHeaderVisible());\r
+        assertEquals("Notes Header", notesHdd.getHeaderText());\r
+        assertTrue(notesHdd.isUserDateVisible());\r
+        assertNull(notesHdd.getDateTimeText());\r
+\r
+        Slide[] slide = ppt.getSlides();\r
+        //the first slide uses presentation-scope headers / footers\r
+        HeadersFooters hd1 = slide[0].getHeadersFooters();\r
+        assertEquals(slideHdd.isFooterVisible(), hd1.isFooterVisible());\r
+        assertEquals(slideHdd.getFooterText(), hd1.getFooterText());\r
+        assertEquals(slideHdd.isSlideNumberVisible(), hd1.isSlideNumberVisible());\r
+        assertEquals(slideHdd.isHeaderVisible(), hd1.isHeaderVisible());\r
+        assertEquals(slideHdd.getHeaderText(), hd1.getHeaderText());\r
+        assertEquals(slideHdd.isUserDateVisible(), hd1.isUserDateVisible());\r
+        assertEquals(slideHdd.getDateTimeText(), hd1.getDateTimeText());\r
+\r
+        //the first slide uses per-slide headers / footers\r
+        HeadersFooters hd2 = slide[1].getHeadersFooters();\r
+        assertEquals(true, hd2.isFooterVisible());\r
+        assertEquals("per-slide footer", hd2.getFooterText());\r
+        assertEquals(true, hd2.isUserDateVisible());\r
+        assertEquals("custom date format", hd2.getDateTimeText());\r
+    }\r
+\r
+    public void testCreateSlideFooters() throws Exception\r
+    {\r
+        SlideShow ppt = new SlideShow();\r
+        HeadersFooters hdd = ppt.getSlideHeadersFooters();\r
+        hdd.setFootersText("My slide footer");\r
+        hdd.setSlideNumberVisible(true);\r
+\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        ppt.write(out);\r
+        byte[] b = out.toByteArray();\r
+\r
+        SlideShow ppt2 = new SlideShow(new ByteArrayInputStream(b));\r
+        HeadersFooters hdd2 = ppt2.getSlideHeadersFooters();\r
+        assertTrue(hdd2.isSlideNumberVisible());\r
+        assertTrue(hdd2.isFooterVisible());\r
+        assertEquals("My slide footer", hdd2.getFooterText());\r
+    }\r
+\r
+    public void testCreateNotesFooters() throws Exception\r
+    {\r
+        SlideShow ppt = new SlideShow();\r
+        HeadersFooters hdd = ppt.getNotesHeadersFooters();\r
+        hdd.setFootersText("My notes footer");\r
+        hdd.setHeaderText("My notes header");\r
+        hdd.setSlideNumberVisible(true);\r
+\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        ppt.write(out);\r
+        byte[] b = out.toByteArray();\r
+\r
+        SlideShow ppt2 = new SlideShow(new ByteArrayInputStream(b));\r
+        HeadersFooters hdd2 = ppt2.getNotesHeadersFooters();\r
+        assertTrue(hdd2.isSlideNumberVisible());\r
+        assertTrue(hdd2.isFooterVisible());\r
+        assertEquals("My notes footer", hdd2.getFooterText());\r
+        assertTrue(hdd2.isHeaderVisible());\r
+        assertEquals("My notes header", hdd2.getHeaderText());\r
+    }\r
+}
\ No newline at end of file
index 3f3d1a1447e900060e61e10778f7a452607f1e3d..df8e1a3dae8e092915d49c493f79837d7cfa36b4 100644 (file)
@@ -46,12 +46,12 @@ public class TestCString extends TestCase {
        }
        public void testCount() throws Exception {
                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);
-               assertEquals(0x10, cb.getCount());
+               assertEquals(0x10, cb.getOptions());
                
-               ca.setCount(28);
-               assertEquals(28, ca.getCount());
+               ca.setOptions(28);
+               assertEquals(28, ca.getOptions());
        }
        
        public void testText() throws Exception {
@@ -90,7 +90,7 @@ public class TestCString extends TestCase {
        public void testChange() throws Exception {
                CString ca = new CString(data_a, 0, data_a.length);
                ca.setText("Comments");
-               ca.setCount(0x10);
+               ca.setOptions(0x10);
                
                try {
                        for(int i=0; i<data_a.length; i++) {
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestHeadersFootersAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestHeadersFootersAtom.java
new file mode 100644 (file)
index 0000000..8c6972c
--- /dev/null
@@ -0,0 +1,95 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+        \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests that {@link HeadersFootersAtom} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestHeadersFootersAtom extends TestCase {\r
+       // From a real file\r
+       private byte[] data = new byte[] {\r
+            0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 00,\r
+            0x00, 0x00, 0x23, 0x00 };\r
+\r
+    public void testRead() throws Exception {\r
+               HeadersFootersAtom record = new HeadersFootersAtom(data, 0, data.length);\r
+               assertEquals(RecordTypes.HeadersFootersAtom.typeID, record.getRecordType());\r
+\r
+        assertEquals(0, record.getFormatId());\r
+        assertEquals(0x23, record.getMask());\r
+\r
+        assertTrue(record.getFlag(HeadersFootersAtom.fHasDate));\r
+        assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));\r
+        assertFalse(record.getFlag(HeadersFootersAtom.fHasUserDate));\r
+        assertFalse(record.getFlag(HeadersFootersAtom.fHasSlideNumber));\r
+        assertFalse(record.getFlag(HeadersFootersAtom.fHasHeader));\r
+        assertTrue(record.getFlag(HeadersFootersAtom.fHasFooter));\r
+    }\r
+\r
+       public void testWrite() throws Exception {\r
+               HeadersFootersAtom record = new HeadersFootersAtom(data, 0, data.length);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               record.writeOut(baos);\r
+               byte[] b = baos.toByteArray();\r
+\r
+               assertTrue(Arrays.equals(data, b));\r
+       }\r
+\r
+    public void testNewRecord() throws Exception {\r
+        HeadersFootersAtom record = new HeadersFootersAtom();\r
+        record.setFlag(HeadersFootersAtom.fHasDate, true);\r
+        record.setFlag(HeadersFootersAtom.fHasTodayDate, true);\r
+        record.setFlag(HeadersFootersAtom.fHasFooter, true);\r
+\r
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+        record.writeOut(baos);\r
+        byte[] b = baos.toByteArray();\r
+\r
+        assertTrue(Arrays.equals(data, b));\r
+    }\r
+\r
+    public void testFlags() throws Exception {\r
+        HeadersFootersAtom record = new HeadersFootersAtom();\r
+\r
+        //in a new record all the bits are 0\r
+        for(int i = 0; i < 6; i++) assertFalse(record.getFlag(1 << i));\r
+\r
+        record.setFlag(HeadersFootersAtom.fHasTodayDate, true);\r
+        assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));\r
+\r
+        record.setFlag(HeadersFootersAtom.fHasTodayDate, true);\r
+        assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));\r
+\r
+        record.setFlag(HeadersFootersAtom.fHasTodayDate, false);\r
+        assertFalse(record.getFlag(HeadersFootersAtom.fHasTodayDate));\r
+\r
+        record.setFlag(HeadersFootersAtom.fHasTodayDate, false);\r
+        assertFalse(record.getFlag(HeadersFootersAtom.fHasTodayDate));\r
+\r
+    }\r
+}
\ No newline at end of file
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestHeadersFootersContainer.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestHeadersFootersContainer.java
new file mode 100644 (file)
index 0000000..d24ca05
--- /dev/null
@@ -0,0 +1,171 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+        \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests that {@link HeadersFootersContainer} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestHeadersFootersContainer extends TestCase {\r
+       // SlideHeadersFootersContainer\r
+       private byte[] slideData = new byte[] {\r
+            0x3F, 0x00, (byte)0xD9, 0x0F, 0x2E, 0x00, 0x00, 0x00,\r
+            0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00,\r
+            0x20, 0x00, (byte)0xBA, 0x0F, 0x1A, 0x00, 0x00, 0x00,\r
+            0x4D, 0x00, 0x79, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74,\r
+            0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x2D, 0x00, 0x20, 0x00, 0x31, 0x00\r
+\r
+    };\r
+\r
+    // NotesHeadersFootersContainer\r
+    private byte[] notesData = new byte[] {\r
+            0x4F, 0x00, (byte)0xD9, 0x0F, 0x48, 0x00, 0x00, 0x00,\r
+            0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x00,\r
+            0x10, 0x00, (byte)0xBA, 0x0F, 0x16, 0x00, 0x00, 0x00,\r
+            0x4E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x48, 0x00,\r
+            0x65, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00,\r
+            0x20, 0x00, (byte)0xBA, 0x0F, 0x16, 0x00, 0x00, 0x00,\r
+            0x4E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00,\r
+            0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00\r
+    };\r
+\r
+    public void testReadSlideHeadersFootersContainer() throws Exception {\r
+               HeadersFootersContainer record = new HeadersFootersContainer(slideData, 0, slideData.length);\r
+               assertEquals(RecordTypes.HeadersFooters.typeID, record.getRecordType());\r
+        assertEquals(HeadersFootersContainer.SlideHeadersFootersContainer, record.getOptions());\r
+        assertEquals(2, record.getChildRecords().length);\r
+\r
+        HeadersFootersAtom hdd = record.getHeadersFootersAtom();\r
+        assertNotNull(hdd);\r
+\r
+        CString csFooter = record.getFooterAtom();\r
+        assertNotNull(csFooter);\r
+        assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);\r
+\r
+        assertEquals("My Footer - 1", csFooter.getText());\r
+\r
+        assertNull(record.getUserDateAtom());\r
+        assertNull(record.getHeaderAtom());\r
+    }\r
+\r
+       public void testWriteSlideHeadersFootersContainer() throws Exception {\r
+               HeadersFootersContainer record = new HeadersFootersContainer(slideData, 0, slideData.length);\r
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               record.writeOut(baos);\r
+               byte[] b = baos.toByteArray();\r
+\r
+               assertTrue(Arrays.equals(slideData, b));\r
+       }\r
+\r
+    public void testNewSlideHeadersFootersContainer() throws Exception {\r
+        HeadersFootersContainer record = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);\r
+\r
+        assertNotNull(record.getHeadersFootersAtom());\r
+        assertNull(record.getUserDateAtom());\r
+        assertNull(record.getHeaderAtom());\r
+        assertNull(record.getFooterAtom());\r
+\r
+        HeadersFootersAtom hd = record.getHeadersFootersAtom();\r
+        hd.setFlag(HeadersFootersAtom.fHasDate, true);\r
+        hd.setFlag(HeadersFootersAtom.fHasTodayDate, true);\r
+        hd.setFlag(HeadersFootersAtom.fHasFooter, true);\r
+\r
+        CString csFooter = record.addFooterAtom();\r
+        assertNotNull(csFooter);\r
+        assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);\r
+        csFooter.setText("My Footer - 1");\r
+\r
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+        record.writeOut(baos);\r
+        byte[] b = baos.toByteArray();\r
+\r
+        assertTrue(Arrays.equals(slideData, b));\r
+    }\r
+\r
+    public void testReadNotesHeadersFootersContainer() throws Exception {\r
+               HeadersFootersContainer record = new HeadersFootersContainer(notesData, 0, notesData.length);\r
+               assertEquals(RecordTypes.HeadersFooters.typeID, record.getRecordType());\r
+        assertEquals(HeadersFootersContainer.NotesHeadersFootersContainer, record.getOptions());\r
+        assertEquals(3, record.getChildRecords().length);\r
+\r
+        HeadersFootersAtom hdd = record.getHeadersFootersAtom();\r
+        assertNotNull(hdd);\r
+\r
+        CString csHeader = record.getHeaderAtom();\r
+        assertNotNull(csHeader);\r
+        assertEquals(HeadersFootersContainer.HEADERATOM, csHeader.getOptions() >> 4);\r
+        assertEquals("Note Header", csHeader.getText());\r
+\r
+        CString csFooter = record.getFooterAtom();\r
+        assertNotNull(csFooter);\r
+        assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);\r
+        assertEquals("Note Footer", csFooter.getText());\r
+    }\r
+\r
+       public void testWriteNotesHeadersFootersContainer() throws Exception {\r
+               HeadersFootersContainer record = new HeadersFootersContainer(notesData, 0, notesData.length);\r
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+               record.writeOut(baos);\r
+               byte[] b = baos.toByteArray();\r
+\r
+               assertTrue(Arrays.equals(notesData, b));\r
+       }\r
+\r
+    public void testNewNotesHeadersFootersContainer() throws Exception {\r
+        HeadersFootersContainer record = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer);\r
+\r
+        assertNotNull(record.getHeadersFootersAtom());\r
+        assertNull(record.getUserDateAtom());\r
+        assertNull(record.getHeaderAtom());\r
+        assertNull(record.getFooterAtom());\r
+\r
+        HeadersFootersAtom hd = record.getHeadersFootersAtom();\r
+        hd.setFlag(HeadersFootersAtom.fHasDate, true);\r
+        hd.setFlag(HeadersFootersAtom.fHasTodayDate, false);\r
+        hd.setFlag(HeadersFootersAtom.fHasUserDate, true);\r
+        hd.setFlag(HeadersFootersAtom.fHasSlideNumber, true);\r
+        hd.setFlag(HeadersFootersAtom.fHasHeader, true);\r
+        hd.setFlag(HeadersFootersAtom.fHasFooter, true);\r
+\r
+        CString csHeader = record.addHeaderAtom();\r
+        assertNotNull(csHeader);\r
+        assertEquals(HeadersFootersContainer.HEADERATOM, csHeader.getOptions() >> 4);\r
+        csHeader.setText("Note Header");\r
+\r
+        CString csFooter = record.addFooterAtom();\r
+        assertNotNull(csFooter);\r
+        assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);\r
+        csFooter.setText("Note Footer");\r
+\r
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+        record.writeOut(baos);\r
+        byte[] b = baos.toByteArray();\r
+\r
+        assertTrue(Arrays.equals(notesData, b));\r
+    }\r
+\r
+}
\ No newline at end of file