LibreOffice Module xmerge (master)  1
TextStyle.java
Go to the documentation of this file.
1 /*
2  * This file is part of the LibreOffice project.
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * This file incorporates work covered by the following license notice:
9  *
10  * Licensed to the Apache Software Foundation (ASF) under one or more
11  * contributor license agreements. See the NOTICE file distributed
12  * with this work for additional information regarding copyright
13  * ownership. The ASF licenses this file to you under the Apache
14  * License, Version 2.0 (the "License"); you may not use this file
15  * except in compliance with the License. You may obtain a copy of
16  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
17  */
18 
19 // DJP ToDo: need way of specifying fg/bg colors on ws->DOM
20 
21 package org.openoffice.xmerge.converter.xml;
22 
23 import java.awt.Color;
24 
25 import org.w3c.dom.NodeList;
26 import org.w3c.dom.Node;
27 import org.w3c.dom.NamedNodeMap;
28 import org.w3c.dom.Element;
29 
31 
35 public class TextStyle extends Style implements Cloneable {
36 
38  final private static int BOLD = 0x01;
40  final private static int ITALIC = 0x02;
42  final private static int UNDERLINE = 0x04;
44  final private static int STRIKETHRU = 0x08;
46  final private static int SUPERSCRIPT = 0x10;
48  final private static int SUBSCRIPT = 0x20;
49 
51  private int values = 0;
53  private int mask = 0;
54 
56  private int sizeInPoints = 0;
58  private String fontName = null;
60  private Color fontColor = null;
62  private Color bgColor = null;
63 
73  public TextStyle(Node node, StyleCatalog sc) {
74  super(node, sc);
75 
76  // Run through the attributes of this node, saving
77  // the ones we're interested in.
78  NamedNodeMap attrNodes = node.getAttributes();
79  if (attrNodes != null) {
80  int len = attrNodes.getLength();
81  for (int i = 0; i < len; i++) {
82  Node attr = attrNodes.item(i);
83  handleAttribute(attr.getNodeName(), attr.getNodeValue());
84  }
85  }
86 
87  // Look for children. Only ones we care about are "style:properties"
88  // nodes. If any are found, recursively traverse them, passing
89  // along the style element to add properties to.
90  if (!node.hasChildNodes()) {
91  return;
92  }
93  NodeList children = node.getChildNodes();
94  int len = children.getLength();
95  for (int i = 0; i < len; i++) {
96  Node child = children.item(i);
97  String nodeName = child.getNodeName();
98  if (nodeName.equals("style:properties")) {
99  NamedNodeMap childAttrNodes = child.getAttributes();
100  if (childAttrNodes != null) {
101  int nChildAttrNodes = childAttrNodes.getLength();
102  for (int j = 0; j < nChildAttrNodes; j++) {
103  Node attr = childAttrNodes.item(j);
104  handleAttribute(attr.getNodeName(),
105  attr.getNodeValue());
106  }
107  }
108  }
109  }
110  }
111 
138  public TextStyle(String name, String family, String parent,
139  int mask, int values, int fontSize, String fontName, StyleCatalog sc) {
140  super(name, family, parent, sc);
141  this.mask = mask;
142  this.values = values;
143  this.sizeInPoints = fontSize;
144  this.fontName = fontName;
145  }
146 
154  private Color parseColorString(String value) {
155  int red = 0;
156  int green = 0;
157  int blue = 0;
158  try {
159  // Assume color value is of form #rrggbb
160  red = Integer.parseInt(value.substring(1, 3), 16);
161  green = Integer.parseInt(value.substring(3, 5), 16);
162  blue = Integer.parseInt(value.substring(5, 7), 16);
163  } catch (NumberFormatException e) {
164  Debug.log(Debug.ERROR, "Problem parsing a color string", e);
165  } catch (IndexOutOfBoundsException e) {
166  Debug.log(Debug.ERROR, "Problem parsing a color string", e);
167  }
168  return new Color(red, green, blue);
169  }
170 
177  private void handleAttribute(String attr, String value) {
178 
179  if (attr.equals("fo:font-weight")) {
180  if (value.equals("bold")) turnAttributesOn(BOLD);
181  else if (value.equals("normal")) turnAttributesOff(BOLD);
182  }
183 
184  else if (attr.equals("fo:font-style")) {
185  if (value.equals("italic")) turnAttributesOn(ITALIC);
186  else if (value.equals("oblique")) turnAttributesOn(ITALIC);
187  else if (value.equals("normal")) turnAttributesOff(ITALIC);
188  }
189 
190  else if (attr.equals("style:text-underline")) {
191  if (value.equals("none"))
192  turnAttributesOff(UNDERLINE);
193  else
194  turnAttributesOn(UNDERLINE);
195  }
196 
197  else if (attr.equals("style:text-crossing-out")) {
198  if (value.equals("none"))
199  turnAttributesOff(STRIKETHRU);
200  else
201  turnAttributesOn(STRIKETHRU);
202  }
203 
204  else if (attr.equals("style:text-position")) {
205  if (value.startsWith("super "))
206  turnAttributesOn(SUPERSCRIPT);
207  else if (value.startsWith("sub "))
208  turnAttributesOn(SUBSCRIPT);
209  else if (value.startsWith("0% "))
210  turnAttributesOff(SUPERSCRIPT | SUBSCRIPT);
211  else {
212  String firstPart = value.substring(0, value.indexOf(' '));
213  if (firstPart.endsWith("%")) {
214  firstPart = firstPart.substring(0, value.indexOf('%'));
215  int amount;
216  try {
217  amount = Integer.parseInt(firstPart);
218  } catch (NumberFormatException e) {
219  amount = 0;
220  Debug.log(Debug.ERROR, "Problem with style:text-position tag", e);
221  }
222  if (amount < 0) turnAttributesOn(SUBSCRIPT);
223  else if (amount > 0) turnAttributesOn(SUPERSCRIPT);
224  }
225  }
226  }
227 
228  else if (attr.equals("fo:font-size")) {
229  if (value.endsWith("pt")) {
230  String num = value.substring(0, value.length() - 2);
231  sizeInPoints = Integer.parseInt(num);
232  }
233  }
234 
235  else if (attr.equals("style:font-name"))
236  fontName = value;
237 
238  else if (attr.equals("fo:color"))
239  fontColor = parseColorString(value);
240 
241  else if (attr.equals("style:text-background-color"))
242  bgColor = parseColorString(value);
243 
244  else if (isIgnored(attr)) {}
245 
246  else {
247  Debug.log(Debug.INFO, "TextStyle Unhandled: " + attr + "=" + value);
248  }
249  }
250 
256  public int getFontSize() {
257  return sizeInPoints;
258  }
259 
266  public String getFontName() {
267  return fontName;
268  }
269 
277  public Color getFontColor() {
278  return fontColor;
279  }
280 
290  return bgColor;
291  }
292 
302  @Override
303  public Style getResolved() {
304  // Create a new object to return, which is a clone of this one.
305  TextStyle resolved = null;
306  try {
307  resolved = (TextStyle)this.clone();
308  } catch (Exception e) {
309  Debug.log(Debug.ERROR, "Can't clone", e);
310  }
311 
312  // Look up the parentStyle. (If there is no style catalog
313  // specified, we can't do any lookups.)
314  TextStyle parentStyle = null;
315  if (sc != null) {
316  if (parent != null) {
317  parentStyle = (TextStyle)sc.lookup(parent, family, null,
318  this.getClass());
319  if (parentStyle == null)
320  Debug.log(Debug.ERROR, "parent style lookup of "
321  + parent + " failed!");
322  else
323  parentStyle = (TextStyle)parentStyle.getResolved();
324 
325  } else if (!name.equals("DEFAULT_STYLE")) {
326  parentStyle = (TextStyle)sc.lookup("DEFAULT_STYLE", null,
327  null, this.getClass());
328  }
329  }
330 
331  // If we found a parent, for any attributes which we don't have
332  // set, try to get the values from the parent.
333  if (parentStyle != null) {
334  parentStyle = (TextStyle)parentStyle.getResolved();
335 
336  if ((sizeInPoints == 0) && (parentStyle.sizeInPoints != 0))
337  resolved.sizeInPoints = parentStyle.sizeInPoints;
338  if ((fontName == null) && (parentStyle.fontName != null))
339  resolved.fontName = parentStyle.fontName;
340  if ((fontColor == null) && (parentStyle.fontColor != null))
341  resolved.fontColor = parentStyle.fontColor;
342  if ((bgColor == null) && (parentStyle.bgColor != null))
343  resolved.bgColor = parentStyle.bgColor;
344  for (int m = BOLD; m <= SUBSCRIPT; m = m << 1) {
345  if (((mask & m) == 0) && ((parentStyle.mask & m) != 0)) {
346  resolved.mask |= m;
347  resolved.values |= (parentStyle.mask & m);
348  }
349  }
350 
351  }
352  return resolved;
353  }
354 
360  private void turnAttributesOn(int flags) {
361  mask |= flags;
362  values |= flags;
363  }
364 
370  private void turnAttributesOff(int flags) {
371  mask |= flags;
372  values &= ~flags;
373  }
374 
383  private static String toCSV(String value) {
384  if (value != null)
385  return "\"" + value + "\",";
386  else
387  return "\"\",";
388  }
389 
398  private static String toLastCSV(String value) {
399  if (value != null)
400  return "\"" + value + "\"";
401  else
402  return "\"\"";
403  }
404 
408  public static void dumpHdr() {
409  System.out.println(toCSV("Name") + toCSV("Family") + toCSV("parent")
410  + toCSV("Font") + toCSV("Size")
411  + toCSV("Bold") + toCSV("Italic") + toCSV("Underline")
412  + toCSV("Strikethru") + toCSV("Superscript") + toLastCSV("Subscript"));
413  }
414 
418  public void dumpCSV() {
419  StringBuilder attributes = new StringBuilder();
420  for (int bitVal = 0x01; bitVal <= 0x20; bitVal = bitVal << 1) {
421  if ((bitVal & mask) != 0) {
422  attributes.append(toCSV(((bitVal & values) != 0) ? "yes" : "no"));
423  }
424  else {
425  attributes.append(toCSV(null)); // unspecified
426  }
427  }
428  System.out.println(toCSV(name) + toCSV(family) + toCSV(parent)
429  + toCSV(fontName) + toCSV("" + sizeInPoints) + attributes.toString() + toLastCSV(null));
430  }
431 
442  @Override
443  public Node createNode(org.w3c.dom.Document parentDoc, String name) {
444  Element node = parentDoc.createElement(name);
445  writeAttributes(node);
446  return node;
447  }
448 
458  @Override
459  public boolean isSubset(Style style) {
460  if (style.getClass() != this.getClass())
461  return false;
462  TextStyle tStyle = (TextStyle)style;
463 
464  if (tStyle.values != values)
465  return false;
466 
467  if (tStyle.sizeInPoints != 0 && sizeInPoints != tStyle.sizeInPoints)
468  return false;
469 
470  if (tStyle.fontName != null) {
471  if (fontName == null)
472  return false;
473  if (!fontName.equals(tStyle.fontName))
474  return false;
475  }
476 
477  if (tStyle.fontColor != null) {
478  if (fontColor == null)
479  return false;
480  if (!fontColor.equals(tStyle.fontColor))
481  return false;
482  }
483 
484  if (tStyle.bgColor != null) {
485  if (bgColor == null)
486  return false;
487  if (!bgColor.equals(tStyle.bgColor))
488  return false;
489  }
490 
491  return true;
492  }
493 
500  private void writeAttributes(Element node) {
501 
502  if ((mask & BOLD) != 0 && (values & BOLD) != 0)
503  node.setAttribute("fo:font-weight", "bold");
504 
505  if ((mask & ITALIC) != 0 && (values & ITALIC) != 0)
506  node.setAttribute("fo:font-style", "italic");
507 
508  if ((mask & UNDERLINE) != 0 && (values & UNDERLINE) != 0)
509  node.setAttribute("style:text-underline", "single");
510 
511  if ((mask & STRIKETHRU) != 0 && (values & STRIKETHRU) != 0)
512  node.setAttribute("style:text-crossing-out", "single-line");
513 
514  if ((mask & SUPERSCRIPT) != 0 && (values & SUPERSCRIPT) != 0)
515  node.setAttribute("style:text-position", "super 58%");
516 
517  if ((mask & SUBSCRIPT) != 0 && (values & SUBSCRIPT) != 0)
518  node.setAttribute("style:text-position", "sub 58%");
519 
520  if (sizeInPoints != 0) {
521  node.setAttribute("fo:font-size", Integer.toString(sizeInPoints) + "pt");
522  }
523 
524  if (fontName != null)
525  node.setAttribute("style:font-name", fontName);
526 
527  if (fontColor != null)
528  node.setAttribute("fo:color", buildColorString(fontColor));
529 
530  if (bgColor != null)
531  node.setAttribute("style:text-background-color",
532  buildColorString(bgColor));
533  }
534 
542  private String buildColorString(Color c) {
543  return String.format("#%06X", c.getRGB() & 0x00FFFFFF);
544  }
545 
546  private static String[] ignored = {
547  "style:text-autospace", "style:text-underline-color",
548  "fo:margin-left", "fo:margin-right", "fo:text-indent",
549  "fo:margin-top", "fo:margin-bottom", "text:line-number",
550  "text:number-lines", "style:country-asian",
551  "style:font-size-asian", "style:font-name-complex",
552  "style:language-complex", "style:country-complex",
553  "style:font-size-complex", "style:punctuation-wrap",
554  "fo:language", "fo:country",
555  "style:font-name-asian", "style:language-asian",
556  "style:line-break", "fo:keep-with-next"
557  };
558 
567  private boolean isIgnored(String attribute) {
568  for (String ignored1 : ignored) {
569  if (ignored1.equals(attribute)) {
570  return true;
571  }
572  }
573  return false;
574  }
575 }
static final int INFO
Informational messages.
Definition: Debug.java:42
Provides general purpose utilities.
boolean isSubset(Style style)
Return.
Definition: TextStyle.java:459
static void log(int flag, String msg)
Log message based on the flag type.
Definition: Debug.java:205
boolean isIgnored(String attribute)
This code checks whether an attribute is one that we intentionally ignore.
Definition: TextStyle.java:567
final static int ITALIC
Indicates italic text.
Definition: TextStyle.java:40
static String toCSV(String value)
Private function to return the value as an element in a Comma Separated Value (CSV) format...
Definition: TextStyle.java:383
void handleAttribute(String attr, String value)
Set an attribute.
Definition: TextStyle.java:177
final static int SUPERSCRIPT
Indicates superscripted text.
Definition: TextStyle.java:46
static void dumpHdr()
Print a Comma Separated Value (CSV) header line for the spreadsheet dump.
Definition: TextStyle.java:408
static final int ERROR
Error messages.
Definition: Debug.java:44
Color getBackgroundColor()
Return the background.
Definition: TextStyle.java:289
exports com.sun.star. java
int values
Values of text attributes.
Definition: TextStyle.java:51
final static int STRIKETHRU
Indicates strike-through in the text.
Definition: TextStyle.java:44
int i
final static int SUBSCRIPT
Indicates subscripted text.
Definition: TextStyle.java:48
void turnAttributesOn(int flags)
Set one or more text attributes to on.
Definition: TextStyle.java:360
PyRef getClass(const OUString &name, const Runtime &runtime)
TextStyle(String name, String family, String parent, int mask, int values, int fontSize, String fontName, StyleCatalog sc)
Constructor for use when going from client device format to DOM.
Definition: TextStyle.java:138
void writeAttributes(Element node)
Write this.
Definition: TextStyle.java:500
TextStyle(Node node, StyleCatalog sc)
Constructor for use when going from DOM to client device format.
Definition: TextStyle.java:73
String getFontName()
Return the name of the font for this.
Definition: TextStyle.java:266
int getFontSize()
Return the font size for this.
Definition: TextStyle.java:256
int mask
Bitwise mask of text attributes.
Definition: TextStyle.java:53
T * clone(T *const other)
final static int BOLD
Indicates bold text.
Definition: TextStyle.java:38
Provides interfaces for converting between two.
Definition: Convert.java:19
This class is used for logging debug messages.
Definition: Debug.java:39
tuple m
Node createNode(org.w3c.dom.Document parentDoc, String name)
Create a new.
Definition: TextStyle.java:443
Color parseColorString(String value)
Parse a color specification of the form #rrggbb
Definition: TextStyle.java:154
static String toLastCSV(String value)
Private function to return the value as a last element in a Comma Separated Value (CSV) format...
Definition: TextStyle.java:398
void turnAttributesOff(int flags)
Set one or more text attributes to off.
Definition: TextStyle.java:370
final static int UNDERLINE
Indicates underlined text.
Definition: TextStyle.java:42