001package com.hfg.xml.msofficexml.docx.wordprocessingml;
002
003
004import com.hfg.graphics.PaperSize;
005import com.hfg.graphics.units.GfxSize2D;
006import com.hfg.graphics.units.GfxUnits;
007import com.hfg.graphics.units.Pixels;
008import com.hfg.util.Orientation;
009import com.hfg.xml.XMLTag;
010import com.hfg.xml.msofficexml.docx.Docx;
011import com.hfg.xml.msofficexml.docx.DocxException;
012import com.hfg.xml.msofficexml.docx.RelationshipXML;
013
014
015//------------------------------------------------------------------------------
016/**
017 Represents an Office Open XML section properties (<w:sectPr>) tag.
018
019 @author J. Alex Taylor, hairyfatguy.com
020 */
021//------------------------------------------------------------------------------
022// com.hfg XML/HTML Coding Library
023//
024// This library is free software; you can redistribute it and/or
025// modify it under the terms of the GNU Lesser General Public
026// License as published by the Free Software Foundation; either
027// version 2.1 of the License, or (at your option) any later version.
028//
029// This library is distributed in the hope that it will be useful,
030// but WITHOUT ANY WARRANTY; without even the implied warranty of
031// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
032// Lesser General Public License for more details.
033//
034// You should have received a copy of the GNU Lesser General Public
035// License along with this library; if not, write to the Free Software
036// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
037//
038// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
039// jataylor@hairyfatguy.com
040//------------------------------------------------------------------------------
041// Section 17.6 (pg. 538) of Ecma Office Open XML Part 1
042/*
04317.6 Sections
044WordprocessingML does not natively store the concept of pages, since it is based on paragraphs and runs
045(which are laid out on to pages by consumers of this content). However, although there is no concept of
046storing pages in the WordprocessingML format, it is often necessary to store information about a page or
047group of pages in a document, in order to store information that is to be used to format the pages on which
048a set of paragraphs appear. In WordprocessingML, this information is stored via the use of sections.
049
050In WordprocessingML, sections are groupings of paragraphs that have a specific set of properties used to define
051the pages on which the text appears, as well as other section-level (applying to all paragraphs' appearance) properties.
052
053[Example: Consider a document with four paragraphs of text that is to be printed on a page in landscape mode,
054followed by ten paragraphs of text that are to be printed in portrait mode. This requirement implies information
055about the page(s) used to lay out each grouping of text - the first four paragraphs could require one page, or
056ten.
057
058Therefore, rather than try to cache knowledge of the number of pages and their properties (which is likely to become
059incorrect if the XML is manipulated by a producer that does not understand page layout), this information is stored
060by breaking the document into two sections, as follows:
061<pre>
062&lt;w:p> ...
063&lt;/w:p>
064&lt;w:p> ...
065&lt;/w:p>
066&lt;w:p> ...
067&lt;/w:p>
068&lt;w:p>
069   &lt;w:sectPr> ...
070   (section one properties go here) &lt;w:pgSz ... w:orient="landscape" /> ...
071   &lt;/w:sectPr>
072   ...
073&lt;/w:p>
074...
075&lt;w:p>
076   &lt;w:sectPr> ...
077   (section two properties go here) &lt;w:pgSz ... w:orient="portrait" /> ...
078   &lt;/w:sectPr>
079   ...
080&lt;/w:p>
081</pre>
082
083end example]
084<p>
085 For all sections except the final section, the sectPr element is stored as a child element of the last paragraph
086 in the section. For the final section, this information is stored as the last child element of the body element
087</p>
088*/
089public class WmlSectionProperties extends WmlXMLTag
090{
091   private WmlPageMargins mPageMargins;
092   private WmlPageSize    mPageSize;
093
094   //---------------------------------------------------------------------------
095   public WmlSectionProperties(Docx inDocx)
096   {
097      super(WmlXML.SECT_PROPS, inDocx);
098   }
099
100
101   //---------------------------------------------------------------------------
102   /**
103    * Sets the page dimensions based on the specified paper size and orientation.
104    */
105   public WmlSectionProperties setPageSize(PaperSize inSize, Orientation inOrientation)
106   {
107      setPageSize(inSize);
108      getPageSize().setOrientation(inOrientation);
109
110      return this;
111   }
112
113   //---------------------------------------------------------------------------
114   /**
115    * Sets the page dimensions based on the specified paper size.
116    */
117   public WmlSectionProperties setPageSize(PaperSize inValue)
118   {
119      if (inValue != null)
120      {
121         getPageSize().setWidth(inValue.getDimensions().getWidth()).setHeight(inValue.getDimensions().getHeight());
122      }
123      else
124      {
125         mPageSize = null;
126      }
127
128      return this;
129   }
130
131   //---------------------------------------------------------------------------
132   /**
133    * Returns the page size tag if one exists or else instantiates a new one.
134    * @return the page size tag for this section
135    */
136   public WmlPageSize getPageSize()
137   {
138      if (null == mPageSize)
139      {
140         // Check if it has been added via addSubtag()...
141         mPageSize = getOptionalSubtagByName(WmlXML.PAGE_SIZE);
142         if (null == mPageSize)
143         {
144            mPageSize = new WmlPageSize();
145            addSubtag(mPageSize);
146         }
147      }
148
149      return mPageSize;
150   }
151
152   //---------------------------------------------------------------------------
153   /**
154    * Returns the page margins if one exists or else instantiates a new one.
155    * @return the page margins for this section
156    */
157   public WmlPageMargins getPageMargins()
158   {
159      if (null == mPageMargins)
160      {
161         // Check if it has been added via addSubtag()...
162         mPageMargins = getOptionalSubtagByName(WmlXML.PAGE_MARGINS);
163         if (null == mPageMargins)
164         {
165            mPageMargins = new WmlPageMargins();
166            addSubtag(mPageMargins);
167         }
168      }
169
170      return mPageMargins;
171   }
172
173   //---------------------------------------------------------------------------
174   public GfxSize2D getContentDimensions()
175   {
176      // Start with the page dimensions
177      GfxSize2D dimensions = getPageSize().getDimensions();
178
179      float widthPx = dimensions.getWidth().to(GfxUnits.pixels);
180      float heightPx = dimensions.getHeight().to(GfxUnits.pixels);
181
182      // Now adjust for margins and gutter
183
184      WmlPageMargins pageMargins = getPageMargins();
185      if (pageMargins.getLeft() != null)
186      {
187         widthPx -= pageMargins.getLeft().to(GfxUnits.pixels);
188      }
189
190      if (pageMargins.getRight() != null)
191      {
192         widthPx -= pageMargins.getRight().to(GfxUnits.pixels);
193      }
194
195      if (pageMargins.getGutter() != null)
196      {
197         widthPx -= pageMargins.getGutter().to(GfxUnits.pixels);
198      }
199
200      if (pageMargins.getTop() != null)
201      {
202         heightPx -= pageMargins.getTop().to(GfxUnits.pixels);
203      }
204
205      if (pageMargins.getBottom() != null)
206      {
207         heightPx -= pageMargins.getBottom().to(GfxUnits.pixels);
208      }
209
210      return new GfxSize2D().setWidth(new Pixels(widthPx)).setHeight(new Pixels(heightPx));
211   }
212
213
214   //---------------------------------------------------------------------------
215   // The header itself is placed in its own file and a reference is retained.
216   public void addHeader(WmlHeader inValue, WmlHeaderFooterType inType)
217   {
218      Docx docx = getParentDoc();
219      if (null == docx)
220      {
221         throw new DocxException("No reference to the parent doc available!?");
222      }
223
224      String headerId = docx.addHeader(inValue);
225
226      XMLTag headerRefTag = new XMLTag(WmlXML.HEADER_REFERENCE);
227      headerRefTag.setAttribute(RelationshipXML.ID_ATT, headerId);
228      headerRefTag.setAttribute(WmlXML.TYPE_ATT, inType);
229
230      addSubtag(headerRefTag);
231   }
232
233
234   //---------------------------------------------------------------------------
235   // The footer itself is placed in its own file and a reference is retained.
236   public void addFooter(WmlFooter inValue, WmlHeaderFooterType inType)
237   {
238      Docx docx = getParentDoc();
239      if (null == docx)
240      {
241         throw new DocxException("No reference to the parent doc available!?");
242      }
243
244      String footerId = docx.addFooter(inValue);
245
246      XMLTag footerRefTag = new XMLTag(WmlXML.FOOTER_REFERENCE);
247      footerRefTag.setAttribute(RelationshipXML.ID_ATT, footerId);
248      footerRefTag.setAttribute(WmlXML.TYPE_ATT, inType);
249
250      addSubtag(footerRefTag);
251   }
252
253}