001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hslf.usermodel;
019:
020: import org.apache.poi.hslf.model.*;
021: import org.apache.poi.hslf.model.Shape;
022: import org.apache.poi.hslf.model.textproperties.*;
023: import org.apache.poi.hslf.record.ColorSchemeAtom;
024: import org.apache.poi.hslf.exceptions.HSLFException;
025:
026: import java.awt.*;
027:
028: /**
029: * Represents a run of text, all with the same style
030: *
031: * TODO: get access to the font/character properties
032: *
033: * @author Nick Burch
034: */
035:
036: public class RichTextRun {
037: /** The TextRun we belong to */
038: private TextRun parentRun;
039: /** The SlideShow we belong to */
040: private SlideShow slideShow;
041:
042: /** Where in the parent TextRun we start from */
043: private int startPos;
044:
045: /** How long a string (in the parent TextRun) we represent */
046: private int length;
047:
048: private String _fontname;
049: /**
050: * Our paragraph and character style.
051: * Note - we may share these styles with other RichTextRuns
052: */
053: private TextPropCollection paragraphStyle;
054: private TextPropCollection characterStyle;
055: private boolean sharingParagraphStyle;
056: private boolean sharingCharacterStyle;
057:
058: /**
059: * Create a new wrapper around a (currently not)
060: * rich text string
061: * @param parent
062: * @param startAt
063: * @param len
064: */
065: public RichTextRun(TextRun parent, int startAt, int len) {
066: this (parent, startAt, len, null, null, false, false);
067: }
068:
069: /**
070: * Create a new wrapper around a rich text string
071: * @param parent The parent TextRun
072: * @param startAt The start position of this run
073: * @param len The length of this run
074: * @param pStyle The paragraph style property collection
075: * @param cStyle The character style property collection
076: * @param pShared The paragraph styles are shared with other runs
077: * @param cShared The character styles are shared with other runs
078: */
079: public RichTextRun(TextRun parent, int startAt, int len,
080: TextPropCollection pStyle, TextPropCollection cStyle,
081: boolean pShared, boolean cShared) {
082: parentRun = parent;
083: startPos = startAt;
084: length = len;
085: paragraphStyle = pStyle;
086: characterStyle = cStyle;
087: sharingParagraphStyle = pShared;
088: sharingCharacterStyle = cShared;
089: }
090:
091: /**
092: * Supply (normally default) textprops, and if they're shared,
093: * when a run gets them
094: */
095: public void supplyTextProps(TextPropCollection pStyle,
096: TextPropCollection cStyle, boolean pShared, boolean cShared) {
097: if (paragraphStyle != null || characterStyle != null) {
098: throw new IllegalStateException(
099: "Can't call supplyTextProps if run already has some");
100: }
101: paragraphStyle = pStyle;
102: characterStyle = cStyle;
103: sharingParagraphStyle = pShared;
104: sharingCharacterStyle = cShared;
105: }
106:
107: /**
108: * Supply the SlideShow we belong to
109: */
110: public void supplySlideShow(SlideShow ss) {
111: slideShow = ss;
112: if (_fontname != null) {
113: setFontName(_fontname);
114: _fontname = null;
115: }
116: }
117:
118: /**
119: * Get the length of the text
120: */
121: public int getLength() {
122: return length;
123: }
124:
125: /**
126: * Fetch the text, in output suitable form
127: */
128: public String getText() {
129: return parentRun.getText().substring(startPos,
130: startPos + length);
131: }
132:
133: /**
134: * Fetch the text, in raw storage form
135: */
136: public String getRawText() {
137: return parentRun.getRawText().substring(startPos,
138: startPos + length);
139: }
140:
141: /**
142: * Change the text
143: */
144: public void setText(String text) {
145: length = text.length();
146: parentRun.changeTextInRichTextRun(this , text);
147: }
148:
149: /**
150: * Tells the RichTextRun its new position in the parent TextRun
151: * @param startAt
152: */
153: public void updateStartPosition(int startAt) {
154: startPos = startAt;
155: }
156:
157: // --------------- Internal helpers on rich text properties -------
158:
159: /**
160: * Fetch the value of the given flag in the CharFlagsTextProp.
161: * Returns false if the CharFlagsTextProp isn't present, since the
162: * text property won't be set if there's no CharFlagsTextProp.
163: */
164: private boolean isCharFlagsTextPropVal(int index) {
165: return getFlag(true, index);
166: }
167:
168: private boolean getFlag(boolean isCharacter, int index) {
169: TextPropCollection props;
170: String propname;
171: if (isCharacter) {
172: props = characterStyle;
173: propname = CharFlagsTextProp.NAME;
174: } else {
175: props = paragraphStyle;
176: propname = ParagraphFlagsTextProp.NAME;
177: }
178:
179: BitMaskTextProp prop = null;
180: if (props != null) {
181: prop = (BitMaskTextProp) props.findByName(propname);
182: }
183: if (prop == null) {
184: Sheet sheet = parentRun.getSheet();
185: int txtype = parentRun.getRunType();
186: MasterSheet master = sheet.getMasterSheet();
187: if (master != null)
188: prop = (BitMaskTextProp) master
189: .getStyleAttribute(txtype, getIndentLevel(),
190: propname, isCharacter);
191: }
192:
193: return prop == null ? false : prop.getSubValue(index);
194: }
195:
196: /**
197: * Set the value of the given flag in the CharFlagsTextProp, adding
198: * it if required.
199: */
200: private void setCharFlagsTextPropVal(int index, boolean value) {
201: setFlag(true, index, value);
202: }
203:
204: public void setFlag(boolean isCharacter, int index, boolean value) {
205: TextPropCollection props;
206: String propname;
207: if (isCharacter) {
208: props = characterStyle;
209: propname = CharFlagsTextProp.NAME;
210: } else {
211: props = paragraphStyle;
212: propname = ParagraphFlagsTextProp.NAME;
213: }
214:
215: // Ensure we have the StyleTextProp atom we're going to need
216: if (props == null) {
217: parentRun.ensureStyleAtomPresent();
218: props = isCharacter ? characterStyle : paragraphStyle;
219: }
220:
221: BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(
222: props, propname);
223: prop.setSubValue(value, index);
224: }
225:
226: /**
227: * Returns the named TextProp, either by fetching it (if it exists) or adding it
228: * (if it didn't)
229: * @param textPropCol The TextPropCollection to fetch from / add into
230: * @param textPropName The name of the TextProp to fetch/add
231: */
232: private TextProp fetchOrAddTextProp(TextPropCollection textPropCol,
233: String textPropName) {
234: // Fetch / Add the TextProp
235: TextProp tp = textPropCol.findByName(textPropName);
236: if (tp == null) {
237: tp = textPropCol.addWithName(textPropName);
238: }
239: return tp;
240: }
241:
242: /**
243: * Fetch the value of the given Character related TextProp.
244: * Returns -1 if that TextProp isn't present.
245: * If the TextProp isn't present, the value from the appropriate
246: * Master Sheet will apply.
247: */
248: private int getCharTextPropVal(String propName) {
249: TextProp prop = null;
250: if (characterStyle != null) {
251: prop = characterStyle.findByName(propName);
252: }
253:
254: if (prop == null) {
255: Sheet sheet = parentRun.getSheet();
256: int txtype = parentRun.getRunType();
257: MasterSheet master = sheet.getMasterSheet();
258: if (master != null)
259: prop = master.getStyleAttribute(txtype,
260: getIndentLevel(), propName, true);
261: }
262: return prop == null ? -1 : prop.getValue();
263: }
264:
265: /**
266: * Fetch the value of the given Paragraph related TextProp.
267: * Returns -1 if that TextProp isn't present.
268: * If the TextProp isn't present, the value from the appropriate
269: * Master Sheet will apply.
270: */
271: private int getParaTextPropVal(String propName) {
272: TextProp prop = null;
273: if (paragraphStyle != null) {
274: prop = paragraphStyle.findByName(propName);
275: }
276: if (prop == null) {
277: Sheet sheet = parentRun.getSheet();
278: int txtype = parentRun.getRunType();
279: MasterSheet master = sheet.getMasterSheet();
280: if (master != null)
281: prop = master.getStyleAttribute(txtype,
282: getIndentLevel(), propName, false);
283: }
284:
285: return prop == null ? -1 : prop.getValue();
286: }
287:
288: /**
289: * Sets the value of the given Character TextProp, add if required
290: * @param propName The name of the Character TextProp
291: * @param val The value to set for the TextProp
292: */
293: public void setParaTextPropVal(String propName, int val) {
294: // Ensure we have the StyleTextProp atom we're going to need
295: if (paragraphStyle == null) {
296: parentRun.ensureStyleAtomPresent();
297: // paragraphStyle will now be defined
298: }
299:
300: TextProp tp = fetchOrAddTextProp(paragraphStyle, propName);
301: tp.setValue(val);
302: }
303:
304: /**
305: * Sets the value of the given Paragraph TextProp, add if required
306: * @param propName The name of the Paragraph TextProp
307: * @param val The value to set for the TextProp
308: */
309: public void setCharTextPropVal(String propName, int val) {
310: // Ensure we have the StyleTextProp atom we're going to need
311: if (characterStyle == null) {
312: parentRun.ensureStyleAtomPresent();
313: // characterStyle will now be defined
314: }
315:
316: TextProp tp = fetchOrAddTextProp(characterStyle, propName);
317: tp.setValue(val);
318: }
319:
320: // --------------- Friendly getters / setters on rich text properties -------
321:
322: public boolean isBold() {
323: return isCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX);
324: }
325:
326: public void setBold(boolean bold) {
327: setCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX, bold);
328: }
329:
330: public boolean isItalic() {
331: return isCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX);
332: }
333:
334: public void setItalic(boolean italic) {
335: setCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX, italic);
336: }
337:
338: public boolean isUnderlined() {
339: return isCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX);
340: }
341:
342: public void setUnderlined(boolean underlined) {
343: setCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX,
344: underlined);
345: }
346:
347: public int getFontSize() {
348: return getCharTextPropVal("font.size");
349: }
350:
351: public void setFontSize(int fontSize) {
352: setCharTextPropVal("font.size", fontSize);
353: }
354:
355: public void setFontName(String fontName) {
356: if (slideShow == null) {
357: //we can't set font since slideshow is not assigned yet
358: _fontname = fontName;
359: } else {
360: // Get the index for this font (adding if needed)
361: int fontIdx = slideShow.getFontCollection().addFont(
362: fontName);
363: setCharTextPropVal("font.index", fontIdx);
364: }
365: }
366:
367: public String getFontName() {
368: if (slideShow == null) {
369: return _fontname;
370: } else {
371: int fontIdx = getCharTextPropVal("font.index");
372: if (fontIdx == -1) {
373: return null;
374: }
375: return slideShow.getFontCollection().getFontWithId(fontIdx);
376: }
377: }
378:
379: /**
380: * @return font color as RGB value
381: * @see java.awt.Color
382: */
383: public Color getFontColor() {
384: int rgb = getCharTextPropVal("font.color");
385: if (rgb >= 0x8000000) {
386: int idx = rgb % 0x8000000;
387: ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
388: if (idx >= 0 && idx <= 7)
389: rgb = ca.getColor(idx);
390: }
391:
392: Color tmp = new Color(rgb, true);
393: return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
394: }
395:
396: /**
397: * Sets color of the text, as a int bgr.
398: * (PowerPoint stores as BlueGreenRed, not the more
399: * usual RedGreenBlue)
400: * @see java.awt.Color
401: */
402: public void setFontColor(int bgr) {
403: setCharTextPropVal("font.color", bgr);
404: }
405:
406: /**
407: * Sets color of the text, as a java.awt.Color
408: */
409: public void setFontColor(Color color) {
410: // In PowerPont RGB bytes are swapped, as BGR
411: int rgb = new Color(color.getBlue(), color.getGreen(), color
412: .getRed(), 254).getRGB();
413: setFontColor(rgb);
414: }
415:
416: /**
417: * Sets the type of horizontal alignment for the text.
418: * One of the <code>Align*</code> constants defined in the <code>TextBox</code> class.
419: *
420: * @param align - the type of alignment
421: */
422: public void setAlignment(int align) {
423: setParaTextPropVal("alignment", align);
424: }
425:
426: /**
427: * Returns the type of horizontal alignment for the text.
428: * One of the <code>Align*</code> constants defined in the <code>TextBox</class> class.
429: *
430: * @return the type of alignment
431: */
432: public int getAlignment() {
433: return getParaTextPropVal("alignment");
434: }
435:
436: /**
437: *
438: * @return indentation level
439: */
440: public int getIndentLevel() {
441: return paragraphStyle == null ? 0 : paragraphStyle
442: .getReservedField();
443: }
444:
445: /**
446: * Sets whether this rich text run has bullets
447: */
448: public void setBullet(boolean flag) {
449: setFlag(false, ParagraphFlagsTextProp.BULLET_IDX, flag);
450: }
451:
452: /**
453: * Returns whether this rich text run has bullets
454: */
455: public boolean isBullet() {
456: return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
457: }
458:
459: /**
460: * Sets the bullet character
461: */
462: public void setBulletChar(char c) {
463: setParaTextPropVal("bullet.char", c);
464: }
465:
466: /**
467: * Returns the bullet character
468: */
469: public char getBulletChar() {
470: return (char) getParaTextPropVal("bullet.char");
471: }
472:
473: /**
474: * Sets the bullet offset
475: */
476: public void setBulletOffset(int offset) {
477: setParaTextPropVal("bullet.offset", offset * Shape.MASTER_DPI
478: / Shape.POINT_DPI);
479: }
480:
481: /**
482: * Returns the bullet offset
483: */
484: public int getBulletOffset() {
485: return getParaTextPropVal("bullet.offset") * Shape.POINT_DPI
486: / Shape.MASTER_DPI;
487: }
488:
489: /**
490: * Sets the text offset
491: */
492: public void setTextOffset(int offset) {
493: setParaTextPropVal("text.offset", offset * Shape.MASTER_DPI
494: / Shape.POINT_DPI);
495: }
496:
497: /**
498: * Returns the text offset
499: */
500: public int getTextOffset() {
501: return getParaTextPropVal("text.offset") * Shape.POINT_DPI
502: / Shape.MASTER_DPI;
503: }
504:
505: // --------------- Internal HSLF methods, not intended for end-user use! -------
506:
507: /**
508: * Internal Use Only - get the underlying paragraph style collection.
509: * For normal use, use the friendly setters and getters
510: */
511: public TextPropCollection _getRawParagraphStyle() {
512: return paragraphStyle;
513: }
514:
515: /**
516: * Internal Use Only - get the underlying character style collection.
517: * For normal use, use the friendly setters and getters
518: */
519: public TextPropCollection _getRawCharacterStyle() {
520: return characterStyle;
521: }
522:
523: /**
524: * Internal Use Only - are the Paragraph styles shared?
525: */
526: public boolean _isParagraphStyleShared() {
527: return sharingParagraphStyle;
528: }
529:
530: /**
531: * Internal Use Only - are the Character styles shared?
532: */
533: public boolean _isCharacterStyleShared() {
534: return sharingCharacterStyle;
535: }
536: }
|