Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

FObj.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.fo;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.Iterator;
  21. import java.util.ListIterator;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import org.apache.fop.apps.FOPException;
  25. import org.apache.fop.fo.flow.Marker;
  26. import org.apache.fop.fo.properties.Property;
  27. import org.apache.fop.fo.properties.PropertyMaker;
  28. import org.xml.sax.Attributes;
  29. import org.xml.sax.Locator;
  30. /**
  31. * Base class for representation of formatting objects and their processing.
  32. */
  33. public class FObj extends FONode implements Constants {
  34. private static final String FO_URI = "http://www.w3.org/1999/XSL/Format";
  35. public static PropertyMaker[] propertyListTable = null;
  36. /**
  37. * Formatting properties for this fo element.
  38. */
  39. public PropertyList propertyList;
  40. /**
  41. * Property manager for handling some common properties.
  42. */
  43. protected PropertyManager propMgr;
  44. /**
  45. * Id of this fo element of null if no id.
  46. */
  47. protected String id = null;
  48. /**
  49. * The children of this node.
  50. */
  51. public ArrayList children = null;
  52. /**
  53. * Markers added to this element.
  54. */
  55. protected Map markers = null;
  56. /**
  57. * Dynamic layout dimension. Used to resolve relative lengths.
  58. */
  59. protected Map layoutDimension = null;
  60. /**
  61. * Create a new formatting object.
  62. * All formatting object classes extend this class.
  63. *
  64. * @param parent the parent node
  65. */
  66. public FObj(FONode parent) {
  67. super(parent);
  68. if (propertyListTable == null) {
  69. propertyListTable = new PropertyMaker[Constants.PROPERTY_COUNT+1];
  70. PropertyMaker[] list = FOPropertyMapping.getGenericMappings();
  71. for (int i = 1; i < list.length; i++) {
  72. if (list[i] != null)
  73. propertyListTable[i] = list[i];
  74. }
  75. }
  76. }
  77. /** Marks input file containing this object **/
  78. public String systemId;
  79. /** Marks line number of this object in the input file **/
  80. public int line;
  81. /** Marks column number of this object in the input file **/
  82. public int column;
  83. /**
  84. * Set the name of this element.
  85. * The prepends "fo:" to the name to indicate it is in the fo namespace.
  86. *
  87. * @param str the xml element name
  88. */
  89. public void setName(String str) {
  90. name = "fo:" + str;
  91. }
  92. public void setLocation(Locator locator) {
  93. if (locator != null) {
  94. line = locator.getLineNumber();
  95. column = locator.getColumnNumber();
  96. systemId = locator.getSystemId();
  97. }
  98. }
  99. /**
  100. * Handle the attributes for this element.
  101. * The attributes must be used immediately as the sax attributes
  102. * will be altered for the next element.
  103. * @param attlist Collection of attributes passed to us from the parser.
  104. * @throws FOPException for invalid FO data
  105. */
  106. public void handleAttrs(Attributes attlist) throws FOPException {
  107. FObj parentFO = findNearestAncestorFObj();
  108. PropertyList parentPropertyList = null;
  109. if (parentFO != null) {
  110. parentPropertyList = parentFO.getPropertiesForNamespace(FO_URI);
  111. }
  112. propertyList = new PropertyList(this, parentPropertyList, FO_URI,
  113. name);
  114. propertyList.addAttributesToList(attlist);
  115. this.propMgr = makePropertyManager(propertyList);
  116. setWritingMode();
  117. }
  118. /**
  119. * Find the nearest parent, grandparent, etc. FONode that is also an FObj
  120. * @return FObj the nearest ancestor FONode that is an FObj
  121. */
  122. public FObj findNearestAncestorFObj() {
  123. FONode par = parent;
  124. while (par != null && !(par instanceof FObj)) {
  125. par = par.parent;
  126. }
  127. return (FObj) par;
  128. }
  129. /**
  130. * Find nearest ancestor which generates Reference Areas.
  131. *
  132. * @param includeSelf Set to true to consider the current FObj as an
  133. * "ancestor". Set to false to only return a true ancestor.
  134. * @param returnRoot Supposing a condition where no appropriate ancestor
  135. * FObj is found, setting returnRoot to true will return the FObj with no
  136. * parent (presumably the root FO). Otherwise, null will be returned.
  137. * Note that this will override a false setting for includeSelf, and return
  138. * the current node if it is the root FO. Setting returnRoot to true should
  139. * always return a valid FObj.
  140. * @return FObj of the nearest ancestor that generates Reference Areas
  141. * and fits the parameters.
  142. */
  143. private FObj findNearestAncestorGeneratingRAs(boolean includeSelf,
  144. boolean returnRoot) {
  145. FObj p = this;
  146. if (includeSelf && p.generatesReferenceAreas()) {
  147. return p;
  148. }
  149. FObj parent = p.findNearestAncestorFObj();
  150. if (parent == null && returnRoot) {
  151. return p;
  152. }
  153. do {
  154. p = parent;
  155. parent = p.findNearestAncestorFObj();
  156. } while (parent != null && !p.generatesReferenceAreas());
  157. if (p.generatesReferenceAreas()) {
  158. return p;
  159. }
  160. // if we got here, it is because parent is null
  161. if (returnRoot) {
  162. return p;
  163. } else {
  164. return null;
  165. }
  166. }
  167. /**
  168. * For a given namespace, determine whether the properties of this object
  169. * match that namespace.
  170. * @param nameSpaceURI the namespace URI to be tested against
  171. * @return this.propertyList, if the namespaces match; otherwise, null
  172. */
  173. public PropertyList getPropertiesForNamespace(String nameSpaceURI) {
  174. if (this.propertyList == null) {
  175. return null;
  176. }
  177. if (!nameSpaceURI.equals(this.propertyList.getNameSpace())) {
  178. return null;
  179. }
  180. return this.propertyList;
  181. }
  182. /**
  183. * @param propertyList the collection of Property objects to be managed
  184. * @return a PropertyManager for the Property objects
  185. */
  186. protected PropertyManager makePropertyManager(
  187. PropertyList propertyList) {
  188. return new PropertyManager(propertyList);
  189. }
  190. /* This section is the implemenation of the property context. */
  191. /**
  192. * Assign the size of a layout dimension to the key.
  193. * @param key the Layout dimension, from PercentBase.
  194. * @param dimension The layout length.
  195. */
  196. public void setLayoutDimension(Integer key, int dimension) {
  197. if (layoutDimension == null){
  198. layoutDimension = new HashMap();
  199. }
  200. layoutDimension.put(key, new Integer(dimension));
  201. }
  202. /**
  203. * Assign the size of a layout dimension to the key.
  204. * @param key the Layout dimension, from PercentBase.
  205. * @param dimension The layout length.
  206. */
  207. public void setLayoutDimension(Integer key, float dimension) {
  208. if (layoutDimension == null){
  209. layoutDimension = new HashMap();
  210. }
  211. layoutDimension.put(key, new Float(dimension));
  212. }
  213. /**
  214. * Return the size associated with the key.
  215. * @param key The layout dimension key.
  216. * @return the length.
  217. */
  218. public Number getLayoutDimension(Integer key) {
  219. if (layoutDimension != null) {
  220. Number result = (Number) layoutDimension.get(key);
  221. if (result != null) {
  222. return result;
  223. }
  224. }
  225. if (parent != null) {
  226. return ((FObj) parent).getLayoutDimension(key);
  227. }
  228. return new Integer(0);
  229. }
  230. /**
  231. * Add the child to this object.
  232. *
  233. * @param child the child node to add
  234. */
  235. protected void addChild(FONode child) {
  236. if (containsMarkers() && child.isMarker()) {
  237. addMarker((Marker)child);
  238. } else {
  239. if (children == null) {
  240. children = new ArrayList();
  241. }
  242. children.add(child);
  243. }
  244. }
  245. /**
  246. * lets outside sources access the property list
  247. * first used by PageNumberCitation to find the "id" property
  248. * @param name - the name of the desired property to obtain
  249. * @return the property
  250. */
  251. public Property getProperty(int propId) {
  252. return (propertyList.get(propId));
  253. }
  254. /**
  255. * Setup the id for this formatting object.
  256. * Most formatting objects can have an id that can be referenced.
  257. * This methods checks that the id isn't already used by another
  258. * fo and sets the id attribute of this object.
  259. */
  260. public void setupID() {
  261. Property prop = this.propertyList.get(PR_ID);
  262. if (prop != null) {
  263. String str = prop.getString();
  264. if (str != null && !str.equals("")) {
  265. Set idrefs = getFOTreeControl().getIDReferences();
  266. if (!idrefs.contains(str)) {
  267. id = str;
  268. idrefs.add(id);
  269. } else {
  270. getLogger().warn("duplicate id:" + str + " ignored");
  271. }
  272. }
  273. }
  274. }
  275. /**
  276. * Get the id string for this formatting object.
  277. * This will be unique for the fo document.
  278. *
  279. * @return the id string or null if not set
  280. */
  281. public String getID() {
  282. return id;
  283. }
  284. /**
  285. * Check if this formatting object generates reference areas.
  286. *
  287. * @return true if generates reference areas
  288. */
  289. public boolean generatesReferenceAreas() {
  290. return false;
  291. }
  292. /**
  293. * Check if this formatting object generates inline areas.
  294. *
  295. * @return true if generates inline areas
  296. */
  297. public boolean generatesInlineAreas() {
  298. return true;
  299. }
  300. /**
  301. * Check if this formatting object may contain markers.
  302. *
  303. * @return true if this can contian markers
  304. */
  305. protected boolean containsMarkers() {
  306. return false;
  307. }
  308. /**
  309. * Set writing mode for this FO.
  310. * Use that from the nearest ancestor, including self, which generates
  311. * reference areas, or from root FO if no ancestor found.
  312. */
  313. protected void setWritingMode() {
  314. FObj p = findNearestAncestorGeneratingRAs(true, true);
  315. this.propertyList.setWritingMode(
  316. p.getProperty(PR_WRITING_MODE).getEnum());
  317. }
  318. /**
  319. * Return an iterator over all the children of this FObj.
  320. * @return A ListIterator.
  321. */
  322. public ListIterator getChildren() {
  323. if (children != null) {
  324. return children.listIterator();
  325. }
  326. return null;
  327. }
  328. /**
  329. * Return an iterator over the object's children starting
  330. * at the pased node.
  331. * @param childNode First node in the iterator
  332. * @return A ListIterator or null if childNode isn't a child of
  333. * this FObj.
  334. */
  335. public ListIterator getChildren(FONode childNode) {
  336. if (children != null) {
  337. int i = children.indexOf(childNode);
  338. if (i >= 0) {
  339. return children.listIterator(i);
  340. }
  341. }
  342. return null;
  343. }
  344. /**
  345. * Add the marker to this formatting object.
  346. * If this object can contain markers it checks that the marker
  347. * has a unique class-name for this object and that it is
  348. * the first child.
  349. * @param marker Marker to add.
  350. */
  351. public void addMarker(Marker marker) {
  352. String mcname = marker.getMarkerClassName();
  353. if (children != null) {
  354. // check for empty children
  355. for (Iterator iter = children.iterator(); iter.hasNext();) {
  356. FONode node = (FONode)iter.next();
  357. if (node instanceof FOText) {
  358. FOText text = (FOText)node;
  359. if (text.willCreateArea()) {
  360. getLogger().error("fo:marker must be an initial child: " + mcname);
  361. return;
  362. } else {
  363. iter.remove();
  364. }
  365. } else {
  366. getLogger().error("fo:marker must be an initial child: " + mcname);
  367. return;
  368. }
  369. }
  370. }
  371. if (markers == null) {
  372. markers = new HashMap();
  373. }
  374. if (!markers.containsKey(mcname)) {
  375. markers.put(mcname, marker);
  376. } else {
  377. getLogger().error("fo:marker 'marker-class-name' "
  378. + "must be unique for same parent: " + mcname);
  379. }
  380. }
  381. /**
  382. * @return true if there are any Markers attached to this object
  383. */
  384. public boolean hasMarkers() {
  385. return markers != null && !markers.isEmpty();
  386. }
  387. /**
  388. * @return th collection of Markers attached to this object
  389. */
  390. public Map getMarkers() {
  391. return markers;
  392. }
  393. /**
  394. * lets layout managers access FO properties via PropertyManager
  395. * @return the property manager for this FO
  396. */
  397. public PropertyManager getPropertyManager() {
  398. return this.propMgr;
  399. }
  400. /**
  401. * This is a hook for an FOTreeVisitor subclass to be able to access
  402. * this object.
  403. * @param fotv the FOTreeVisitor subclass that can access this object.
  404. * @see org.apache.fop.fo.FOTreeVisitor
  405. */
  406. public void acceptVisitor(FOTreeVisitor fotv) {
  407. fotv.serveFObj(this);
  408. }
  409. /**
  410. * Return a string representation of the fo element.
  411. */
  412. public String toString() {
  413. return getName() + " at line " + line + ":" + column;
  414. }
  415. }