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.

AbstractLayoutManager.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * Copyright 1999-2005 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.layoutmgr;
  18. import org.apache.fop.fo.FObj;
  19. import org.apache.fop.fo.FONode;
  20. import org.apache.fop.area.Area;
  21. import org.apache.fop.area.Resolvable;
  22. import org.apache.fop.area.PageViewport;
  23. import org.apache.fop.fo.Constants;
  24. import org.apache.fop.fo.flow.RetrieveMarker;
  25. import org.apache.fop.fo.flow.Marker;
  26. import org.apache.commons.logging.Log;
  27. import org.apache.commons.logging.LogFactory;
  28. import java.util.LinkedList;
  29. import java.util.List;
  30. import java.util.ArrayList;
  31. import java.util.ListIterator;
  32. import java.util.Map;
  33. /**
  34. * The base class for all LayoutManagers.
  35. */
  36. public abstract class AbstractLayoutManager implements LayoutManager, Constants {
  37. protected LayoutManager parentLM = null;
  38. protected List childLMs = null;
  39. protected ListIterator fobjIter = null;
  40. protected Map markers = null;
  41. /** True if this LayoutManager has handled all of its content. */
  42. private boolean bFinished = false;
  43. protected boolean bInited = false;
  44. /**
  45. * Used during addAreas(): signals that a BreakPoss is not generating areas
  46. * and therefore doesn't add IDs and markers to the current page.
  47. * @see org.apache.fop.layoutmgr.AbstractLayoutManager#isBogus
  48. */
  49. protected boolean bBogus = false;
  50. /** child LM and child LM iterator during getNextBreakPoss phase */
  51. protected LayoutManager curChildLM = null;
  52. protected ListIterator childLMiter = null;
  53. /**
  54. * logging instance
  55. */
  56. protected static Log log = LogFactory.getLog(LayoutManager.class);
  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. if (fo == null) {
  69. throw new IllegalStateException("Null formatting object found.");
  70. }
  71. setFObj(fo);
  72. }
  73. /**
  74. * Set the FO object for this layout manager
  75. *
  76. * @param fo the formatting object for this layout manager
  77. */
  78. public void setFObj(FObj fo) {
  79. markers = fo.getMarkers();
  80. fobjIter = fo.getChildNodes();
  81. childLMiter = new LMiter(this);
  82. }
  83. /**
  84. * This method provides a hook for a LayoutManager to initialize traits
  85. * for the areas it will create, based on Properties set on its FO.
  86. */
  87. public void initialize() {
  88. if (bInited == false) {
  89. initProperties();
  90. bInited = true;
  91. }
  92. }
  93. /**
  94. * This method is called by initialize() to set any method variables
  95. * based on Properties set on its FO.
  96. */
  97. protected void initProperties() {
  98. }
  99. public void setParent(LayoutManager lm) {
  100. this.parentLM = lm;
  101. }
  102. public LayoutManager getParent() {
  103. return this.parentLM;
  104. }
  105. // /**
  106. // * Ask the parent LayoutManager to add the current (full) area to the
  107. // * appropriate parent area.
  108. // * @param bFinished If true, this area is finished, either because it's
  109. // * completely full or because there is no more content to put in it.
  110. // * If false, we are in the middle of this area. This can happen,
  111. // * for example, if we find floats in a line. We stop the current area,
  112. // * and add it (temporarily) to its parent so that we can see if there
  113. // * is enough space to place the float(s) anchored in the line.
  114. // */
  115. // protected void flush(Area area, boolean bFinished) {
  116. // if (area != null) {
  117. // // area.setFinished(true);
  118. // parentLM.addChildArea(area, bFinished); // ????
  119. // if (bFinished) {
  120. // setCurrentArea(null);
  121. // }
  122. // }
  123. // }
  124. /**
  125. * Return an Area which can contain the passed childArea. The childArea
  126. * may not yet have any content, but it has essential traits set.
  127. * In general, if the LayoutManager already has an Area it simply returns
  128. * it. Otherwise, it makes a new Area of the appropriate class.
  129. * It gets a parent area for its area by calling its parent LM.
  130. * Finally, based on the dimensions of the parent area, it initializes
  131. * its own area. This includes setting the content IPD and the maximum
  132. * BPD.
  133. */
  134. /** @see org.apache.fop.layoutmgr.LayoutManager#generatesInlineAreas() */
  135. public boolean generatesInlineAreas() {
  136. return false;
  137. }
  138. /** @see org.apache.fop.layoutmgr.LayoutManager#isBogus() */
  139. public boolean isBogus() {
  140. if (getParent().isBogus()) {
  141. return true;
  142. } else {
  143. return bBogus;
  144. }
  145. }
  146. /**
  147. * Add a child area to the current area. If this causes the maximum
  148. * dimension of the current area to be exceeded, the parent LM is called
  149. * to add it.
  150. */
  151. /**
  152. * Return currently active child LayoutManager or null if
  153. * all children have finished layout.
  154. * Note: child must implement LayoutManager! If it doesn't, skip it
  155. * and print a warning.
  156. */
  157. protected LayoutManager getChildLM() {
  158. if (curChildLM != null && !curChildLM.isFinished()) {
  159. return curChildLM;
  160. }
  161. while (childLMiter.hasNext()) {
  162. curChildLM = (LayoutManager) childLMiter.next();
  163. return curChildLM;
  164. }
  165. return null;
  166. }
  167. protected boolean hasMoreLM(LayoutManager prevLM) {
  168. // prevLM should = curChildLM
  169. if (prevLM != curChildLM) {
  170. //log.debug("AbstractLayoutManager.peekNextLM: " +
  171. // "passed LM is not current child LM!");
  172. return false;
  173. }
  174. return !childLMiter.hasNext();
  175. }
  176. /**
  177. * Reset the layoutmanager "iterator" so that it will start
  178. * with the passed Position's generating LM
  179. * on the next call to getChildLM.
  180. * @param pos a Position returned by a child layout manager
  181. * representing a potential break decision.
  182. * If pos is null, then back up to the first child LM.
  183. */
  184. protected void reset(org.apache.fop.layoutmgr.Position pos) {
  185. //if (lm == null) return;
  186. LayoutManager lm = (pos != null) ? pos.getLM() : null;
  187. if (curChildLM != lm) {
  188. // ASSERT curChildLM == (LayoutManager)childLMiter.previous()
  189. if (childLMiter.hasPrevious() && curChildLM
  190. != (LayoutManager) childLMiter.previous()) {
  191. //log.error("LMiter problem!");
  192. }
  193. while (curChildLM != lm && childLMiter.hasPrevious()) {
  194. curChildLM.resetPosition(null);
  195. curChildLM = (LayoutManager) childLMiter.previous();
  196. }
  197. // Otherwise next returns same object
  198. childLMiter.next();
  199. }
  200. if (curChildLM != null) {
  201. curChildLM.resetPosition(pos);
  202. }
  203. if (isFinished()) {
  204. setFinished(false);
  205. }
  206. }
  207. public void resetPosition(Position resetPos) {
  208. // if (resetPos == null) {
  209. // reset(null);
  210. // }
  211. }
  212. /**
  213. * Tell whether this LayoutManager has handled all of its content.
  214. * @return True if there are no more break possibilities,
  215. * ie. the last one returned represents the end of the content.
  216. */
  217. public boolean isFinished() {
  218. return bFinished;
  219. }
  220. public void setFinished(boolean fin) {
  221. bFinished = fin;
  222. }
  223. /**
  224. * Generate and return the next break possibility.
  225. * Each layout manager must implement this.
  226. * TODO: should this be abstract or is there some reasonable
  227. * default implementation?
  228. */
  229. public BreakPoss getNextBreakPoss(LayoutContext context) {
  230. return null;
  231. }
  232. /**
  233. * Return value indicating whether the next area to be generated could
  234. * start a new line or flow area.
  235. * In general, if can't break at the current level, delegate to
  236. * the first child LM.
  237. * NOTE: should only be called if the START_AREA flag is set in context,
  238. * since the previous sibling LM must have returned a BreakPoss which
  239. * does not allow break-after.
  240. * QUESTION: in block-stacked areas, does this mean some kind of keep
  241. * condition, or is it only used for inline-stacked areas?
  242. * Default implementation always returns true.
  243. */
  244. public boolean canBreakBefore(LayoutContext context) {
  245. return true;
  246. }
  247. /**
  248. * @see org.apache.fop.layoutmgr.LayoutManager#addAreas(org.apache.fop.layoutmgr.PositionIterator, org.apache.fop.layoutmgr.LayoutContext)
  249. */
  250. public void addAreas(PositionIterator posIter, LayoutContext context) {
  251. }
  252. public void getWordChars(StringBuffer sbChars, Position bp1,
  253. Position bp2) {
  254. }
  255. /* ---------------------------------------------------------
  256. * PROVIDE NULL IMPLEMENTATIONS OF METHODS from LayoutManager
  257. * interface which are declared abstract in AbstractLayoutManager.
  258. * ---------------------------------------------------------*/
  259. public LinkedList getNextKnuthElements(LayoutContext context,
  260. int alignment) {
  261. log.warn("null implementation of getNextKnuthElements() called!");
  262. setFinished(true);
  263. return null;
  264. }
  265. public KnuthElement addALetterSpaceTo(KnuthElement element) {
  266. log.warn("null implementation of addALetterSpaceTo() called!");
  267. return element;
  268. }
  269. public void getWordChars(StringBuffer sbChars, Position pos) {
  270. log.warn("null implementation of getWordChars() called!");
  271. }
  272. public void hyphenate(Position pos, HyphContext hc) {
  273. log.warn("null implementation of hyphenate called!");
  274. }
  275. public boolean applyChanges(List oldList) {
  276. log.warn("null implementation of applyChanges() called!");
  277. return false;
  278. }
  279. public LinkedList getChangedKnuthElements(List oldList,
  280. /*int flaggedPenalty,*/
  281. int alignment) {
  282. log.warn("null implementation of getChangeKnuthElement() called!");
  283. return null;
  284. }
  285. public int getWordSpaceIPD() {
  286. log.warn("null implementation of getWordSpaceIPD() called!");
  287. return 0;
  288. }
  289. /**
  290. * @see org.apache.fop.layoutmgr.LayoutManager#getParentArea(org.apache.fop.area.Area)
  291. */
  292. public Area getParentArea(Area childArea) {
  293. return null;
  294. }
  295. public void addChildArea(Area childArea) {
  296. }
  297. /**
  298. * Delegate getting the current page viewport to the parent layout manager.
  299. *
  300. * @see org.apache.fop.layoutmgr.LayoutManager
  301. */
  302. public PageViewport getCurrentPV() {
  303. return parentLM.getCurrentPV();
  304. }
  305. /**
  306. * Delegate resolving the id reference to the parent layout manager.
  307. *
  308. * @see org.apache.fop.layoutmgr.LayoutManager
  309. */
  310. public PageViewport resolveRefID(String ref) {
  311. return parentLM.resolveRefID(ref);
  312. }
  313. /**
  314. * Add the id to the page.
  315. * If the id string is not null then add the id to the current page.
  316. */
  317. protected void addID(String foID) {
  318. if (foID != null && foID.length() > 0) {
  319. addIDToPage(foID);
  320. }
  321. }
  322. /**
  323. * Delegate adding id reference to the parent layout manager.
  324. *
  325. * @see org.apache.fop.layoutmgr.LayoutManager
  326. */
  327. public void addIDToPage(String id) {
  328. parentLM.addIDToPage(id);
  329. }
  330. /**
  331. * Delegate adding unresolved area to the parent layout manager.
  332. *
  333. * @see org.apache.fop.layoutmgr.LayoutManager
  334. */
  335. public void addUnresolvedArea(String id, Resolvable res) {
  336. parentLM.addUnresolvedArea(id, res);
  337. }
  338. /**
  339. * Delegate retrieve marker to the parent layout manager.
  340. *
  341. * @see org.apache.fop.layoutmgr.LayoutManager
  342. */
  343. public Marker retrieveMarker(String name, int pos, int boundary) {
  344. return parentLM.retrieveMarker(name, pos, boundary);
  345. }
  346. /**
  347. * Delegate getLayoutManagerMaker to the parent layout manager.
  348. *
  349. * @see org.apache.fop.layoutmgr.LayoutManager
  350. * @return the LayoutManagerMaker object.
  351. */
  352. public LayoutManagerMaker getLayoutManagerMaker() {
  353. return parentLM.getLayoutManagerMaker();
  354. }
  355. /**
  356. * Handles retrieve-marker nodes as they occur.
  357. * @param foNode FO node to check
  358. * @return the original foNode or in case of a retrieve-marker the replaced
  359. * FO node. null if the the replacement results in no nodes to be
  360. * processed.
  361. */
  362. private FONode handleRetrieveMarker(FONode foNode) {
  363. if (foNode instanceof RetrieveMarker) {
  364. RetrieveMarker rm = (RetrieveMarker) foNode;
  365. Marker marker = retrieveMarker(rm.getRetrieveClassName(),
  366. rm.getRetrievePosition(),
  367. rm.getRetrieveBoundary());
  368. if (marker == null) {
  369. return null;
  370. }
  371. rm.bindMarker(marker);
  372. return rm;
  373. } else {
  374. return foNode;
  375. }
  376. }
  377. /**
  378. * Convenience method: preload a number of child LMs
  379. * @param size the requested number of child LMs
  380. * @return the list with the preloaded child LMs
  381. */
  382. protected List preLoadList(int size) {
  383. if (fobjIter == null) {
  384. return null;
  385. }
  386. List newLMs = new ArrayList(size);
  387. while (fobjIter.hasNext() && newLMs.size() < size ) {
  388. Object theobj = fobjIter.next();
  389. if (theobj instanceof FONode) {
  390. FONode foNode = (FONode) theobj;
  391. foNode = handleRetrieveMarker(foNode);
  392. if (foNode != null) {
  393. getLayoutManagerMaker().
  394. makeLayoutManagers(foNode, newLMs);
  395. }
  396. }
  397. }
  398. return newLMs;
  399. }
  400. /**
  401. * @see org.apache.fop.layoutmgr.LayoutManager#preLoadNext
  402. */
  403. public boolean preLoadNext(int pos) {
  404. List newLMs = preLoadList(pos + 1 - childLMs.size());
  405. addChildLMs(newLMs);
  406. return pos < childLMs.size();
  407. }
  408. /**
  409. * @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs
  410. */
  411. public List getChildLMs() {
  412. if (childLMs == null) {
  413. childLMs = new java.util.ArrayList(10);
  414. }
  415. return childLMs;
  416. }
  417. /**
  418. * @see org.apache.fop.layoutmgr.LayoutManager#addChildLM
  419. */
  420. public void addChildLM(LayoutManager lm) {
  421. if (lm == null) {
  422. return;
  423. }
  424. lm.setParent(this);
  425. lm.initialize();
  426. if (childLMs == null) {
  427. childLMs = new java.util.ArrayList(10);
  428. }
  429. childLMs.add(lm);
  430. log.trace(this.getClass().getName()
  431. + ": Adding child LM " + lm.getClass().getName());
  432. }
  433. /**
  434. * @see org.apache.fop.layoutmgr.LayoutManager#addChildLMs
  435. */
  436. public void addChildLMs(List newLMs) {
  437. if (newLMs == null || newLMs.size() == 0) {
  438. return;
  439. }
  440. ListIterator iter = newLMs.listIterator();
  441. while (iter.hasNext()) {
  442. LayoutManager lm = (LayoutManager) iter.next();
  443. addChildLM(lm);
  444. }
  445. }
  446. }