123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /*
- * $Id$
- * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
- * For details on use and redistribution please refer to the
- * LICENSE file included with these sources.
- */
-
- package org.apache.fop.area;
-
- import org.apache.fop.render.Renderer;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.HashMap;
- import java.util.Iterator;
-
- /**
- * Area tree for formatting objects.
- *
- * Concepts:
- * The area tree is to be as small as possible. With minimal classes
- * and data to fully represent an area tree for formatting objects.
- * The area tree needs to be simple to render and follow the spec
- * closely.
- * This area tree has the concept of page sequences.
- * Where ever possible information is discarded or optimised to
- * keep memory use low. The data is also organised to make it
- * possible for renderers to minimise their output.
- * A page can be saved if not fully resolved and once rendered
- * a page contains only size and id reference information.
- * The area tree pages are organised in a model that depends on the
- * type of renderer.
- */
- public class AreaTree {
- // allows for different models to deal with adding/rendering
- // in different situations
- private AreaTreeModel model;
-
- // hashmap of arraylists containing pages with id area
- private HashMap idLocations = new HashMap();
- // list of id's yet to be resolved and arraylists of pages
- private HashMap resolve = new HashMap();
- private ArrayList treeExtensions = new ArrayList();
-
- /**
- * Create a render pages area tree model.
- * @param rend the renderer that will be used
- * @return RenderPagesModel the new area tree model
- */
- public RenderPagesModel createRenderPagesModel(Renderer rend) {
- return new RenderPagesModel(rend);
- }
-
- /**
- * Create a new store pages model.
- * @return StorePagesModel the new model
- */
- public static StorePagesModel createStorePagesModel() {
- return new StorePagesModel();
- }
-
- /**
- * Set the tree model to use for this area tree.
- * The different models can have different behaviour
- * when pages area added and other changes.
- * @param m the area tree model
- */
- public void setTreeModel(AreaTreeModel m) {
- model = m;
- }
-
- /**
- * Start a new page sequence.
- * This signals that a new page sequence has started in the document.
- * @param title the title of the new page sequence or null if no title
- */
- public void startPageSequence(Title title) {
- model.startPageSequence(title);
- }
-
- /**
- * Add a new page to the area tree.
- * @param page the page to add
- */
- public void addPage(PageViewport page) {
- model.addPage(page);
- }
-
- /**
- * Add an id reference pointing to a page viewport.
- * @param id the id of the reference
- * @param pv the page viewport that contains the id reference
- */
- public void addIDRef(String id, PageViewport pv) {
- List list = (List)idLocations.get(id);
- if (list == null) {
- list = new ArrayList();
- idLocations.put(id, list);
- }
- list.add(pv);
-
- List todo = (List)resolve.get(id);
- if (todo != null) {
- for (int count = 0; count < todo.size(); count++) {
- Resolveable res = (Resolveable)todo.get(count);
- res.resolve(id, list);
- }
- resolve.remove(id);
- }
- }
-
- /**
- * Get the list of id references for an id.
- * @param id the id to lookup
- * @return the list of id references.
- */
- public List getIDReferences(String id) {
- return (List)idLocations.get(id);
- }
-
- /**
- * Add an unresolved object with a given id.
- * @param id the id reference that needs resolving
- * @param res the Resolveable object to resolve
- */
- public void addUnresolvedID(String id, Resolveable res) {
- ArrayList todo = (ArrayList)resolve.get(id);
- if (todo == null) {
- todo = new ArrayList();
- resolve.put(id, todo);
- }
- todo.add(res);
- }
-
- /**
- * Add a tree extension.
- * This checks if the extension is resolveable and attempts
- * to resolve or add the resolveable ids for later resolution.
- * @param ext the tree extension to add.
- */
- public void addTreeExtension(TreeExt ext) {
- treeExtensions.add(ext);
- if (ext.isResolveable()) {
- Resolveable res = (Resolveable)ext;
- String[] ids = res.getIDs();
- for (int count = 0; count < ids.length; count++) {
- if (idLocations.containsKey(ids[count])) {
- res.resolve(ids[count], (ArrayList)idLocations.get(ids[count]));
- } else {
- ArrayList todo = (ArrayList)resolve.get(ids[count]);
- if (todo == null) {
- todo = new ArrayList();
- resolve.put(ids[count], todo);
- }
- todo.add(ext);
- }
- }
- } else {
- handleTreeExtension(ext, TreeExt.IMMEDIATELY);
- }
- }
-
- /**
- * Handle a tree extension.
- * This sends the extension to the model for handling.
- * @param ext the tree extension to handle
- * @param when when the extension should be handled by the model
- */
- public void handleTreeExtension(TreeExt ext, int when) {
- // queue tree extension according to the when
- model.addExtension(ext, when);
- }
-
- /**
- * Signal end of document.
- * This indicates that the document is complete and any unresolved
- * reference can be dealt with.
- */
- public void endDocument() {
- for (Iterator iter = resolve.keySet().iterator(); iter.hasNext();) {
- String id = (String)iter.next();
- ArrayList list = (ArrayList)resolve.get(id);
- for (int count = 0; count < list.size(); count++) {
- Resolveable res = (Resolveable)list.get(count);
- if (!res.isResolved()) {
- res.resolve(id, null);
- }
- }
- }
- model.endDocument();
- }
-
- /**
- * This is the model for the area tree object.
- * The model implementation can handle the page sequence,
- * page and extensions.
- */
- public abstract static class AreaTreeModel {
- /**
- * Start a page sequence on this model.
- * @param title the title of the new page sequence
- */
- public abstract void startPageSequence(Title title);
-
- /**
- * Add a page to this moel.
- * @param page the page to add to the model.
- */
- public abstract void addPage(PageViewport page);
-
- /**
- * Add an extension to this model.
- * @param ext the extension to add
- * @param when when the extension should be handled
- */
- public abstract void addExtension(TreeExt ext, int when);
-
- /**
- * Signal the end of the document for any processing.
- */
- public abstract void endDocument();
- }
-
- /**
- * This class stores all the pages in the document
- * for interactive agents.
- * The pages are stored and can be retrieved in any order.
- */
- public static class StorePagesModel extends AreaTreeModel {
- private ArrayList pageSequence = null;
- private ArrayList titles = new ArrayList();
- private ArrayList currSequence;
- private ArrayList extensions = new ArrayList();
-
- /**
- * Create a new store pages model
- */
- public StorePagesModel() {
- }
-
- /**
- * Start a new page sequence.
- * This creates a new list for the pages in the new page sequence.
- * @param title the title of the page sequence.
- */
- public void startPageSequence(Title title) {
- titles.add(title);
- if (pageSequence == null) {
- pageSequence = new ArrayList();
- }
- currSequence = new ArrayList();
- pageSequence.add(currSequence);
- }
-
- /**
- * Add a page.
- * @param page the page to add to the current page sequence
- */
- public void addPage(PageViewport page) {
- currSequence.add(page);
- }
-
- /**
- * Get the page sequence count.
- * @return the number of page sequences in the document.
- */
- public int getPageSequenceCount() {
- return pageSequence.size();
- }
-
- /**
- * Get the title for a page sequence.
- * @param count the page sequence count
- * @return the title of the page sequence
- */
- public Title getTitle(int count) {
- return (Title) titles.get(count);
- }
-
- /**
- * Get the page count.
- * @param seq the page sequence to count.
- * @return returns the number of pages in a page sequence
- */
- public int getPageCount(int seq) {
- ArrayList sequence = (ArrayList) pageSequence.get(seq);
- return sequence.size();
- }
-
- /**
- * Get the page for a position in the document.
- * @param seq the page sequence number
- * @param count the page count in the sequence
- * @return the PageViewport for the particular page
- */
- public PageViewport getPage(int seq, int count) {
- ArrayList sequence = (ArrayList) pageSequence.get(seq);
- return (PageViewport) sequence.get(count);
- }
-
- /**
- * Add an extension to the store page model.
- * The extension is stored so that it can be retrieved in the
- * appropriate position.
- * @param ext the extension to add
- * @param when when the extension should be handled
- */
- public void addExtension(TreeExt ext, int when) {
- int seq, page;
- switch(when) {
- case TreeExt.IMMEDIATELY:
- seq = pageSequence == null ? 0 : pageSequence.size();
- page = currSequence == null ? 0 : currSequence.size();
- break;
- case TreeExt.AFTER_PAGE:
- break;
- case TreeExt.END_OF_DOC:
- break;
- }
- extensions.add(ext);
- }
-
- /**
- * Get the list of extensions that apply at a particular
- * position in the document.
- * @param seq the page sequence number
- * @param count the page count in the sequence
- * @return the list of extensions
- */
- public List getExtensions(int seq, int count) {
- return null;
- }
-
- /**
- * Get the end of document extensions for this stroe pages model.
- * @return the list of end extensions
- */
- public List getEndExtensions() {
- return extensions;
- }
-
- /**
- * End document, do nothing.
- */
- public void endDocument() {
- }
- }
-
- /**
- * This uses the store pages model to store the pages
- * each page is either rendered if ready or prepared
- * for later rendering.
- * Once a page is rendered it is cleared to release the
- * contents but the PageViewport is retained.
- */
- public static class RenderPagesModel extends StorePagesModel {
- private Renderer renderer;
- private ArrayList prepared = new ArrayList();
- private ArrayList pendingExt = new ArrayList();
- private ArrayList endDocExt = new ArrayList();
-
- /**
- * Create a new render pages model with the given renderer.
- * @param rend the renderer to render pages to
- */
- public RenderPagesModel(Renderer rend) {
- renderer = rend;
- }
-
- /**
- * Start a new page sequence.
- * This tells the renderer that a new page sequence has
- * started with the given title.
- * @param title the title of the new page sequence
- */
- public void startPageSequence(Title title) {
- super.startPageSequence(title);
- renderer.startPageSequence(title);
- }
-
- /**
- * Add a page to the render page model.
- * If the page is finished it can be rendered immediately.
- * If the page needs resolving then if the renderer supports
- * out of order rendering it can prepare the page. Otherwise
- * the page is added to a queue.
- * @param page the page to add to the model
- */
- public void addPage(PageViewport page) {
- super.addPage(page);
- // if page finished
- try {
- renderer.renderPage(page);
- } catch (Exception e) {
- // use error handler to handle this FOP or IO Exception
- }
- page.clear();
-
- renderExtensions(pendingExt);
- pendingExt.clear();
-
- // else prepare
- //renderer.preparePage(page);
- prepared.add(page);
- }
-
- /**
- * Add an extension to this model.
- * If handle immediately then send directly to the renderer.
- * The after page ones are handled after the next page is added.
- * End of document extensions are added to a list to be
- * handled at the end.
- * @param ext the extension
- * @param when when to render the extension
- */
- public void addExtension(TreeExt ext, int when) {
- switch(when) {
- case TreeExt.IMMEDIATELY:
- renderer.renderExtension(ext);
- break;
- case TreeExt.AFTER_PAGE:
- pendingExt.add(ext);
- break;
- case TreeExt.END_OF_DOC:
- endDocExt.add(ext);
- break;
- }
- }
-
- private void renderExtensions(ArrayList list) {
- for (int count = 0; count < list.size(); count++) {
- TreeExt ext = (TreeExt)list.get(count);
- renderer.renderExtension(ext);
- }
- }
-
- /**
- * End the document. Render any end document extensions.
- */
- public void endDocument() {
- renderExtensions(endDocExt);
- }
- }
-
- }
|