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.

PageViewport.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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 java.awt.geom.Rectangle2D;
  19. import java.io.ObjectOutputStream;
  20. import java.io.ObjectInputStream;
  21. import java.util.ArrayList;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.HashMap;
  25. import java.util.Iterator;
  26. import org.apache.fop.fo.Constants;
  27. /**
  28. * Page viewport that specifies the viewport area and holds the page contents.
  29. * This is the top level object for a page and remains valid for the life
  30. * of the document and the area tree.
  31. * This object may be used as a key to reference a page.
  32. * This is the level that creates the page.
  33. * The page (reference area) is then rendered inside the page object
  34. */
  35. public class PageViewport implements Resolveable, Cloneable {
  36. private Page page;
  37. private Rectangle2D viewArea;
  38. private boolean clip = false;
  39. private String pageNumber = null;
  40. // list of id references and the rectangle on the page
  41. private Map idReferences = null;
  42. // this keeps a list of currently unresolved areas or extensions
  43. // once the thing is resolved it is removed
  44. // when this is empty the page can be rendered
  45. private Map unresolved = null;
  46. private Map pendingResolved = null;
  47. // hashmap of markers for this page
  48. // start and end are added by the fo that contains the markers
  49. private Map markerFirstStart = null;
  50. private Map markerLastStart = null;
  51. private Map markerFirstAny = null;
  52. private Map markerLastEnd = null;
  53. private Map markerLastAny = null;
  54. /**
  55. * Create a page viewport.
  56. * @param p the page reference area that holds the contents
  57. * @param bounds the bounds of this viewport
  58. */
  59. public PageViewport(Page p, Rectangle2D bounds) {
  60. page = p;
  61. viewArea = bounds;
  62. }
  63. /**
  64. * Set if this viewport should clip.
  65. * @param c true if this viewport should clip
  66. */
  67. public void setClip(boolean c) {
  68. clip = c;
  69. }
  70. /**
  71. * Get the view area rectangle of this viewport.
  72. * @return the rectangle for this viewport
  73. */
  74. public Rectangle2D getViewArea() {
  75. return viewArea;
  76. }
  77. /**
  78. * Get the page reference area with the contents.
  79. * @return the page reference area
  80. */
  81. public Page getPage() {
  82. return page;
  83. }
  84. /**
  85. * Set the page number for this page.
  86. * @param num the string representing the page number
  87. */
  88. public void setPageNumber(String num) {
  89. pageNumber = num;
  90. }
  91. /**
  92. * Get the page number of this page.
  93. * @return the string that represents this page
  94. */
  95. public String getPageNumber() {
  96. return pageNumber;
  97. }
  98. /**
  99. * Get the key for this page viewport.
  100. * This is used so that a serializable key can be used to
  101. * lookup the page or some other reference.
  102. *
  103. * @return a unique page viewport key for this area tree
  104. */
  105. public String getKey() {
  106. return toString();
  107. }
  108. /**
  109. * Add an unresolved id to this page.
  110. * All unresolved ids for the contents of this page are
  111. * added to this page. This is so that the resolvers can be
  112. * serialized with the page to preserve the proper function.
  113. * @param id the id of the reference
  114. * @param res the resolver of the reference
  115. */
  116. public void addUnresolvedID(String id, Resolveable res) {
  117. if (unresolved == null) {
  118. unresolved = new HashMap();
  119. }
  120. List list = (List)unresolved.get(id);
  121. if (list == null) {
  122. list = new ArrayList();
  123. unresolved.put(id, list);
  124. }
  125. list.add(res);
  126. }
  127. /**
  128. * Check if this page has been fully resolved.
  129. * @return true if the page is resolved and can be rendered
  130. */
  131. public boolean isResolved() {
  132. return unresolved == null;
  133. }
  134. /**
  135. * Get the id references for this page.
  136. * @return always null
  137. */
  138. public String[] getIDs() {
  139. return null;
  140. }
  141. /**
  142. * This resolves reference with a list of pages.
  143. * The pages (PageViewport) contain the rectangle of the area.
  144. * @param id the id to resolve
  145. * @param pages the list of pages with the id area
  146. * may be null if not found
  147. */
  148. public void resolve(String id, List pages) {
  149. if (page == null) {
  150. if (pendingResolved == null) {
  151. pendingResolved = new HashMap();
  152. }
  153. pendingResolved.put(id, pages);
  154. } else {
  155. if (unresolved != null) {
  156. List todo = (List)unresolved.get(id);
  157. if (todo != null) {
  158. for (int count = 0; count < todo.size(); count++) {
  159. Resolveable res = (Resolveable)todo.get(count);
  160. res.resolve(id, pages);
  161. }
  162. }
  163. }
  164. }
  165. if (unresolved != null) {
  166. unresolved.remove(id);
  167. if (unresolved.isEmpty()) {
  168. unresolved = null;
  169. }
  170. }
  171. }
  172. /**
  173. * Add the markers for this page.
  174. * Only the required markers are kept.
  175. * For "first-starting-within-page" it adds the markers
  176. * that are starting only if the marker class name is not
  177. * already added.
  178. * For "first-including-carryover" it adds any starting marker
  179. * if the marker class name is not already added.
  180. * For "last-starting-within-page" it adds all marks that
  181. * are starting, replacing earlier markers.
  182. * For "last-ending-within-page" it adds all markers that
  183. * are ending, replacing earlier markers.
  184. *
  185. * Should this logic be placed in the Page layout manager.
  186. *
  187. * @param marks the map of markers to add
  188. * @param start if the area being added is starting or ending
  189. * @param isfirst isfirst or islast flag
  190. */
  191. public void addMarkers(Map marks, boolean start, boolean isfirst) {
  192. if (start) {
  193. if (isfirst) {
  194. if (markerFirstStart == null) {
  195. markerFirstStart = new HashMap();
  196. }
  197. if (markerFirstAny == null) {
  198. markerFirstAny = new HashMap();
  199. }
  200. // only put in new values, leave current
  201. for (Iterator iter = marks.keySet().iterator(); iter.hasNext();) {
  202. Object key = iter.next();
  203. if (!markerFirstStart.containsKey(key)) {
  204. markerFirstStart.put(key, marks.get(key));
  205. }
  206. if (!markerFirstAny.containsKey(key)) {
  207. markerFirstAny.put(key, marks.get(key));
  208. }
  209. }
  210. if (markerLastStart == null) {
  211. markerLastStart = new HashMap();
  212. }
  213. // replace all
  214. markerLastStart.putAll(marks);
  215. } else {
  216. if (markerFirstAny == null) {
  217. markerFirstAny = new HashMap();
  218. }
  219. // only put in new values, leave current
  220. for (Iterator iter = marks.keySet().iterator(); iter.hasNext();) {
  221. Object key = iter.next();
  222. if (!markerFirstAny.containsKey(key)) {
  223. markerFirstAny.put(key, marks.get(key));
  224. }
  225. }
  226. }
  227. } else {
  228. if (!isfirst) {
  229. if (markerLastEnd == null) {
  230. markerLastEnd = new HashMap();
  231. }
  232. // replace all
  233. markerLastEnd.putAll(marks);
  234. }
  235. if (markerLastAny == null) {
  236. markerLastAny = new HashMap();
  237. }
  238. // replace all
  239. markerLastAny.putAll(marks);
  240. }
  241. }
  242. /**
  243. * Get a marker from this page.
  244. * This will retrieve a marker with the class name
  245. * and position.
  246. *
  247. * @param name The class name of the marker to retrieve
  248. * @param pos the position to retrieve
  249. * @return Object the marker found or null
  250. */
  251. public Object getMarker(String name, int pos) {
  252. Object mark = null;
  253. switch (pos) {
  254. case Constants.RetrievePosition.FSWP:
  255. if (markerFirstStart != null) {
  256. mark = markerFirstStart.get(name);
  257. }
  258. if (mark == null && markerFirstAny != null) {
  259. mark = markerFirstAny.get(name);
  260. }
  261. break;
  262. case Constants.RetrievePosition.FIC:
  263. if (markerFirstAny != null) {
  264. mark = markerFirstAny.get(name);
  265. }
  266. break;
  267. case Constants.RetrievePosition.LSWP:
  268. if (markerLastStart != null) {
  269. mark = markerLastStart.get(name);
  270. }
  271. if (mark == null && markerLastAny != null) {
  272. mark = markerLastAny.get(name);
  273. }
  274. break;
  275. case Constants.RetrievePosition.LEWP:
  276. if (markerLastEnd != null) {
  277. mark = markerLastEnd.get(name);
  278. }
  279. if (mark == null && markerLastAny != null) {
  280. mark = markerLastAny.get(name);
  281. }
  282. break;
  283. }
  284. return mark;
  285. }
  286. /**
  287. * Save the page contents to an object stream.
  288. * The map of unresolved references are set on the page so that
  289. * the resolvers can be properly serialized and reloaded.
  290. * @param out the object output stream to write the contents
  291. * @throws Exception if there is a problem saving the page
  292. */
  293. public void savePage(ObjectOutputStream out) throws Exception {
  294. // set the unresolved references so they are serialized
  295. page.setUnresolvedReferences(unresolved);
  296. out.writeObject(page);
  297. page = null;
  298. }
  299. /**
  300. * Load the page contents from an object stream.
  301. * This loads the page contents from the stream and
  302. * if there are any unresolved references that were resolved
  303. * while saved they will be resolved on the page contents.
  304. * @param in the object input stream to read the page from
  305. * @throws Exception if there is an error loading the page
  306. */
  307. public void loadPage(ObjectInputStream in) throws Exception {
  308. page = (Page) in.readObject();
  309. unresolved = page.getUnresolvedReferences();
  310. if (unresolved != null && pendingResolved != null) {
  311. for (Iterator iter = pendingResolved.keySet().iterator();
  312. iter.hasNext();) {
  313. String id = (String) iter.next();
  314. resolve(id, (List)pendingResolved.get(id));
  315. }
  316. pendingResolved = null;
  317. }
  318. }
  319. /**
  320. * Clone this page.
  321. * Used by the page master to create a copy of an original page.
  322. * @return a copy of this page and associated viewports
  323. */
  324. public Object clone() {
  325. Page p = (Page)page.clone();
  326. PageViewport ret = new PageViewport(p, (Rectangle2D)viewArea.clone());
  327. return ret;
  328. }
  329. /**
  330. * Clear the page contents to save memory.
  331. * This object is kept for the life of the area tree since
  332. * it holds id and marker information and is used as a key.
  333. */
  334. public void clear() {
  335. page = null;
  336. }
  337. /**
  338. * @see java.lang.Object#toString()
  339. */
  340. public String toString() {
  341. StringBuffer sb = new StringBuffer(64);
  342. sb.append("PageViewport: page=");
  343. sb.append(getPageNumber());
  344. return sb.toString();
  345. }
  346. }