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.

AreaTree.java 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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.area;
  18. import org.apache.fop.area.extensions.BookmarkData;
  19. import org.apache.fop.fo.extensions.Outline;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.HashMap;
  24. import java.util.Set;
  25. import java.util.HashSet;
  26. import java.util.Iterator;
  27. /**
  28. * Area tree for formatting objects.
  29. *
  30. * Concepts:
  31. * The area tree is to be as small as possible. With minimal classes
  32. * and data to fully represent an area tree for formatting objects.
  33. * The area tree needs to be simple to render and follow the spec
  34. * closely.
  35. * This area tree has the concept of page sequences.
  36. * Where ever possible information is discarded or optimised to
  37. * keep memory use low. The data is also organised to make it
  38. * possible for renderers to minimise their output.
  39. * A page can be saved if not fully resolved and once rendered
  40. * a page contains only size and id reference information.
  41. * The area tree pages are organised in a model that depends on the
  42. * type of renderer.
  43. */
  44. public class AreaTree {
  45. // allows for different models to deal with adding/rendering
  46. // in different situations
  47. private AreaTreeModel model;
  48. private AreaTreeControl atControl;
  49. // hashmap of arraylists containing pages with id area
  50. private Map idLocations = new HashMap();
  51. // list of id's yet to be resolved and arraylists of pages
  52. private Map resolve = new HashMap();
  53. private List treeExtensions = new ArrayList();
  54. /**
  55. * Constructor.
  56. * @param atControl the AreaTreeControl object controlling this AreaTree
  57. */
  58. public AreaTree (AreaTreeControl atControl) {
  59. this.atControl = atControl;
  60. }
  61. /**
  62. * Create a new store pages model.
  63. * @return StorePagesModel the new model
  64. */
  65. public static StorePagesModel createStorePagesModel() {
  66. return new StorePagesModel();
  67. }
  68. /**
  69. * Set the tree model to use for this area tree.
  70. * The different models can have different behaviour
  71. * when pages area added and other changes.
  72. * @param m the area tree model
  73. */
  74. public void setTreeModel(AreaTreeModel m) {
  75. model = m;
  76. }
  77. /**
  78. * Get the area tree model for this area tree.
  79. *
  80. * @return AreaTreeModel the model being used for this area tree
  81. */
  82. public AreaTreeModel getAreaTreeModel() {
  83. return model;
  84. }
  85. /**
  86. * Start a new page sequence.
  87. * This signals that a new page sequence has started in the document.
  88. * @param title the title of the new page sequence or null if no title
  89. */
  90. public void startPageSequence(Title title) {
  91. model.startPageSequence(title);
  92. }
  93. /**
  94. * Add a new page to the area tree.
  95. * @param page the page to add
  96. */
  97. public void addPage(PageViewport page) {
  98. model.addPage(page);
  99. }
  100. /**
  101. * Add an id reference pointing to a page viewport.
  102. * @param id the id of the reference
  103. * @param pv the page viewport that contains the id reference
  104. */
  105. public void addIDRef(String id, PageViewport pv) {
  106. List list = (List)idLocations.get(id);
  107. if (list == null) {
  108. list = new ArrayList();
  109. idLocations.put(id, list);
  110. }
  111. list.add(pv);
  112. Set todo = (Set)resolve.get(id);
  113. if (todo != null) {
  114. for (Iterator iter = todo.iterator(); iter.hasNext();) {
  115. Resolveable res = (Resolveable)iter.next();
  116. res.resolve(id, list);
  117. }
  118. resolve.remove(id);
  119. }
  120. }
  121. /**
  122. * Get the list of id references for an id.
  123. * @param id the id to lookup
  124. * @return the list of id references.
  125. */
  126. public List getIDReferences(String id) {
  127. return (List)idLocations.get(id);
  128. }
  129. /**
  130. * Add an unresolved object with a given id.
  131. * @param id the id reference that needs resolving
  132. * @param res the Resolveable object to resolve
  133. */
  134. public void addUnresolvedID(String id, Resolveable res) {
  135. Set todo = (Set)resolve.get(id);
  136. if (todo == null) {
  137. todo = new HashSet();
  138. resolve.put(id, todo);
  139. }
  140. todo.add(res);
  141. }
  142. /**
  143. * Add a tree extension.
  144. * This checks if the extension is resolveable and attempts
  145. * to resolve or add the resolveable ids for later resolution.
  146. * @param ext the tree extension to add.
  147. */
  148. public void addTreeExtension(TreeExt ext) {
  149. treeExtensions.add(ext);
  150. if (ext.isResolveable()) {
  151. Resolveable res = (Resolveable)ext;
  152. String[] ids = res.getIDs();
  153. for (int count = 0; count < ids.length; count++) {
  154. if (idLocations.containsKey(ids[count])) {
  155. res.resolve(ids[count], (List)idLocations.get(ids[count]));
  156. } else {
  157. Set todo = (Set)resolve.get(ids[count]);
  158. if (todo == null) {
  159. todo = new HashSet();
  160. resolve.put(ids[count], todo);
  161. }
  162. todo.add(ext);
  163. }
  164. }
  165. } else {
  166. handleTreeExtension(ext, TreeExt.IMMEDIATELY);
  167. }
  168. }
  169. /**
  170. * Handle a tree extension.
  171. * This sends the extension to the model for handling.
  172. * @param ext the tree extension to handle
  173. * @param when when the extension should be handled by the model
  174. */
  175. public void handleTreeExtension(TreeExt ext, int when) {
  176. // queue tree extension according to the when
  177. model.addExtension(ext, when);
  178. }
  179. /**
  180. * Signal end of document.
  181. * This indicates that the document is complete and any unresolved
  182. * reference can be dealt with.
  183. */
  184. public void endDocument() {
  185. for (Iterator iter = resolve.keySet().iterator(); iter.hasNext();) {
  186. String id = (String)iter.next();
  187. Set list = (Set)resolve.get(id);
  188. for (Iterator resIter = list.iterator(); resIter.hasNext();) {
  189. Resolveable res = (Resolveable)resIter.next();
  190. if (!res.isResolved()) {
  191. res.resolve(id, null);
  192. }
  193. }
  194. }
  195. model.endDocument();
  196. }
  197. /**
  198. * Create the bookmark data in the area tree.
  199. */
  200. public void addBookmarksToAreaTree() {
  201. if (atControl.getBookmarks() == null) {
  202. return;
  203. }
  204. atControl.getLogger().debug("adding bookmarks to area tree");
  205. BookmarkData data = new BookmarkData();
  206. for (int count = 0; count < atControl.getBookmarks().getOutlines().size(); count++) {
  207. Outline out = (Outline)(atControl.getBookmarks().getOutlines()).get(count);
  208. data.addSubData(createBookmarkData(out));
  209. }
  210. addTreeExtension(data);
  211. data.setAreaTree(this);
  212. }
  213. /**
  214. * Create and return the bookmark data for this outline.
  215. * This creates a bookmark data with the destination
  216. * and adds all the data from child outlines.
  217. *
  218. * @param outline the Outline object for which a bookmark entry should be
  219. * created
  220. * @return the new bookmark data
  221. */
  222. public BookmarkData createBookmarkData(Outline outline) {
  223. BookmarkData data = new BookmarkData(outline.getInternalDestination());
  224. data.setLabel(outline.getLabel());
  225. for (int count = 0; count < outline.getOutlines().size(); count++) {
  226. Outline out = (Outline)(outline.getOutlines()).get(count);
  227. data.addSubData(createBookmarkData(out));
  228. }
  229. return data;
  230. }
  231. public AreaTreeControl getAreaTreeControl() {
  232. return atControl;
  233. }
  234. }