1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.xml.sxc;
25 
26 import org.w3c.dom.NodeList;
27 import org.w3c.dom.Node;
28 import org.w3c.dom.NamedNodeMap;
29 import org.w3c.dom.Element;
30 
31 import org.openoffice.xmerge.converter.xml.Style;
32 import org.openoffice.xmerge.converter.xml.StyleCatalog;
33 import org.openoffice.xmerge.util.Debug;
34 import org.openoffice.xmerge.util.TwipsConverter;
35 
36 /**
37  *  Represents a text <code>Style</code> in an OpenOffice document.
38  *
39  *  @author	Martin Maher
40  */
41 public class ColumnStyle extends Style implements Cloneable {
42 
43 	private	int colWidth = 0;
44     /**
45      *  Constructor for use when going from DOM to client device format.
46      *
47      *  @param  node  The <i>style:style</i> <code>Node</code> containing
48      *                the <code>Style</code>.  (This <code>Node</code> is
49      *                assumed have a <i>family</i> attribute of <i>text</i>).
50      *  @param  sc    The <code>StyleCatalog</code>, which is used for
51      *                looking up ancestor <code>Style</code> objects.
52      */
ColumnStyle(Node node, StyleCatalog sc)53     public ColumnStyle(Node node, StyleCatalog sc) {
54         super(node, sc);
55 
56         // Run through the attributes of this node, saving
57         // the ones we're interested in.
58         NamedNodeMap attrNodes = node.getAttributes();
59         if (attrNodes != null) {
60             int len = attrNodes.getLength();
61             for (int i = 0; i < len; i++) {
62                 Node attr = attrNodes.item(i);
63                 handleAttribute(attr.getNodeName(), attr.getNodeValue());
64             }
65         }
66 
67         // Look for children.  Only ones we care about are "style:properties"
68         // nodes.  If any are found, recursively traverse them, passing
69         // along the style element to add properties to.
70         if (node.hasChildNodes()) {
71             NodeList children = node.getChildNodes();
72             int len = children.getLength();
73             for (int i = 0; i < len; i++) {
74                 Node child = children.item(i);
75                 String name = child.getNodeName();
76                 if (name.equals("style:properties")) {
77                     NamedNodeMap childAttrNodes = child.getAttributes();
78                     if (childAttrNodes != null) {
79                         int nChildAttrNodes = childAttrNodes.getLength();
80                         for (int j = 0; j < nChildAttrNodes; j++) {
81                             Node attr = childAttrNodes.item(j);
82                             handleAttribute(attr.getNodeName(),
83                             attr.getNodeValue());
84                         }
85                     }
86                 }
87             }
88         }
89     }
90 
91 
92     /**
93      *  Constructor for use when going from client device format to DOM
94      *
95      *  @param  name     Name of text <code>Style</code>.  Can be null.
96      *  @param  family   Family of text <code>Style</code> (usually
97      *                   <i>text</i>).  Can be null.
98      *  @param  parent   Name of parent text <code>Style</code>, or null
99      *                   for none.
100      *  @param  colWidth the width of this column
101      *  @param sc        The <code>StyleCatalog</code>, which is used for
102      *                   looking up ancestor <code>Style</code> objects.
103      */
ColumnStyle(String name, String family, String parent,int colWidth, StyleCatalog sc)104     public ColumnStyle(String name, String family, String parent,int colWidth, StyleCatalog sc) {
105         super(name, family, parent, sc);
106 		this.colWidth = colWidth;
107 	}
108 
109 	/**
110 	 * Returns the width of this column
111 	 *
112 	 * @return the <code>Format</code> object
113 	 */
getColWidth()114 	public int getColWidth() {
115 		return colWidth;
116 	}
117 
118 	/**
119 	 * Sets the width of this column
120 	 *
121 	 * @param colWidth the column width
122 	 */
setColWidth(int colWidth)123 	public void setColWidth(int colWidth) {
124 
125 		this.colWidth = colWidth;
126 	}
127 
128     /**
129      *  Parse a colwidth in the form "1.234cm" to twips
130      *
131      *  @param  value  <code>String</code> specification to parse.
132      *
133      *  @return  The twips equivalent.
134      */
parseColWidth(String value)135     private int parseColWidth(String value) {
136 
137 		int width = 255;	// Default value
138 
139 		if(value.indexOf("cm")!=-1) {
140 			float widthCM = Float.parseFloat(value.substring(0,value.indexOf("c")));
141 			width = TwipsConverter.cm2twips(widthCM);
142 		} else if(value.indexOf("inch")!=-1) {
143 			float widthInch = Float.parseFloat(value.substring(0,value.indexOf("i")));
144 			width = TwipsConverter.inches2twips(widthInch);
145 		}
146 
147 		return (width);
148     }
149 
150 
151     /**
152      *  Set an attribute.
153      *
154      *  @param  attr   The attribute to set.
155      *  @param  value  The attribute value to set.
156      */
handleAttribute(String attr, String value)157     private void handleAttribute(String attr, String value) {
158 
159         if (attr.equals("style:column-width")) {
160 			colWidth = parseColWidth(value);
161         }
162         else {
163             Debug.log(Debug.INFO, "ColumnStyle Unhandled: " + attr + "=" + value);
164         }
165     }
166 
167 
168     /**
169      *  Return a <code>Style</code> object corresponding to this one,
170      *  but with all of the inherited information from parent
171      *  <code>Style</code> objects filled in.  The object returned will
172      *  be a new object, not a reference to this object, even if it does
173      *  not need any information added.
174      *
175      *  @return  The <code>StyleCatalog</code> in which to look up
176      *           ancestors.
177      */
getResolved()178     public Style getResolved() {
179         // Create a new object to return, which is a clone of this one.
180         ColumnStyle resolved = null;
181         try {
182             resolved = (ColumnStyle)this.clone();
183         } catch (Exception e) {
184             Debug.log(Debug.ERROR, "Can't clone", e);
185         }
186 
187         // Look up the parentStyle.  (If there is no style catalog
188         // specified, we can't do any lookups.)
189         ColumnStyle parentStyle = null;
190         if (sc != null) {
191             if (parent != null) {
192                 parentStyle = (ColumnStyle)sc.lookup(parent, family, null,
193                            this.getClass());
194                 if (parentStyle == null)
195                     Debug.log(Debug.ERROR, "parent style lookup of "
196                       + parent + " failed!");
197                 else
198                     parentStyle = (ColumnStyle)parentStyle.getResolved();
199 
200             } else if (!name.equals("DEFAULT_STYLE")) {
201                 parentStyle = (ColumnStyle)sc.lookup("DEFAULT_STYLE", null,
202                     null, this.getClass());
203             }
204         }
205 
206         // If we found a parent, for any attributes which we don't have
207         // set, try to get the values from the parent.
208         if (parentStyle != null) {
209             parentStyle = (ColumnStyle)parentStyle.getResolved();
210 
211             if ((colWidth == 0) && (parentStyle.getColWidth() != 0))
212                 resolved.setColWidth(parentStyle.getColWidth());
213         }
214         return resolved;
215     }
216 
217 
218     /**
219      *  Create a new <code>Node</code> in the <code>Document</code>, and
220      *  write this <code>Style</code> to it.
221      *
222      *  @param  parentDoc  Parent <code>Document</code> of the
223      *                    <code>Node</code> to create.
224      *  @param  name       Name to use for the new <code>Node</code> (e.g.
225      *                    <i>style:style</i>)
226      *
227      *  @return  Created <code>Node</code>.
228      */
createNode(org.w3c.dom.Document parentDoc, String name)229     public Node createNode(org.w3c.dom.Document parentDoc, String name) {
230         Element node = parentDoc.createElement(name);
231         writeAttributes(node);
232         return node;
233     }
234 
235 
236     /**
237      *  Return true if <code>style</code> specifies as much or less
238      *  than this <code>Style</code>, and nothing it specifies
239      *  contradicts this <code>Style</code>.
240      *
241      *  @param  style  The <code>Style</code> to check.
242      *
243 	 *  @return  true if <code>style</code> is a subset, false
244      *           otherwise.
245      */
isSubset(Style style)246     public boolean isSubset(Style style) {
247         if (style.getClass() != this.getClass())
248                 return false;
249         ColumnStyle tStyle = (ColumnStyle)style;
250 
251 		if(colWidth!=tStyle.getColWidth())
252 			return false;
253 
254         return true;
255     }
256 
257 
258     /**
259      *  Write this <code>Style</code> object's attributes to a
260      *  <code>Node</code> in the <code>Document</code>.
261      *
262      *  @param  node  The <code>Node</code> to add <code>Style</code>
263      *                attributes.
264      */
writeAttributes(Element node)265     public void writeAttributes(Element node) {
266 
267 		if(colWidth!=0) {
268 			String width = TwipsConverter.twips2cm(colWidth) + "cm";
269 			node.setAttribute("style:column-width", width);
270 		}
271     }
272 
273 
274     private static String[] ignored = {
275         "fo:break-before", "fo:keep-with-next"
276     };
277 
278 
279     /*
280      * This code checks whether an attribute is one that we
281      * intentionally ignore.
282      *
283      *  @param  attribute  The attribute to check.
284      *
285      *  @return  true if <code>attribute</code> can be ignored,
286      *           otherwise false.
287      */
isIgnored(String attribute)288     private boolean isIgnored(String attribute) {
289         for (int i = 0; i < ignored.length; i++) {
290             if (ignored[i].equals(attribute))
291                 return true;
292         }
293         return false;
294     }
295 }
296 
297