123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- /*
- * Copyright 1999-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.area;
-
- import java.awt.geom.Rectangle2D;
- import java.io.ObjectOutputStream;
- import java.io.ObjectInputStream;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- import java.util.HashMap;
- import java.util.Iterator;
-
- import org.apache.fop.fo.Constants;
-
- /**
- * Page viewport that specifies the viewport area and holds the page contents.
- * This is the top level object for a page and remains valid for the life
- * of the document and the area tree.
- * This object may be used as a key to reference a page.
- * This is the level that creates the page.
- * The page (reference area) is then rendered inside the page object
- */
- public class PageViewport implements Resolveable, Cloneable {
-
- private Page page;
- private Rectangle2D viewArea;
- private boolean clip = false;
- private String pageNumber = null;
-
- // list of id references and the rectangle on the page
- private Map idReferences = null;
-
- // this keeps a list of currently unresolved areas or extensions
- // once the thing is resolved it is removed
- // when this is empty the page can be rendered
- private Map unresolved = null;
-
- private Map pendingResolved = null;
-
- // hashmap of markers for this page
- // start and end are added by the fo that contains the markers
- private Map markerFirstStart = null;
- private Map markerLastStart = null;
- private Map markerFirstAny = null;
- private Map markerLastEnd = null;
- private Map markerLastAny = null;
-
- /**
- * Create a page viewport.
- * @param p the page reference area that holds the contents
- * @param bounds the bounds of this viewport
- */
- public PageViewport(Page p, Rectangle2D bounds) {
- page = p;
- viewArea = bounds;
- }
-
- /**
- * Set if this viewport should clip.
- * @param c true if this viewport should clip
- */
- public void setClip(boolean c) {
- clip = c;
- }
-
- /**
- * Get the view area rectangle of this viewport.
- * @return the rectangle for this viewport
- */
- public Rectangle2D getViewArea() {
- return viewArea;
- }
-
- /**
- * Get the page reference area with the contents.
- * @return the page reference area
- */
- public Page getPage() {
- return page;
- }
-
- /**
- * Set the page number for this page.
- * @param num the string representing the page number
- */
- public void setPageNumber(String num) {
- pageNumber = num;
- }
-
- /**
- * Get the page number of this page.
- * @return the string that represents this page
- */
- public String getPageNumber() {
- return pageNumber;
- }
-
- /**
- * Get the key for this page viewport.
- * This is used so that a serializable key can be used to
- * lookup the page or some other reference.
- *
- * @return a unique page viewport key for this area tree
- */
- public String getKey() {
- return toString();
- }
-
- /**
- * Add an unresolved id to this page.
- * All unresolved ids for the contents of this page are
- * added to this page. This is so that the resolvers can be
- * serialized with the page to preserve the proper function.
- * @param id the id of the reference
- * @param res the resolver of the reference
- */
- public void addUnresolvedID(String id, Resolveable res) {
- if (unresolved == null) {
- unresolved = new HashMap();
- }
- List list = (List)unresolved.get(id);
- if (list == null) {
- list = new ArrayList();
- unresolved.put(id, list);
- }
- list.add(res);
- }
-
- /**
- * Check if this page has been fully resolved.
- * @return true if the page is resolved and can be rendered
- */
- public boolean isResolved() {
- return unresolved == null;
- }
-
- /**
- * Get the id references for this page.
- * @return always null
- */
- public String[] getIDs() {
- return null;
- }
-
- /**
- * This resolves reference with a list of pages.
- * The pages (PageViewport) contain the rectangle of the area.
- * @param id the id to resolve
- * @param pages the list of pages with the id area
- * may be null if not found
- */
- public void resolve(String id, List pages) {
- if (page == null) {
- if (pendingResolved == null) {
- pendingResolved = new HashMap();
- }
- pendingResolved.put(id, pages);
- } else {
- if (unresolved != null) {
- List todo = (List)unresolved.get(id);
- if (todo != null) {
- for (int count = 0; count < todo.size(); count++) {
- Resolveable res = (Resolveable)todo.get(count);
- res.resolve(id, pages);
- }
- }
- }
- }
- if (unresolved != null) {
- unresolved.remove(id);
- if (unresolved.isEmpty()) {
- unresolved = null;
- }
- }
- }
-
- /**
- * Add the markers for this page.
- * Only the required markers are kept.
- * For "first-starting-within-page" it adds the markers
- * that are starting only if the marker class name is not
- * already added.
- * For "first-including-carryover" it adds any starting marker
- * if the marker class name is not already added.
- * For "last-starting-within-page" it adds all marks that
- * are starting, replacing earlier markers.
- * For "last-ending-within-page" it adds all markers that
- * are ending, replacing earlier markers.
- *
- * Should this logic be placed in the Page layout manager.
- *
- * @param marks the map of markers to add
- * @param start if the area being added is starting or ending
- * @param isfirst isfirst or islast flag
- */
- public void addMarkers(Map marks, boolean start, boolean isfirst) {
- if (start) {
- if (isfirst) {
- if (markerFirstStart == null) {
- markerFirstStart = new HashMap();
- }
- if (markerFirstAny == null) {
- markerFirstAny = new HashMap();
- }
- // only put in new values, leave current
- for (Iterator iter = marks.keySet().iterator(); iter.hasNext();) {
- Object key = iter.next();
- if (!markerFirstStart.containsKey(key)) {
- markerFirstStart.put(key, marks.get(key));
- }
- if (!markerFirstAny.containsKey(key)) {
- markerFirstAny.put(key, marks.get(key));
- }
- }
- if (markerLastStart == null) {
- markerLastStart = new HashMap();
- }
- // replace all
- markerLastStart.putAll(marks);
-
- } else {
- if (markerFirstAny == null) {
- markerFirstAny = new HashMap();
- }
- // only put in new values, leave current
- for (Iterator iter = marks.keySet().iterator(); iter.hasNext();) {
- Object key = iter.next();
- if (!markerFirstAny.containsKey(key)) {
- markerFirstAny.put(key, marks.get(key));
- }
- }
- }
- } else {
- if (!isfirst) {
- if (markerLastEnd == null) {
- markerLastEnd = new HashMap();
- }
- // replace all
- markerLastEnd.putAll(marks);
- }
- if (markerLastAny == null) {
- markerLastAny = new HashMap();
- }
- // replace all
- markerLastAny.putAll(marks);
- }
- }
-
- /**
- * Get a marker from this page.
- * This will retrieve a marker with the class name
- * and position.
- *
- * @param name The class name of the marker to retrieve
- * @param pos the position to retrieve
- * @return Object the marker found or null
- */
- public Object getMarker(String name, int pos) {
- Object mark = null;
- switch (pos) {
- case Constants.RetrievePosition.FSWP:
- if (markerFirstStart != null) {
- mark = markerFirstStart.get(name);
- }
- if (mark == null && markerFirstAny != null) {
- mark = markerFirstAny.get(name);
- }
- break;
- case Constants.RetrievePosition.FIC:
- if (markerFirstAny != null) {
- mark = markerFirstAny.get(name);
- }
- break;
- case Constants.RetrievePosition.LSWP:
- if (markerLastStart != null) {
- mark = markerLastStart.get(name);
- }
- if (mark == null && markerLastAny != null) {
- mark = markerLastAny.get(name);
- }
- break;
- case Constants.RetrievePosition.LEWP:
- if (markerLastEnd != null) {
- mark = markerLastEnd.get(name);
- }
- if (mark == null && markerLastAny != null) {
- mark = markerLastAny.get(name);
- }
- break;
- }
- return mark;
- }
-
- /**
- * Save the page contents to an object stream.
- * The map of unresolved references are set on the page so that
- * the resolvers can be properly serialized and reloaded.
- * @param out the object output stream to write the contents
- * @throws Exception if there is a problem saving the page
- */
- public void savePage(ObjectOutputStream out) throws Exception {
- // set the unresolved references so they are serialized
- page.setUnresolvedReferences(unresolved);
- out.writeObject(page);
- page = null;
- }
-
- /**
- * Load the page contents from an object stream.
- * This loads the page contents from the stream and
- * if there are any unresolved references that were resolved
- * while saved they will be resolved on the page contents.
- * @param in the object input stream to read the page from
- * @throws Exception if there is an error loading the page
- */
- public void loadPage(ObjectInputStream in) throws Exception {
- page = (Page) in.readObject();
- unresolved = page.getUnresolvedReferences();
- if (unresolved != null && pendingResolved != null) {
- for (Iterator iter = pendingResolved.keySet().iterator();
- iter.hasNext();) {
- String id = (String) iter.next();
- resolve(id, (List)pendingResolved.get(id));
- }
- pendingResolved = null;
- }
- }
-
- /**
- * Clone this page.
- * Used by the page master to create a copy of an original page.
- * @return a copy of this page and associated viewports
- */
- public Object clone() {
- Page p = (Page)page.clone();
- PageViewport ret = new PageViewport(p, (Rectangle2D)viewArea.clone());
- return ret;
- }
-
- /**
- * Clear the page contents to save memory.
- * This object is kept for the life of the area tree since
- * it holds id and marker information and is used as a key.
- */
- public void clear() {
- page = null;
- }
-
- /**
- * @see java.lang.Object#toString()
- */
- public String toString() {
- StringBuffer sb = new StringBuffer(64);
- sb.append("PageViewport: page=");
- sb.append(getPageNumber());
- return sb.toString();
- }
- }
|