You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FObj.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * $Id$
  3. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  4. * For details on use and redistribution please refer to the
  5. * LICENSE file included with these sources.
  6. */
  7. package org.apache.fop.fo;
  8. // FOP
  9. import org.apache.fop.layout.AreaClass;
  10. import org.apache.fop.apps.FOPException;
  11. import org.apache.fop.apps.StructureHandler;
  12. import org.apache.fop.layoutmgr.LayoutManager;
  13. import org.apache.fop.fo.properties.FOPropertyMapping;
  14. import org.apache.fop.fo.flow.Marker;
  15. // Java
  16. import java.util.Iterator;
  17. import org.xml.sax.Attributes;
  18. import java.util.Iterator;
  19. import java.util.ListIterator;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import java.util.HashMap;
  23. import java.util.HashSet;
  24. /**
  25. * base class for representation of formatting objects and their processing
  26. */
  27. public class FObj extends FONode {
  28. protected StructureHandler structHandler;
  29. public PropertyList properties;
  30. protected PropertyManager propMgr;
  31. protected String areaClass = AreaClass.UNASSIGNED;
  32. protected String id = null;
  33. /**
  34. * value of marker before layout begins
  35. */
  36. public final static int START = -1000;
  37. /**
  38. * value of marker after break-after
  39. */
  40. public final static int BREAK_AFTER = -1001;
  41. /**
  42. * where the layout was up to.
  43. * for FObjs it is the child number
  44. * for FOText it is the character number
  45. */
  46. protected int marker = START;
  47. protected ArrayList children = new ArrayList(); // made public for searching for id's
  48. protected boolean isInTableCell = false;
  49. protected int forcedStartOffset = 0;
  50. protected int forcedWidth = 0;
  51. protected int widows = 0;
  52. protected int orphans = 0;
  53. // count of areas generated-by/returned-by
  54. public int areasGenerated = 0;
  55. // markers
  56. protected HashMap markers;
  57. public FObj(FONode parent) {
  58. super(parent);
  59. markers = new HashMap();
  60. if (parent instanceof FObj)
  61. this.areaClass = ((FObj) parent).areaClass;
  62. }
  63. public void setName(String str) {
  64. name = "fo:" + str;
  65. }
  66. protected static PropertyListBuilder plb = null;
  67. protected PropertyListBuilder getListBuilder() {
  68. if (plb == null) {
  69. plb = new PropertyListBuilder();
  70. plb.addList(FOPropertyMapping.getGenericMappings());
  71. for (Iterator iter =
  72. FOPropertyMapping.getElementMappings().iterator();
  73. iter.hasNext();) {
  74. String elem = (String) iter.next();
  75. plb.addElementList(elem,
  76. FOPropertyMapping.getElementMapping(elem));
  77. }
  78. }
  79. return plb;
  80. }
  81. /**
  82. * Handle the attributes for this element.
  83. * The attributes must be used immediately as the sax attributes
  84. * will be altered for the next element.
  85. */
  86. public void handleAttrs(Attributes attlist) throws FOPException {
  87. String uri = "http://www.w3.org/1999/XSL/Format";
  88. FONode par = parent;
  89. while (par != null && !(par instanceof FObj)) {
  90. par = par.parent;
  91. }
  92. PropertyList props = null;
  93. if (par != null) {
  94. props = ((FObj) par).properties;
  95. }
  96. properties = getListBuilder().makeList(uri, name, attlist, props,
  97. (FObj) par);
  98. properties.setFObj(this);
  99. this.propMgr = makePropertyManager(properties);
  100. setWritingMode();
  101. }
  102. protected PropertyManager makePropertyManager(
  103. PropertyList propertyList) {
  104. return new PropertyManager(propertyList);
  105. }
  106. protected void addChild(FONode child) {
  107. children.add(child);
  108. }
  109. public void setStructHandler(StructureHandler st) {
  110. structHandler = st;
  111. }
  112. /**
  113. * lets outside sources access the property list
  114. * first used by PageNumberCitation to find the "id" property
  115. * @param name - the name of the desired property to obtain
  116. * @return the property
  117. */
  118. public Property getProperty(String name) {
  119. return (properties.get(name));
  120. }
  121. protected void setupID() {
  122. Property prop = this.properties.get("id");
  123. if(prop != null) {
  124. String str = prop.getString();
  125. if(str != null && !str.equals("")) {
  126. HashSet idrefs = structHandler.getIDReferences();
  127. if(!idrefs.contains(str)) {
  128. id = str;
  129. idrefs.add(id);
  130. } else {
  131. getLogger().warn("duplicate id:" + str + " ignored");
  132. }
  133. }
  134. }
  135. }
  136. /**
  137. * Return the "content width" of the areas generated by this FO.
  138. * This is used by percent-based properties to get the dimension of
  139. * the containing block.
  140. * If an FO has a property with a percentage value, that value
  141. * is usually calculated on the basis of the corresponding dimension
  142. * of the area which contains areas generated by the FO.
  143. * NOTE: subclasses of FObj should implement this to return a reasonable
  144. * value!
  145. */
  146. public int getContentWidth() {
  147. return 0;
  148. }
  149. public boolean generatesReferenceAreas() {
  150. return false;
  151. }
  152. public boolean generatesInlineAreas() {
  153. return true;
  154. }
  155. /**
  156. * Set writing mode for this FO.
  157. * Find nearest ancestor, including self, which generates
  158. * reference areas and use the value of its writing-mode property.
  159. * If no such ancestor is found, use the value on the root FO.
  160. */
  161. protected void setWritingMode() {
  162. FObj p;
  163. FONode parent;
  164. for (p = this; !p.generatesReferenceAreas() &&
  165. (parent = p.getParent()) != null &&
  166. (parent instanceof FObj); p = (FObj) parent)
  167. ;
  168. this.properties.setWritingMode(
  169. p.getProperty("writing-mode").getEnum());
  170. }
  171. /**
  172. * Return a LayoutManager responsible for laying out this FObj's content.
  173. * Must override in subclasses if their content can be laid out.
  174. */
  175. public void addLayoutManager(List list) {
  176. }
  177. /**
  178. * Return an iterator over all the children of this FObj.
  179. * @return A ListIterator.
  180. */
  181. public ListIterator getChildren() {
  182. return children.listIterator();
  183. }
  184. /**
  185. * Return an iterator over the object's children starting
  186. * at the pased node.
  187. * @param childNode First node in the iterator
  188. * @return A ListIterator or null if childNode isn't a child of
  189. * this FObj.
  190. */
  191. public ListIterator getChildren(FONode childNode) {
  192. int i = children.indexOf(childNode);
  193. if (i >= 0) {
  194. return children.listIterator(i);
  195. } else
  196. return null;
  197. }
  198. public void setIsInTableCell() {
  199. this.isInTableCell = true;
  200. // made recursive by Eric Schaeffer
  201. for (int i = 0; i < this.children.size(); i++) {
  202. Object obj = this.children.get(i);
  203. if (obj instanceof FObj) {
  204. FObj child = (FObj) obj;
  205. child.setIsInTableCell();
  206. }
  207. }
  208. }
  209. public void forceStartOffset(int offset) {
  210. this.forcedStartOffset = offset;
  211. // made recursive by Eric Schaeffer
  212. for (int i = 0; i < this.children.size(); i++) {
  213. Object obj = this.children.get(i);
  214. if (obj instanceof FObj) {
  215. FObj child = (FObj) obj;
  216. child.forceStartOffset(offset);
  217. }
  218. }
  219. }
  220. public void forceWidth(int width) {
  221. this.forcedWidth = width;
  222. // made recursive by Eric Schaeffer
  223. for (int i = 0; i < this.children.size(); i++) {
  224. Object obj = this.children.get(i);
  225. if (obj instanceof FObj) {
  226. FObj child = (FObj) obj;
  227. child.forceWidth(width);
  228. }
  229. }
  230. }
  231. public void resetMarker() {
  232. this.marker = START;
  233. int numChildren = this.children.size();
  234. for (int i = 0; i < numChildren; i++) {
  235. Object obj = this.children.get(i);
  236. if (obj instanceof FObj) {
  237. FObj child = (FObj) obj;
  238. child.resetMarker();
  239. }
  240. }
  241. }
  242. public void setWidows(int wid) {
  243. widows = wid;
  244. }
  245. public void setOrphans(int orph) {
  246. orphans = orph;
  247. }
  248. public void removeAreas() {
  249. // still to do
  250. }
  251. /**
  252. * At the start of a new span area layout may be partway through a
  253. * nested FO, and balancing requires rollback to this known point.
  254. * The snapshot records exactly where layout is at.
  255. * @param snapshot a ArrayList of markers (Integer)
  256. * @returns the updated ArrayList of markers (Integers)
  257. */
  258. public ArrayList getMarkerSnapshot(ArrayList snapshot) {
  259. snapshot.add(new Integer(this.marker));
  260. // terminate if no kids or child not yet accessed
  261. if (this.marker < 0)
  262. return snapshot;
  263. else if (children.isEmpty())
  264. return snapshot;
  265. else
  266. return ( (FObj) children.get(this.marker)).getMarkerSnapshot(
  267. snapshot);
  268. }
  269. /**
  270. * When balancing occurs, the flow layout() method restarts at the
  271. * point specified by the current marker snapshot, which is retrieved
  272. * and restored using this method.
  273. * @param snapshot the ArrayList of saved markers (Integers)
  274. */
  275. public void rollback(ArrayList snapshot) {
  276. this.marker = ((Integer) snapshot.get(0)).intValue();
  277. snapshot.remove(0);
  278. if (this.marker == START) {
  279. // make sure all the children of this FO are also reset
  280. resetMarker();
  281. return;
  282. } else if ((this.marker == -1) || children.isEmpty())
  283. return;
  284. int numChildren = this.children.size();
  285. if (this.marker <= START) {
  286. return;
  287. }
  288. for (int i = this.marker + 1; i < numChildren; i++) {
  289. Object obj = this.children.get(i);
  290. if (obj instanceof FObj) {
  291. FObj child = (FObj) obj;
  292. child.resetMarker();
  293. }
  294. }
  295. ((FObj) children.get(this.marker)).rollback(snapshot);
  296. }
  297. public void addMarker(Marker marker) throws FOPException {
  298. String mcname = marker.getMarkerClassName();
  299. if (!markers.containsKey(mcname) && children.isEmpty()) {
  300. markers.put(mcname, marker);
  301. } else {
  302. getLogger().error("fo:marker must be an initial child," + "and 'marker-class-name' must be unique for same parent");
  303. throw new FOPException(
  304. "fo:marker must be an initial child," + "and 'marker-class-name' must be unique for same parent");
  305. }
  306. }
  307. public boolean hasMarkers() {
  308. return !markers.isEmpty();
  309. }
  310. public ArrayList getMarkers() {
  311. return new ArrayList(markers.values());
  312. }
  313. /**
  314. * lets layout managers access FO properties via PropertyManager
  315. * @return the property manager for this FO
  316. */
  317. public PropertyManager getPropertyManager() {
  318. return this.propMgr;
  319. }
  320. }