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.

IDTracker.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.area;
  19. import java.util.ArrayList;
  20. import java.util.HashMap;
  21. import java.util.HashSet;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Set;
  26. import org.apache.commons.logging.Log;
  27. import org.apache.commons.logging.LogFactory;
  28. /**
  29. * Used by the AreaTreeHandler to keep track of ID reference usage
  30. * on a PageViewport level.
  31. */
  32. public class IDTracker {
  33. private static Log log = LogFactory.getLog(IDTracker.class);
  34. // HashMap of ID's whose area is located on one or more consecutive
  35. // PageViewports. Each ID has an arraylist of PageViewports that
  36. // form the defined area of this ID
  37. private Map idLocations = new HashMap();
  38. // idref's whose target PageViewports have yet to be identified
  39. // Each idref has a HashSet of Resolvable objects containing that idref
  40. private Map unresolvedIDRefs = new HashMap();
  41. private Set unfinishedIDs = new HashSet();
  42. private Set alreadyResolvedIDs = new HashSet();
  43. /**
  44. * Tie a PageViewport with an ID found on a child area of the PV. Note that
  45. * an area with a given ID may be on more than one PV, hence an ID may have
  46. * more than one PV associated with it.
  47. *
  48. * @param id the property ID of the area
  49. * @param pv a page viewport that contains the area with this ID
  50. */
  51. public void associateIDWithPageViewport(String id, PageViewport pv) {
  52. if (log.isDebugEnabled()) {
  53. log.debug("associateIDWithPageViewport(" + id + ", " + pv + ")");
  54. }
  55. List pvList = (List) idLocations.get(id);
  56. if (pvList == null) { // first time ID located
  57. pvList = new ArrayList();
  58. idLocations.put(id, pvList);
  59. pvList.add(pv);
  60. // signal the PageViewport that it is the first PV to contain this id:
  61. pv.setFirstWithID(id);
  62. /*
  63. * See if this ID is in the unresolved idref list, if so resolve
  64. * Resolvable objects tied to it.
  65. */
  66. if (!unfinishedIDs.contains(id)) {
  67. tryIDResolution(id, pv, pvList);
  68. }
  69. } else {
  70. /* TODO: The check is a quick-fix to avoid a waste
  71. * when adding inline-ids to the page */
  72. if (!pvList.contains(pv)) {
  73. pvList.add(pv);
  74. }
  75. }
  76. }
  77. /**
  78. * This method tie an ID to the areaTreeHandler until this one is ready to
  79. * be processed. This is used in page-number-citation-last processing so we
  80. * know when an id can be resolved.
  81. *
  82. * @param id the id of the object being processed
  83. */
  84. public void signalPendingID(String id) {
  85. if (log.isDebugEnabled()) {
  86. log.debug("signalPendingID(" + id + ")");
  87. }
  88. unfinishedIDs.add(id);
  89. }
  90. /**
  91. * Signals that all areas for the formatting object with the given ID have
  92. * been generated. This is used to determine when page-number-citation-last
  93. * ref-ids can be resolved.
  94. *
  95. * @param id the id of the formatting object which was just finished
  96. */
  97. public void signalIDProcessed(String id) {
  98. if (log.isDebugEnabled()) {
  99. log.debug("signalIDProcessed(" + id + ")");
  100. }
  101. alreadyResolvedIDs.add(id);
  102. if (!unfinishedIDs.contains(id)) {
  103. return;
  104. }
  105. unfinishedIDs.remove(id);
  106. List pvList = (List) idLocations.get(id);
  107. Set todo = (Set) unresolvedIDRefs.get(id);
  108. if (todo != null) {
  109. for (Iterator iter = todo.iterator(); iter.hasNext();) {
  110. Resolvable res = (Resolvable) iter.next();
  111. res.resolveIDRef(id, pvList);
  112. }
  113. unresolvedIDRefs.remove(id);
  114. }
  115. }
  116. /**
  117. * Check if an ID has already been resolved
  118. *
  119. * @param id the id to check
  120. * @return true if the ID has been resolved
  121. */
  122. public boolean alreadyResolvedID(String id) {
  123. return (alreadyResolvedIDs.contains(id));
  124. }
  125. /**
  126. * Tries to resolve all unresolved ID references on the given page.
  127. *
  128. * @param id ID to resolve
  129. * @param pv page viewport whose ID refs to resolve
  130. * @param pvList of PageViewports
  131. */
  132. private void tryIDResolution(String id, PageViewport pv, List pvList) {
  133. Set todo = (Set) unresolvedIDRefs.get(id);
  134. if (todo != null) {
  135. for (Iterator iter = todo.iterator(); iter.hasNext();) {
  136. Resolvable res = (Resolvable) iter.next();
  137. if (!unfinishedIDs.contains(id)) {
  138. res.resolveIDRef(id, pvList);
  139. } else {
  140. return;
  141. }
  142. }
  143. alreadyResolvedIDs.add(id);
  144. unresolvedIDRefs.remove(id);
  145. }
  146. }
  147. /**
  148. * Tries to resolve all unresolved ID references on the given page.
  149. *
  150. * @param pv page viewport whose ID refs to resolve
  151. */
  152. public void tryIDResolution(PageViewport pv) {
  153. String[] ids = pv.getIDRefs();
  154. if (ids != null) {
  155. for (int i = 0; i < ids.length; i++) {
  156. List pvList = (List) idLocations.get(ids[i]);
  157. if (pvList != null) {
  158. tryIDResolution(ids[i], pv, pvList);
  159. }
  160. }
  161. }
  162. }
  163. /**
  164. * Get the list of page viewports that have an area with a given id.
  165. *
  166. * @param id the id to lookup
  167. * @return the list of PageViewports
  168. */
  169. public List getPageViewportsContainingID(String id) {
  170. return (List) idLocations.get(id);
  171. }
  172. /**
  173. * Add an Resolvable object with an unresolved idref
  174. *
  175. * @param idref the idref whose target id has not yet been located
  176. * @param res the Resolvable object needing the idref to be resolved
  177. */
  178. public void addUnresolvedIDRef(String idref, Resolvable res) {
  179. Set todo = (Set) unresolvedIDRefs.get(idref);
  180. if (todo == null) {
  181. todo = new HashSet();
  182. unresolvedIDRefs.put(idref, todo);
  183. }
  184. // add Resolvable object to this HashSet
  185. todo.add(res);
  186. }
  187. }