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.

RtfTextrun.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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.render.rtf.rtflib.rtfdoc;
  19. // Java
  20. import java.io.IOException;
  21. import java.io.Writer;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.ListIterator;
  25. // FOP
  26. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic;
  27. /**
  28. * Class which contains a linear text run. It has methods to add attributes,
  29. * text, paragraph breaks....
  30. * @author Peter Herweg, pherweg@web.de
  31. */
  32. public class RtfTextrun extends RtfContainer {
  33. private boolean bSuppressLastPar = false;
  34. private RtfListItem rtfListItem;
  35. /** Manager for handling space-* property. */
  36. private RtfSpaceManager rtfSpaceManager = new RtfSpaceManager();
  37. /** Class which represents the opening of a RTF group mark.*/
  38. private class RtfOpenGroupMark extends RtfElement {
  39. RtfOpenGroupMark(RtfContainer parent, Writer w, RtfAttributes attr)
  40. throws IOException {
  41. super(parent, w, attr);
  42. }
  43. /**
  44. * @return true if this element would generate no "useful" RTF content
  45. */
  46. public boolean isEmpty() {
  47. return false;
  48. }
  49. /**
  50. * write RTF code of all our children
  51. * @throws IOException for I/O problems
  52. */
  53. protected void writeRtfContent() throws IOException {
  54. writeGroupMark(true);
  55. writeAttributes(getRtfAttributes(), null);
  56. }
  57. }
  58. /** Class which represents the closing of a RTF group mark.*/
  59. private class RtfCloseGroupMark extends RtfElement {
  60. RtfCloseGroupMark(RtfContainer parent, Writer w)
  61. throws IOException {
  62. super(parent, w);
  63. }
  64. /**
  65. * @return true if this element would generate no "useful" RTF content
  66. */
  67. public boolean isEmpty() {
  68. return false;
  69. }
  70. /**
  71. * write RTF code of all our children
  72. * @throws IOException for I/O problems
  73. */
  74. protected void writeRtfContent() throws IOException {
  75. writeGroupMark(false);
  76. }
  77. }
  78. /** Class which represents a paragraph break.*/
  79. private class RtfParagraphBreak extends RtfElement {
  80. RtfParagraphBreak(RtfContainer parent, Writer w)
  81. throws IOException {
  82. super(parent, w);
  83. }
  84. /**
  85. * @return true if this element would generate no "useful" RTF content
  86. */
  87. public boolean isEmpty() {
  88. return false;
  89. }
  90. /**
  91. * write RTF code of all our children
  92. * @throws IOException for I/O problems
  93. */
  94. protected void writeRtfContent() throws IOException {
  95. writeControlWord("par");
  96. }
  97. }
  98. /** Create an RTF container as a child of given container */
  99. RtfTextrun(RtfContainer parent, Writer w, RtfAttributes attrs) throws IOException {
  100. super(parent, w, attrs);
  101. }
  102. /**
  103. * Adds instance of <code>OpenGroupMark</code> as a child with attributes.
  104. *
  105. * @param attrs attributes to add
  106. * @throws IOException for I/O problems
  107. */
  108. private void addOpenGroupMark(RtfAttributes attrs) throws IOException {
  109. RtfOpenGroupMark r = new RtfOpenGroupMark(this, writer, attrs);
  110. }
  111. /**
  112. * Adds instance of <code>CloseGroupMark</code> as a child.
  113. *
  114. * @throws IOException for I/O problems
  115. */
  116. private void addCloseGroupMark() throws IOException {
  117. RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer);
  118. }
  119. /**
  120. * Pushes block attributes, notifies all opened blocks about pushing block
  121. * attributes, adds <code>OpenGroupMark</code> as a child.
  122. *
  123. * @param attrs the block attributes to push
  124. * @throws IOException for I/O problems
  125. */
  126. public void pushBlockAttributes(RtfAttributes attrs) throws IOException {
  127. rtfSpaceManager.stopUpdatingSpaceBefore();
  128. RtfSpaceSplitter splitter = rtfSpaceManager.pushRtfSpaceSplitter(attrs);
  129. addOpenGroupMark(splitter.getCommonAttributes());
  130. }
  131. /**
  132. * Pops block attributes, notifies all opened blocks about pushing block
  133. * attributes, adds <code>CloseGroupMark</code> as a child.
  134. *
  135. * @throws IOException for I/O problems
  136. */
  137. public void popBlockAttributes() throws IOException {
  138. rtfSpaceManager.popRtfSpaceSplitter();
  139. rtfSpaceManager.stopUpdatingSpaceBefore();
  140. addCloseGroupMark();
  141. }
  142. /**
  143. * Pushes inline attributes.
  144. *
  145. * @param attrs the inline attributes to push
  146. * @throws IOException for I/O problems
  147. */
  148. public void pushInlineAttributes(RtfAttributes attrs) throws IOException {
  149. rtfSpaceManager.pushInlineAttributes(attrs);
  150. addOpenGroupMark(attrs);
  151. }
  152. /**
  153. * Inserts a page number citation.
  154. * @param refId the identifier being referenced
  155. * @throws IOException for I/O problems
  156. */
  157. public void addPageNumberCitation(String refId) throws IOException {
  158. RtfPageNumberCitation r = new RtfPageNumberCitation(this, writer, refId);
  159. }
  160. /**
  161. * Pop inline attributes.
  162. *
  163. * @throws IOException for I/O problems
  164. */
  165. public void popInlineAttributes() throws IOException {
  166. rtfSpaceManager.popInlineAttributes();
  167. addCloseGroupMark();
  168. }
  169. /**
  170. * Add string to children list.
  171. *
  172. * @param s string to add
  173. * @throws IOException for I/O problems
  174. */
  175. public void addString(String s) throws IOException {
  176. if (s.equals("")) {
  177. return;
  178. }
  179. RtfAttributes attrs = rtfSpaceManager.getLastInlineAttribute();
  180. //add RtfSpaceSplitter to inherit accumulated space
  181. rtfSpaceManager.pushRtfSpaceSplitter(attrs);
  182. rtfSpaceManager.setCandidate(attrs);
  183. RtfString r = new RtfString(this, writer, s);
  184. rtfSpaceManager.popRtfSpaceSplitter();
  185. }
  186. /**
  187. * Inserts a footnote.
  188. *
  189. * @return inserted footnote
  190. * @throws IOException for I/O problems
  191. */
  192. public RtfFootnote addFootnote() throws IOException {
  193. return new RtfFootnote(this, writer);
  194. }
  195. /**
  196. * Inserts paragraph break before all close group marks.
  197. *
  198. * @throws IOException for I/O problems
  199. */
  200. public void addParagraphBreak() throws IOException {
  201. // get copy of children list
  202. List children = getChildren();
  203. // delete all previous CloseGroupMark
  204. int deletedCloseGroupCount = 0;
  205. ListIterator lit = children.listIterator(children.size());
  206. while (lit.hasPrevious()
  207. && (lit.previous() instanceof RtfCloseGroupMark)) {
  208. lit.remove();
  209. deletedCloseGroupCount++;
  210. }
  211. if (children.size() != 0) {
  212. // add paragraph break and restore all deleted close group marks
  213. setChildren(children);
  214. new RtfParagraphBreak(this, writer);
  215. for (int i = 0; i < deletedCloseGroupCount; i++) {
  216. addCloseGroupMark();
  217. }
  218. }
  219. }
  220. /**
  221. * Inserts a leader.
  222. * @param attrs Attributes for the leader
  223. * @throws IOException for I/O problems
  224. */
  225. public void addLeader(RtfAttributes attrs) throws IOException {
  226. new RtfLeader(this, writer, attrs);
  227. }
  228. /**
  229. * Inserts a page number.
  230. * @param attr Attributes for the page number to insert.
  231. * @throws IOException for I/O problems
  232. */
  233. public void addPageNumber(RtfAttributes attr) throws IOException {
  234. RtfPageNumber r = new RtfPageNumber(this, writer, attr);
  235. }
  236. /**
  237. * Inserts a hyperlink.
  238. * @param attr Attributes for the hyperlink to insert.
  239. * @return inserted hyperlink
  240. * @throws IOException for I/O problems
  241. */
  242. public RtfHyperLink addHyperlink(RtfAttributes attr) throws IOException {
  243. return new RtfHyperLink(this, writer, attr);
  244. }
  245. /**
  246. * Inserts a bookmark.
  247. * @param id Id for the inserted bookmark
  248. * @throws IOException for I/O problems
  249. */
  250. public void addBookmark(String id) throws IOException {
  251. if (id != "") {
  252. // if id is not empty, add boormark
  253. new RtfBookmark(this, writer, id);
  254. }
  255. }
  256. /**
  257. * Inserts an image.
  258. * @return inserted image
  259. * @throws IOException for I/O problems
  260. */
  261. public RtfExternalGraphic newImage() throws IOException {
  262. return new RtfExternalGraphic(this, writer);
  263. }
  264. /**
  265. * Adds a new RtfTextrun to the given container if necessary, and returns it.
  266. * @param container RtfContainer, which is the parent of the returned RtfTextrun
  267. * @param writer Writer of the given RtfContainer
  268. * @param attrs RtfAttributes which are to write at the beginning of the RtfTextrun
  269. * @return new or existing RtfTextrun object.
  270. * @throws IOException for I/O problems
  271. */
  272. public static RtfTextrun getTextrun(RtfContainer container, Writer writer, RtfAttributes attrs)
  273. throws IOException {
  274. List list = container.getChildren();
  275. if (list.size() == 0) {
  276. //add a new RtfTextrun
  277. RtfTextrun textrun = new RtfTextrun(container, writer, attrs);
  278. list.add(textrun);
  279. return textrun;
  280. }
  281. Object obj = list.get(list.size() - 1);
  282. if (obj instanceof RtfTextrun) {
  283. //if the last child is a RtfTextrun, return it
  284. return (RtfTextrun) obj;
  285. }
  286. //add a new RtfTextrun as the last child
  287. RtfTextrun textrun = new RtfTextrun(container, writer, attrs);
  288. list.add(textrun);
  289. return textrun;
  290. }
  291. /**
  292. * specify, if the last paragraph control word (\par) should be suppressed.
  293. * @param bSuppress true, if the last \par should be suppressed
  294. */
  295. public void setSuppressLastPar(boolean bSuppress) {
  296. bSuppressLastPar = bSuppress;
  297. }
  298. /**
  299. * write RTF code of all our children
  300. * @throws IOException for I/O problems
  301. */
  302. protected void writeRtfContent() throws IOException {
  303. /**
  304. *TODO: The textrun's children are iterated twice:
  305. * 1. To determine the last RtfParagraphBreak
  306. * 2. To write the children
  307. * Maybe this can be done more efficient.
  308. */
  309. boolean bHasTableCellParent =
  310. this.getParentOfClass(RtfTableCell.class) != null;
  311. RtfAttributes attrBlockLevel = new RtfAttributes();
  312. //determine, if this RtfTextrun is the last child of its parent
  313. boolean bLast = false;
  314. for (Iterator it = parent.getChildren().iterator(); it.hasNext();) {
  315. if (it.next() == this) {
  316. bLast = !it.hasNext();
  317. break;
  318. }
  319. }
  320. //get last RtfParagraphBreak, which is not followed by any visible child
  321. RtfParagraphBreak lastParagraphBreak = null;
  322. if (bLast) {
  323. for (Iterator it = getChildren().iterator(); it.hasNext();) {
  324. final RtfElement e = (RtfElement)it.next();
  325. if (e instanceof RtfParagraphBreak) {
  326. lastParagraphBreak = (RtfParagraphBreak)e;
  327. } else {
  328. if (!(e instanceof RtfOpenGroupMark)
  329. && !(e instanceof RtfCloseGroupMark)
  330. && e.isEmpty()) {
  331. lastParagraphBreak = null;
  332. }
  333. }
  334. }
  335. }
  336. //may contain for example \intbl
  337. writeAttributes(attrib, null);
  338. if (rtfListItem != null) {
  339. rtfListItem.getRtfListStyle().writeParagraphPrefix(this);
  340. }
  341. //write all children
  342. boolean bPrevPar = false;
  343. boolean bFirst = true;
  344. for (Iterator it = getChildren().iterator(); it.hasNext();) {
  345. final RtfElement e = (RtfElement)it.next();
  346. final boolean bRtfParagraphBreak = (e instanceof RtfParagraphBreak);
  347. if (bHasTableCellParent) {
  348. attrBlockLevel.set(e.getRtfAttributes());
  349. }
  350. /**
  351. * -Write RtfParagraphBreak only, if the previous visible child
  352. * was't also a RtfParagraphBreak.
  353. * -Write RtfParagraphBreak only, if it is not the first visible
  354. * child.
  355. * -If the RtfTextrun is the last child of its parent, write a
  356. * RtfParagraphBreak only, if it is not the last child.
  357. */
  358. boolean bHide = false;
  359. bHide = bRtfParagraphBreak;
  360. bHide = bHide
  361. && (bPrevPar
  362. || bFirst
  363. || (bSuppressLastPar && bLast && lastParagraphBreak != null
  364. && e == lastParagraphBreak));
  365. if (!bHide) {
  366. newLine();
  367. e.writeRtf();
  368. if (rtfListItem != null && e instanceof RtfParagraphBreak) {
  369. rtfListItem.getRtfListStyle().writeParagraphPrefix(this);
  370. }
  371. }
  372. if (e instanceof RtfParagraphBreak) {
  373. bPrevPar = true;
  374. } else if (e instanceof RtfCloseGroupMark) {
  375. //do nothing
  376. } else if (e instanceof RtfOpenGroupMark) {
  377. //do nothing
  378. } else {
  379. bPrevPar = bPrevPar && e.isEmpty();
  380. bFirst = bFirst && e.isEmpty();
  381. }
  382. } //for (Iterator it = ...)
  383. //
  384. if (bHasTableCellParent) {
  385. writeAttributes(attrBlockLevel, null);
  386. }
  387. }
  388. /**
  389. * Set the parent list-item of the textrun.
  390. *
  391. * @param listItem parent list-item of the textrun
  392. */
  393. public void setRtfListItem(RtfListItem listItem) {
  394. rtfListItem = listItem;
  395. }
  396. /**
  397. * Gets the parent list-item of the textrun.
  398. *
  399. * @return parent list-item of the textrun
  400. */
  401. public RtfListItem getRtfListItem() {
  402. return rtfListItem;
  403. }
  404. }