選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

AbstractLayoutManager.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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.layoutmgr;
  19. import java.util.ArrayList;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.ListIterator;
  23. import java.util.Map;
  24. import org.apache.commons.logging.Log;
  25. import org.apache.commons.logging.LogFactory;
  26. import org.apache.fop.area.Area;
  27. import org.apache.fop.area.PageViewport;
  28. import org.apache.fop.fo.Constants;
  29. import org.apache.fop.fo.FONode;
  30. import org.apache.fop.fo.FObj;
  31. import org.apache.fop.fo.flow.RetrieveMarker;
  32. /**
  33. * The base class for most LayoutManagers.
  34. */
  35. public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
  36. implements Constants {
  37. /**
  38. * logging instance
  39. */
  40. private static Log log = LogFactory.getLog(AbstractLayoutManager.class);
  41. /** Parent LayoutManager for this LayoutManager */
  42. protected LayoutManager parentLM = null;
  43. /** List of child LayoutManagers */
  44. protected List childLMs = null;
  45. /** Iterator for child LayoutManagers */
  46. protected ListIterator fobjIter = null;
  47. /** Marker map for markers related to this LayoutManager */
  48. private Map markers = null;
  49. /** True if this LayoutManager has handled all of its content. */
  50. private boolean bFinished = false;
  51. /** child LM during getNextKnuthElement phase */
  52. protected LayoutManager curChildLM = null;
  53. /** child LM iterator during getNextKnuthElement phase */
  54. protected ListIterator childLMiter = null;
  55. private int lastGeneratedPosition = -1;
  56. private int smallestPosNumberChecked = Integer.MAX_VALUE;
  57. /**
  58. * Abstract layout manager.
  59. */
  60. public AbstractLayoutManager() {
  61. }
  62. /**
  63. * Abstract layout manager.
  64. *
  65. * @param fo the formatting object for this layout manager
  66. */
  67. public AbstractLayoutManager(FObj fo) {
  68. super(fo);
  69. if (fo == null) {
  70. throw new IllegalStateException("Null formatting object found.");
  71. }
  72. markers = fo.getMarkers();
  73. fobjIter = fo.getChildNodes();
  74. childLMiter = new LMiter(this);
  75. }
  76. /** {@inheritDoc} */
  77. public void setParent(LayoutManager lm) {
  78. this.parentLM = lm;
  79. }
  80. /** {@inheritDoc} */
  81. public LayoutManager getParent() {
  82. return this.parentLM;
  83. }
  84. /** {@inheritDoc} */
  85. public void initialize() {
  86. // Empty
  87. }
  88. /**
  89. * Return currently active child LayoutManager or null if
  90. * all children have finished layout.
  91. * Note: child must implement LayoutManager! If it doesn't, skip it
  92. * and print a warning.
  93. * @return the current child LayoutManager
  94. */
  95. protected LayoutManager getChildLM() {
  96. if (curChildLM != null && !curChildLM.isFinished()) {
  97. return curChildLM;
  98. }
  99. if (childLMiter.hasNext()) {
  100. curChildLM = (LayoutManager) childLMiter.next();
  101. curChildLM.initialize();
  102. return curChildLM;
  103. }
  104. return null;
  105. }
  106. /**
  107. * Return indication if getChildLM will return another LM.
  108. * @return true if another child LM is still available
  109. */
  110. protected boolean hasNextChildLM() {
  111. return childLMiter.hasNext();
  112. }
  113. /**
  114. * Tell whether this LayoutManager has handled all of its content.
  115. * @return True if there are no more break possibilities,
  116. * ie. the last one returned represents the end of the content.
  117. */
  118. public boolean isFinished() {
  119. return bFinished;
  120. }
  121. /**
  122. * Set the flag indicating the LayoutManager has handled all of its content.
  123. * @param fin the flag value to be set
  124. */
  125. public void setFinished(boolean fin) {
  126. bFinished = fin;
  127. }
  128. /**
  129. * {@inheritDoc}
  130. */
  131. public void addAreas(PositionIterator posIter, LayoutContext context) {
  132. }
  133. /**
  134. * {@inheritDoc}
  135. */
  136. public LinkedList getNextKnuthElements(LayoutContext context,
  137. int alignment) {
  138. log.warn("null implementation of getNextKnuthElements() called!");
  139. setFinished(true);
  140. return null;
  141. }
  142. /**
  143. * {@inheritDoc}
  144. */
  145. public LinkedList getChangedKnuthElements(List oldList,
  146. int alignment) {
  147. log.warn("null implementation of getChangeKnuthElement() called!");
  148. return null;
  149. }
  150. /**
  151. * Return an Area which can contain the passed childArea. The childArea
  152. * may not yet have any content, but it has essential traits set.
  153. * In general, if the LayoutManager already has an Area it simply returns
  154. * it. Otherwise, it makes a new Area of the appropriate class.
  155. * It gets a parent area for its area by calling its parent LM.
  156. * Finally, based on the dimensions of the parent area, it initializes
  157. * its own area. This includes setting the content IPD and the maximum
  158. * BPD.
  159. * @param childArea the child area for which the parent area is wanted
  160. * @return the parent area for the given child
  161. */
  162. public Area getParentArea(Area childArea) {
  163. return null;
  164. }
  165. /**
  166. * Add a child area to the current area. If this causes the maximum
  167. * dimension of the current area to be exceeded, the parent LM is called
  168. * to add it.
  169. * @param childArea the child area to be added
  170. */
  171. public void addChildArea(Area childArea) {
  172. }
  173. /**
  174. * Create the LM instances for the children of the
  175. * formatting object being handled by this LM.
  176. * @param size the requested number of child LMs
  177. * @return the list with the preloaded child LMs
  178. */
  179. protected List createChildLMs(int size) {
  180. if (fobjIter == null) {
  181. return null;
  182. }
  183. List newLMs = new ArrayList(size);
  184. while (fobjIter.hasNext() && newLMs.size() < size ) {
  185. Object theobj = fobjIter.next();
  186. if (theobj instanceof FONode) {
  187. FONode foNode = (FONode) theobj;
  188. if (foNode instanceof RetrieveMarker) {
  189. foNode = getPSLM().resolveRetrieveMarker(
  190. (RetrieveMarker) foNode);
  191. }
  192. if (foNode != null) {
  193. getPSLM().getLayoutManagerMaker().
  194. makeLayoutManagers(foNode, newLMs);
  195. }
  196. }
  197. }
  198. return newLMs;
  199. }
  200. /** {@inheritDoc} */
  201. public PageSequenceLayoutManager getPSLM() {
  202. return parentLM.getPSLM();
  203. }
  204. /**
  205. * @see PageSequenceLayoutManager#getCurrentPage()
  206. * @return the {@link Page} instance corresponding to the current page
  207. */
  208. public Page getCurrentPage() {
  209. return getPSLM().getCurrentPage();
  210. }
  211. /** @return the current page viewport */
  212. public PageViewport getCurrentPV() {
  213. return getPSLM().getCurrentPage().getPageViewport();
  214. }
  215. /**
  216. * {@inheritDoc}
  217. */
  218. public boolean createNextChildLMs(int pos) {
  219. List newLMs = createChildLMs(pos + 1 - childLMs.size());
  220. addChildLMs(newLMs);
  221. return pos < childLMs.size();
  222. }
  223. /**
  224. * {@inheritDoc}
  225. */
  226. public List getChildLMs() {
  227. if (childLMs == null) {
  228. childLMs = new java.util.ArrayList(10);
  229. }
  230. return childLMs;
  231. }
  232. /**
  233. * {@inheritDoc}
  234. */
  235. public void addChildLM(LayoutManager lm) {
  236. if (lm == null) {
  237. return;
  238. }
  239. lm.setParent(this);
  240. if (childLMs == null) {
  241. childLMs = new java.util.ArrayList(10);
  242. }
  243. childLMs.add(lm);
  244. log.trace(this.getClass().getName()
  245. + ": Adding child LM " + lm.getClass().getName());
  246. }
  247. /**
  248. * {@inheritDoc}
  249. */
  250. public void addChildLMs(List newLMs) {
  251. if (newLMs == null || newLMs.size() == 0) {
  252. return;
  253. }
  254. ListIterator iter = newLMs.listIterator();
  255. while (iter.hasNext()) {
  256. LayoutManager lm = (LayoutManager) iter.next();
  257. addChildLM(lm);
  258. }
  259. }
  260. /**
  261. * Adds a Position to the Position participating in the first|last determination by assigning
  262. * it a unique position index.
  263. * @param pos the Position
  264. * @return the same Position but with a position index
  265. */
  266. public Position notifyPos(Position pos) {
  267. if (pos.getIndex() >= 0) {
  268. throw new IllegalStateException("Position already got its index");
  269. }
  270. lastGeneratedPosition++;
  271. pos.setIndex(lastGeneratedPosition);
  272. return pos;
  273. }
  274. /**
  275. * Indicates whether the given Position is the first area-generating Position of this LM.
  276. * @param pos the Position (must be one with a position index)
  277. * @return True if it is the first Position
  278. */
  279. public boolean isFirst(Position pos) {
  280. //log.trace("isFirst() smallestPosNumberChecked=" + smallestPosNumberChecked + " " + pos);
  281. if (pos == null || pos.getIndex() < 0) {
  282. throw new IllegalArgumentException("Only non-null Positions with an index can be checked");
  283. }
  284. if (pos.getIndex() == this.smallestPosNumberChecked) {
  285. return true;
  286. } else if (pos.getIndex() < this.smallestPosNumberChecked) {
  287. this.smallestPosNumberChecked = pos.getIndex();
  288. return true;
  289. } else {
  290. return false;
  291. }
  292. }
  293. /**
  294. * Indicates whether the given Position is the last area-generating Position of this LM.
  295. * @param pos the Position (must be one with a position index)
  296. * @return True if it is the last Position
  297. */
  298. public boolean isLast(Position pos) {
  299. //log.trace("isLast() lastGenPos=" + lastGeneratedPosition + " " + pos);
  300. if (pos == null || pos.getIndex() < 0) {
  301. throw new IllegalArgumentException("Only non-null Positions with an index can be checked");
  302. }
  303. return (pos.getIndex() == this.lastGeneratedPosition
  304. && isFinished());
  305. }
  306. /**
  307. * Transfers foreign attributes from the formatting object to the area.
  308. * @param targetArea the area to set the attributes on
  309. */
  310. protected void transferForeignAttributes(Area targetArea) {
  311. Map atts = fobj.getForeignAttributes();
  312. targetArea.setForeignAttributes(atts);
  313. }
  314. /**
  315. * Registers the FO's markers on the current PageViewport
  316. *
  317. * @param isStarting boolean indicating whether the markers qualify as 'starting'
  318. * @param isFirst boolean indicating whether the markers qualify as 'first'
  319. * @param isLast boolean indicating whether the markers qualify as 'last'
  320. */
  321. protected void addMarkersToPage(boolean isStarting, boolean isFirst, boolean isLast) {
  322. if (this.markers != null) {
  323. getCurrentPV().addMarkers(
  324. this.markers,
  325. isStarting,
  326. isFirst,
  327. isLast);
  328. }
  329. }
  330. /**
  331. * Registers the FO's id on the current PageViewport
  332. */
  333. protected void addId() {
  334. if (fobj != null) {
  335. getPSLM().addIDToPage(fobj.getId());
  336. }
  337. }
  338. /**
  339. * Notifies the {@link PageSequenceLayoutManager} that layout
  340. * for this LM has ended.
  341. */
  342. protected void notifyEndOfLayout() {
  343. if (fobj != null) {
  344. getPSLM().notifyEndOfLayout(fobj.getId());
  345. }
  346. }
  347. /** {@inheritDoc} */
  348. public String toString() {
  349. return (super.toString() + (fobj != null ? "[fobj=" + fobj.toString() + "]" : ""));
  350. }
  351. }