001: /*
002: * (C) Copyright IBM Corp. 1998-2004. All Rights Reserved.
003: *
004: * The program is provided "as is" without any warranty express or
005: * implied, including the warranty of non-infringement and the implied
006: * warranties of merchantibility and fitness for a particular purpose.
007: * IBM will not be liable for any damages suffered by you as a result
008: * of using the Program. In no event will IBM be liable for any
009: * special, indirect or consequential damages or lost profits even if
010: * IBM has been advised of the possibility of their occurrence. IBM
011: * will not be liable for any third party claims against you.
012: */
013:
014: package com.ibm.richtext.textformat;
015:
016: import java.awt.Color;
017: import java.awt.Graphics;
018: import java.awt.Point;
019: import java.awt.Rectangle;
020:
021: import com.ibm.richtext.styledtext.MConstText;
022: import com.ibm.richtext.textlayout.attributes.AttributeMap;
023:
024: /**
025: *
026: * This class formats lines of text to a given length.
027: * It provides services needed for static text display,
028: * and also editable text, including: displaying text,
029: * reformatting text after an edit, converting between
030: * screen locations and offsets into the text, calculating
031: * areas of the screen for "highlighting," and computing
032: * offsets into the text resulting from arrow keys.
033: * <p>
034: * Text clients instantiate this class with an
035: * <tt>MConstText</tt> object and a format width. Text
036: * can be formatted such that all lines fit within the
037: * format length. Alternatively, text can be formatted
038: * such that lines end only at the end of paragraphs.
039: * <p>
040: * The format length is specified with the <tt>setLineBound()</tt>
041: * method.
042: * <p>
043: * Methods in the formatter which interact with the graphics
044: * system generally take as a paramter a <tt>Point</tt> object
045: * which represents the "origin" of the text display. The
046: * origin represents the location, in the graphics system used to display the text, of
047: * the top-left corner of the text.
048: * <p>
049: * To display the text, call <tt>draw()</tt>, passing the
050: * a rectangle in which to draw as a parameter. Only lines
051: * of text in the draw rectangle will be drawn.
052: * <p>
053: * When the formatter's text changes, it is important to first call
054: * <tt>stopBackgroundFormatting()</tt> to prevent the Formatter from
055: * accessing the text from a background thread. After modifications are
056: * complete,
057: * call the <tt>updateFormat()</tt> method before invoking any other
058: * methods of the formatter. <tt>updateFormat()</tt> reformats the
059: * new text, formatting no more text than is necessary.
060: * <p>
061: * The formatter provides services for responding to user input from the
062: * mouse and keyboard. The method <tt>pointToTextOffset()</tt> converts
063: * a screen location to an offset in the text. The method <tt>textOffsetToPoint</tt>
064: * converts an offset in the text to an array of two <tt>Point</tt> objects, which can be
065: * used to draw a verticle caret, denoting an insertion point. <tt>highlightArea</tt>
066: * accepts two offsets into the text as paramters, and returns an array of <tt>Polygon</tt>
067: * objects representing areas where visual highlighting should be applied.
068: * <p>
069: * Finally, for
070: * keyboard handling, the <tt>findNewInsertionOffset()</tt> method accepts an "initial"
071: * offset, a "previous" offset, as well as a direction, and returns a new offset. The direction
072: * can be up, down, left, or right. The previous offset is the insertion point location, before
073: * the arrow key is processed. The initial offset is the offset where an up or down arrow
074: * key sequence began. Using the initial offset allows for "intelligent" handling of up and down
075: * arrow keys.
076: * <p>
077: * Examples of using the MFormatter class
078: * are given in the <tt>AsyncFormatter</tt> class
079: * documentation.
080: * <p>
081: * @author John Raley
082: *
083: * @see com.ibm.richtext.styledtext.MText
084: */
085:
086: public abstract class MFormatter {
087: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
088:
089: public abstract AttributeMap getDefaultValues();
090:
091: /**
092: * Display text in drawArea, with highlighting.
093: * Does not reformat text
094: * @param g the Graphics object in which to draw
095: * @param drawArea the rectangle, in g's coordinate system, in which to draw
096: * @param origin the top-left corner of the text, in g's coordinate system
097: * @param selStart the offset where the current selection begins; pass <tt>null</tt> if no selection
098: * @param selStop the offset where the current selection ends
099: * @param highlight the color of the highlighting
100: */
101: public abstract void draw(Graphics g, Rectangle drawArea,
102: Point origin, TextOffset selStart, TextOffset selStop,
103: Color highlight);
104:
105: public abstract void draw(Graphics g, Rectangle drawArea,
106: Point origin);
107:
108: /**
109: * Specify whether to wrap line at the edge of the destination area.
110: * <tt>true</tt> means wrap lines; <tt>false</tt> means to break lines
111: * only when an end-of-line character is reached.
112: * @param wrap <tt>true</tt> to break lines at the edge of the destination
113: * area; <tt>false</tt> otherwise.
114: */
115:
116: public abstract void setWrap(boolean wrap);
117:
118: /**
119: * Return whether text is wrapped at the edge of the destination area.
120: * @see #setWrap
121: */
122: public abstract boolean wrap();
123:
124: /**
125: * Specify the number of pixels along the "line dimension".
126: * Lines are formatted to fit within the line dimension. The
127: * line dimension in Roman script is horizontal.
128: * @param lineBound the length, in pixels, to which lines will be formatted
129: */
130: public abstract void setLineBound(int lineBound);
131:
132: /**
133: * Return the number of pixels along the line dimension.
134: * @return the number of pixels along the line dimension.
135: */
136: public abstract int lineBound();
137:
138: /**
139: * Format text down to given height.
140: * @param height the height to which text will be formatted
141: */
142: public abstract void formatToHeight(int height);
143:
144: /**
145: * Reformat text after a change.
146: * After the formatter's text changes, call this method to reformat. Does
147: * not redraw.
148: * @param afStart the offset into the text where modification began; ie, the
149: * first character in the text which is "different" in some way. Does not
150: * have to be nonnegative.
151: * @param afLength the number of new or changed characters in the text. Should never
152: * be less than 0.
153: * @param viewRect the Rectangle in which the text will be displayed. This is needed for
154: * returning the "damaged" area - the area of the screen in which the text must be redrawn.
155: * @param origin the top-left corner of the text, in the display's coordinate system
156: * @return a <tt>Rectangle</tt> which specifies the area in which text must be
157: * redrawn to reflect the change to the text.
158: */
159: public abstract Rectangle updateFormat(int afStart, int afLength,
160: Rectangle viewRect, Point origin);
161:
162: public abstract int minY();
163:
164: /**
165: * Return the maximum vertical coordinate of the document area.
166: */
167: public abstract int maxY();
168:
169: public abstract int minX();
170:
171: /**
172: * Return the maximum horizontal coordinate of the document area.
173: */
174: public abstract int maxX();
175:
176: /**
177: * Return the actual pixel length of the text which has been formatted.
178: */
179: public abstract int formattedHeight();
180:
181: public static final short eUp = -10, eDown = 10, eLeft = -1,
182: eRight = 1;
183:
184: /**
185: * Given a screen location p, return the offset of the character in the text nearest to p.
186: *
187: * The offset may or may not include a newline at the end of a line, determined by anchor and infiniteMode.
188: * The newline is not included if infiniteMode is true and the anchor is the position before the newline.
189: *
190: * @param result TextOffset to modify and return. If null, one will be allocated, modified, and returned.
191: * @param px the x component of the point.
192: * @param py the y component of the point.
193: * @param origin the top-left corner of the text, in the display's coordinate system
194: * @param anchor the previous offset. May be null. Used to determine whether newlines are included.
195: * @param infiniteMode if true, treat newlines at end of line as having infinite width.
196: */
197: public abstract TextOffset pointToTextOffset(TextOffset result,
198: int px, int py, Point origin, TextOffset anchor,
199: boolean infiniteMode);
200:
201: /**
202: * Given an offset, return the Rectangle bounding the caret at the offset.
203: * @param offset an offset into the text
204: * @param origin the top-left corner of the text, in the display's coordinate system
205: * @return a Rectangle bounding the caret.
206: */
207: public abstract Rectangle getCaretRect(TextOffset offset,
208: Point origin);
209:
210: /**
211: * Draw the caret(s) associated with the given offset into the given Graphics.
212: * @param g the Graphics to draw into
213: * @param offset the offset in the text for which the caret is drawn
214: * @param origin the top-left corner of the text, in the display's coordinate system
215: * @param strongCaretColor the color of the strong caret
216: * @param weakCaretColor the color of the weak caret (if any)
217: */
218: public abstract void drawCaret(Graphics g, TextOffset offset,
219: Point origin, Color strongCaretColor, Color weakCaretColor);
220:
221: /**
222: * @see #getBoundingRect
223: */
224: public static final boolean LOOSE = false;
225: /**
226: * @see #getBoundingRect
227: */
228: public static final boolean TIGHT = true;
229:
230: /**
231: * Given two offsets in the text, return a rectangle which encloses the lines containing the offsets.
232: * Offsets do not need to be ordered or nonnegative.
233: * @param offset1 an offset into the text
234: * @param offset2 the other offset into the text
235: * @param origin the top-left corner of the text, in the display's coordinate system
236: * @param tight if equal to TIGHT, the bounds is as small as possible. If LOOSE, the width
237: * of the bounds is allowed to be wider than necesary. Loose bounds are easier to compute.
238: * @return a <tt>Rectangle</tt>, relative to <tt>origin</tt>, which encloses the lines containing the offsets
239: */
240: public abstract Rectangle getBoundingRect(TextOffset offset1,
241: TextOffset offset2, Point origin, boolean tight);
242:
243: public abstract void getBoundingRect(Rectangle boundingRect,
244: TextOffset offset1, TextOffset offset2, Point origin,
245: boolean tight);
246:
247: /**
248: * Compute the offset resulting from moving from a previous offset in direction dir.
249: * For arrow keys.
250: * @param previousOffset the insertion offset prior to the arrow key press
251: * @param direction the direction of the arrow key (eUp, eDown, eLeft, or eRight)
252: * @return new offset based on direction and previous offset.
253: */
254: public abstract TextOffset findInsertionOffset(TextOffset result,
255: TextOffset previousOffset, short direction);
256:
257: /**
258: * Compute the offset resulting from moving from a previous offset, starting at an original offset, in direction dir.
259: * For arrow keys. Use this for "smart" up/down keys.
260: * @param result TextOffset to modify and return. If null, a new TextOffset is created, modified, and returned.
261: * @param initialOffset The offset at which an up-down arrow key sequence began.
262: * @param previousOffset The insertion offset prior to the arrow key press.
263: * @param direction The direction of the arrow key (eUp, eDown, eLeft, or eRight)
264: * @return new offset based on direction and previous offset(s).
265: */
266: public abstract TextOffset findNewInsertionOffset(
267: TextOffset result, TextOffset initialOffset,
268: TextOffset previousOffset, short direction);
269:
270: /**
271: * Return the index of the line containing the given character index.
272: * This method has complicated semantics, arising from not knowing
273: * which side of the index to check. The index will be given an
274: * implicit AFTER bias, unless the index is the last index in the text,
275: * the text length is non-zero, and there is not a paragraph separator
276: * at the end of the text.
277: */
278: public abstract int lineContaining(int index);
279:
280: /**
281: * Return the index of the line containing the given offset.
282: */
283: public abstract int lineContaining(TextOffset offset);
284:
285: /**
286: * Return the number of lines.
287: */
288: public abstract int getLineCount();
289:
290: /**
291: * Return the index of the first character on the given line.
292: */
293: public abstract int lineRangeLow(int lineNumber);
294:
295: /**
296: * Return the index of the first character following the given line.
297: */
298: public abstract int lineRangeLimit(int lineNumber);
299:
300: /**
301: * Tells the formatter to stop accessing the text until updateFormat is called.
302: */
303: public abstract void stopBackgroundFormatting();
304:
305: /**
306: * Return the line number at the given graphic height. If height is greater than
307: * the text height, maxLineNumber + 1 is returned.
308: */
309: public abstract int lineAtHeight(int height);
310:
311: /**
312: * Return the graphic height where the given line begins. If the lineNumber is
313: * maxLineNumber the entire text height is returned.
314: */
315: public abstract int lineGraphicStart(int lineNumber);
316:
317: /**
318: * Return true if the given line is left-to-right.
319: * @param lineNumber a valid line
320: * @return true if lineNumber is left-to-right
321: */
322: public abstract boolean lineIsLeftToRight(int lineNumber);
323:
324: /**
325: * Return a new <tt>MFormatter</tt>.
326: * @param text the text to format
327: * @param defaultValues values to use when certain attributes are not specified.
328: * <tt>defaultValues</tt> must contain values for the following attributes:
329: * <tt>FAMILY</tt>, <tt>WEIGHT</tt>, <tt>POSTURE</tt>, <tt>SIZE</tt>, <tt>SUPERSCRIPT</tt>,
330: * <tt>FOREGROUND</tt>, <tt>UNDERLINE</tt>, <tt>STRIKETHROUGH</tt>,
331: * <tt>EXTRA_LINE_SPACING</tt>, <tt>FIRST_LINE_INDENT</tt>,<tt>MIN_LINE_SPACING</tt>,
332: * <tt>LINE_FLUSH</tt>, <tt>LEADING_MARGIN</tt>, <tt>TRAILING_MARGIN</tt>, <tt>TAB_RULER</tt>
333: * @param lineBound length to which lines are formatted
334: * @param wrap <tt>true</tt> if text should be "line wrapped" (formatted to fit destination area)
335: */
336: public static MFormatter createFormatter(MConstText text,
337: AttributeMap defaultValues, int lineBound, boolean wrap,
338: Graphics g) {
339:
340: return new AsyncFormatter(text, defaultValues, lineBound, wrap,
341: g);
342: }
343: }
|