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 
18 /* $Id: RtfText.java 1822095 2018-01-24 11:53:32Z ssteiner $ */
19 
20 package org.apache.fop.render.rtf.rtflib.rtfdoc;
21 
22 /*
23  * This file is part of the RTF library of the FOP project, which was originally
24  * created by Bertrand Delacretaz bdelacretaz@codeconsult.ch and by other
25  * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
26  * the FOP project.
27  */
28 
29 import java.io.IOException;
30 import java.io.Writer;
31 
32 import org.apache.fop.apps.FOPException;
33 
34 /**
35  * <p>Model of a text run (a piece of text with attributes) in an RTF document.</p>
36  *
37  * <p>This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch).</p>
38  */
39 
40 public class RtfText extends RtfElement {
41     // char code for non-breakable space
42     private static final int CHAR_NBSP = 160;
43     private static final int CHAR_TAB = 137;
44     private static final int CHAR_NEW_LINE = 141;
45     /* these next two variables are used to encode bold formating in the
46      * raw xml text. Usefull when specific words or phrases are to be bolded
47      * but their placement and length change.  Thus the bold formatting becomes
48      * part of the data.  The same method can be used for implementing other types
49      * of raw text formatting.
50      */
51     private static final int CHAR_BOLD_START = 130;
52     private static final int CHAR_BOLD_END = 131;
53 
54     /** members */
55     private String text;
56     private final RtfAttributes attr;
57 
58 
59     /** RtfText attributes: attribute names are RTF control word names to avoid
60      *  additional mapping */
61     /** constant for bold */
62     public static final String ATTR_BOLD = "b";
63     /** constant for italic */
64     public static final String ATTR_ITALIC = "i";
65     /** constant for underline */
66     public static final String ATTR_UNDERLINE = "ul";
67     /** constant for underline */
68     public static final String ATTR_STRIKETHROUGH = "strike";
69     /** constant for font size */
70     public static final String ATTR_FONT_SIZE = "fs";
71     /** constant for font family */
72     public static final String ATTR_FONT_FAMILY = "f";
73     /** constant for font color */
74     public static final String ATTR_FONT_COLOR = "cf";
75     /** constant for background color */
76     public static final String ATTR_BACKGROUND_COLOR = "chcbpat"; // Added by Boris on 06/25//02
77     /** constant for superscript */
78     public static final String ATTR_SUPERSCRIPT = "super";
79     /** constant for subscript */
80     public static final String ATTR_SUBSCRIPT = "sub";
81 
82     /** RtfText attributes: paragraph shading attributes */
83     /** Constant for the shading of the paragraph */
84     public static final String SHADING = "shading";
85     /** Constant for the document's color tableshading of the paragraph */
86     public static final String SHADING_FRONT_COLOR = "cfpat";
87     /** Constant for the 100% shading of the paragraph */
88     public static final int FULL_SHADING = 10000;
89 
90     /** RtfText attributes: alignment attributes */
91     /** constant for align center */
92     public static final String ALIGN_CENTER = "qc";
93     /** constant for align left */
94     public static final String ALIGN_LEFT = "ql";
95     /** constant for align right */
96     public static final String ALIGN_RIGHT = "qr";
97     /** constant for align justified */
98     public static final String ALIGN_JUSTIFIED = "qj";
99     /** constant for align distributed */
100     public static final String ALIGN_DISTRIBUTED = "qd";
101 
102     /** RtfText attributes: border attributes */
103     //added by Chris Scott
104     /** constant for bottom single border */
105     public static final String BDR_BOTTOM_SINGLE = "brdrb\\brsp40\\brdrs";
106     /** constant for bottom double border */
107     public static final String BDR_BOTTOM_DOUBLE = "brdrb\\brsp40\\brdrdb";
108     /** constant for bottom embossed border */
109     public static final String BDR_BOTTOM_EMBOSS = "brdrb\\brsp40\\brdremboss";
110     /** constant for bottom dotted border */
111     public static final String BDR_BOTTOM_DOTTED = "brdrb\\brsp40\\brdrdot";
112     /** constant for bottom dashed border */
113     public static final String BDR_BOTTOM_DASH = "brdrb\\brsp40\\brdrdash";
114 
115     /** RtfText attributes: fields */
116     //must be carefull of group markings and star control
117     //ie page field:
118     //  "{\field {\*\fldinst {PAGE}} {\fldrslt}}"
119     /** constant for field */
120     public static final String RTF_FIELD = "field";
121     /** constant for field page */
122     public static final String RTF_FIELD_PAGE = "fldinst { PAGE }";
123     /** constant for field result */
124     public static final String RTF_FIELD_RESULT = "fldrslt";
125 
126     /**RtfText attributes: indentation attributes */
127     //added by Chris Scott
128     /** constant for left indent body */
129     public static final String LEFT_INDENT_BODY = "li";
130     /** constant for left indent first */
131     public static final String LEFT_INDENT_FIRST = "fi";
132     /** constant for right indent body */
133     public static final String RIGHT_INDENT_BODY = "ri";
134 
135     /** constant for center tab */
136     public static final String TAB_CENTER = "tqc\\tx";
137     /** constant for right tab */
138     public static final String TAB_RIGHT = "tqr\\tx";
139     /** constant for tab leader dots */
140     public static final String TAB_LEADER_DOTS = "tldot";
141     /** constant for tab leader hyphens */
142     public static final String TAB_LEADER_HYPHEN = "tlhyph";
143     /** constant for tab leader underscores */
144     public static final String TAB_LEADER_UNDER = "tlul";
145     /** constant for tab leader thick */
146     public static final String TAB_LEADER_THICK = "tlth";
147     /** constant for tab leader equals */
148     public static final String TAB_LEADER_EQUALS = "tleq";
149 
150     /** Space before/after a paragraph */
151     //these lines were added by Boris Pouderous
152     public static final String SPACE_BEFORE = "sb";
153     /** Space after a paragraph */
154     public static final String SPACE_AFTER = "sa";
155 
156     /** RtfText attributes: this must contain all allignment attributes names */
157     public static final String[] ALIGNMENT = new String []
158     {
159         ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_JUSTIFIED, ALIGN_DISTRIBUTED
160     };
161 
162     /** RtfText attributes:: this must contain all border attribute names*/
163     //this line added by Chris Scott, Westinghouse
164     public static final String[] BORDER = new String []
165     {
166         BDR_BOTTOM_SINGLE, BDR_BOTTOM_DOUBLE, BDR_BOTTOM_EMBOSS, BDR_BOTTOM_DOTTED,
167         BDR_BOTTOM_DASH
168     };
169 
170     /** String array of indent constants */
171     public static final String[] INDENT = new String []
172     {
173         LEFT_INDENT_BODY, LEFT_INDENT_FIRST
174     };
175 
176     /** String array of tab constants */
177     public static final String[] TABS = new String []
178     {
179         TAB_CENTER, TAB_RIGHT, TAB_LEADER_DOTS, TAB_LEADER_HYPHEN, TAB_LEADER_UNDER,
180         TAB_LEADER_THICK, TAB_LEADER_EQUALS
181     };
182 
183 
184     /** RtfText attributes: this must contain all attribute names */
185     public static final String [] ATTR_NAMES = {
186         ATTR_BOLD,
187         ATTR_ITALIC,
188         ATTR_UNDERLINE,
189         ATTR_FONT_SIZE,
190         ATTR_FONT_FAMILY,
191         ATTR_FONT_COLOR,
192         ATTR_BACKGROUND_COLOR
193     };
194 
195     /** Create an RtfText in given IRtfTextContainer.
196      *  @param str optional initial text content
197      */
RtfText(IRtfTextContainer parent, Writer w, String str, RtfAttributes attr)198     RtfText(IRtfTextContainer parent, Writer w, String str, RtfAttributes attr)
199            throws IOException {
200         super((RtfContainer)parent, w);
201         this.text = str;
202         this.attr = attr;
203     }
204 
205     /**
206      * Write our text to the RTF stream
207      * @throws IOException for I/O problems
208      */
writeRtfContent()209     public void writeRtfContent() throws IOException {
210         writeChars: {
211 
212             //these lines were added by Boris Pouderous
213             if (attr != null) {
214                 writeAttributes(attr, new String[] {RtfText.SPACE_BEFORE});
215                 writeAttributes(attr, new String[] {RtfText.SPACE_AFTER});
216             }
217 
218             if (isTab()) {
219                 writeControlWord("tab");
220             } else if (isNewLine()) {
221                 break writeChars;
222             } else if (isBold(true)) {
223                 writeControlWord("b");
224             } else if (isBold(false)) {
225                 writeControlWord("b0");
226             // TODO not optimal, consecutive RtfText with same attributes
227             // could be written without group marks
228             } else {
229                 writeGroupMark(true);
230                 if (attr != null && mustWriteAttributes()) {
231                     writeAttributes(attr, RtfText.ATTR_NAMES);
232                 }
233                 RtfStringConverter.getInstance().writeRtfString(writer, text);
234                 writeGroupMark(false);
235             }
236         }
237     }
238 
239     /** true if our text attributes must be written */
mustWriteAttributes()240     private boolean mustWriteAttributes() {
241         return !isEmpty() && !isNbsp();
242     }
243 
244     /** IRtfTextContainer requirement:
245      * @return a copy of our attributes
246      * @throws FOPException if attributes cannot be cloned
247      */
getTextContainerAttributes()248     public RtfAttributes getTextContainerAttributes() throws FOPException {
249         if (attrib == null) {
250             return null;
251         }
252         try {
253             return (RtfAttributes)this.attrib.clone();
254         } catch (CloneNotSupportedException e) {
255             throw new FOPException(e);
256         }
257     }
258 
259     /** direct access to our text */
getText()260     String getText() {
261         return text;
262     }
263 
264     /** direct access to our text */
setText(String str)265     void setText(String str) {
266         text = str;
267     }
268 
269     /**
270      * Checks whether the text is empty.
271      *
272      * @return true    If m_text is null\n
273      *         false   m_text is set
274      */
isEmpty()275     public boolean isEmpty() {
276         return text == null || text.trim().length() == 0;
277     }
278 
279     /**
280      *  True if text contains a single non-breaking space (#160).
281      *  TODO make this more general and/or merge with isEmpty? -- what happen
282      *       with empty paragraphs, if they will be removed, than NO, else ok
283      *
284      * @return true    If m_text is character 160\n
285      *         false   m_text is not a nbsp
286      */
isNbsp()287     public boolean isNbsp() {
288         if (!isEmpty()) {
289             if (text.trim().length() == 1 && text.charAt(0) == CHAR_NBSP) {
290                 return true;
291             }
292         }
293         return false;
294     }
295 
296     /**
297      * @return true if the text is a tab character
298      */
isTab()299     public boolean isTab() {
300         return (text.trim().length() == 1 && text.charAt(0) == CHAR_TAB);
301     }
302 
303     /**
304      * @return true if text is a newline character
305      */
isNewLine()306     public boolean isNewLine() {
307         return (text.trim().length() == 1 && text.charAt(0) == CHAR_NEW_LINE);
308     }
309 
310     /**
311      * @param isStart set to true if processing the start of the text (??)
312      * @return true if text is bold
313      */
isBold(boolean isStart)314     public boolean isBold(boolean isStart) {
315         if (isStart) {
316             return (text.trim().length() == 1 && text.charAt(0) == CHAR_BOLD_START);
317         } else {
318             return (text.trim().length() == 1 && text.charAt(0) == CHAR_BOLD_END);
319         }
320     }
321 
322     /** @return the attributes of our text */
getTextAttributes()323     public RtfAttributes getTextAttributes() {
324         return attr;
325     }
326 }
327