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: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.awt.Graphics;
023:
024: import org.apache.harmony.x.swing.Utilities;
025:
026: /**
027: * Represents a basic interval of text. There are three non-abstract
028: * implementations:
029: * <ol>
030: * <li><code>UnselectedTextInterval</code>,</li>
031: * <li><code>SelectedTextInterval</code>,</li>
032: * <li><code>ComposedTextInterval</code>.</li>
033: * </ol>
034: */
035: abstract class TextInterval implements Cloneable {
036:
037: /**
038: * Defines how text is actually painted.
039: */
040: interface TextIntervalPainter {
041: /**
042: * Paints selected range of text.
043: *
044: * @param g graphics to paint on.
045: * @param start the start of the selected range.
046: * @param end the end of the selected range.
047: * @param x the <var>x</var> coordinate of the text.
048: * @param y the <var>y</var> coordinate of the text.
049: * It assumed to be the baseline position.
050: * @return the <var>x</var> coordinate where the next interval is
051: * to be painted.
052: *
053: * @throws BadLocationException if interval represents invalid
054: * model range.
055: */
056: int paintSelected(Graphics g, int start, int end, int x, int y)
057: throws BadLocationException;
058:
059: /**
060: * Paints unselected range of text.
061: *
062: * @param g graphics to paint on.
063: * @param start the start of the unselected range.
064: * @param end the end of the unselected range.
065: * @param x the <var>x</var> coordinate of the text.
066: * @param y the <var>y</var> coordinate of the text.
067: * It assumed to be the baseline position.
068: * @return the <var>x</var> coordinate where the next interval is
069: * to be painted.
070: *
071: * @throws BadLocationException if interval represents invalid
072: * model range.
073: */
074: int paintUnselected(Graphics g, int start, int end, int x, int y)
075: throws BadLocationException;
076:
077: /**
078: * Paints composed text.
079: *
080: * @param g graphics to paint on.
081: * @param start the start of the composed text.
082: * @param end the end of the composed text.
083: * @param x the <var>x</var> coordinate of the text.
084: * @param y the <var>y</var> coordinate of the text.
085: * It assumed to be the baseline position.
086: * @return the <var>x</var> coordinate where the next interval is
087: * to be painted.
088: *
089: * @throws BadLocationException if interval represents invalid
090: * model range.
091: */
092: int paintComposed(Graphics g, int start, int end, int x, int y)
093: throws BadLocationException;
094: }
095:
096: /**
097: * Start of the interval.
098: */
099: protected int start;
100: /**
101: * End of the interval.
102: */
103: protected int end;
104: /**
105: * Painter to do actual text painting.
106: */
107: protected final TextIntervalPainter painter;
108:
109: /**
110: * Creates a text interval.
111: *
112: * @param start the start of the interval.
113: * @param end the end of the interval.
114: * @param painter the painter to use.
115: */
116: public TextInterval(final int start, final int end,
117: final TextIntervalPainter painter) {
118: this .start = start;
119: this .end = end;
120: this .painter = painter;
121: }
122:
123: /**
124: * Returns dissection of this interval and <code>another</code>.
125: *
126: * @param another the interval to dissect with.
127: * @return pairwise disjoint intervals.
128: */
129: public abstract TextInterval[] dissect(TextInterval another);
130:
131: /**
132: * Returns the string type of the interval.
133: * It is used in <code>toString</code> method.
134: *
135: * @return the string type of the interval.
136: */
137: public abstract String getType();
138:
139: /**
140: * Checks whether this interval is empty.
141: *
142: * @return <code>true</code> if the interval start is equal to its end;
143: * <code>false</code> otherwise.
144: */
145: public final boolean isEmpty() {
146: return start == end;
147: }
148:
149: /**
150: * Checks whether two intervals intersect.
151: *
152: * @param another the interval to check intersection with.
153: * @return <code>true</code> if this interval intersects
154: * with <code>another</code>; <code>false</code> otherwise.
155: */
156: public final boolean intersects(final TextInterval another) {
157: return Utilities.range(start, another.start, another.end) != Utilities
158: .range(end, another.start, another.end);
159: }
160:
161: /**
162: * Paints text which falls in this interval.
163: *
164: * @param g graphics to paint on.
165: * @param x the <var>x</var> coordinate.
166: * @param y the <var>y</var> coordinate.
167: * It assumed to be the baseline of text.
168: * @return the <var>x</var> coordinate where the next text interval should
169: * be painted.
170: * @throws BadLocationException if interval represents invalid model range.
171: */
172: public abstract int paint(final Graphics g, final int x, final int y)
173: throws BadLocationException;
174:
175: /**
176: * Creates a copy of the interval with new start and end.
177: *
178: * @param start the new start of the interval.
179: * @param end the new end of the interval.
180: * @return the interval with the new start and end.
181: */
182: public final TextInterval create(final int start, final int end) {
183: TextInterval result;
184: try {
185: result = (TextInterval) clone();
186: } catch (CloneNotSupportedException e) {
187: e.printStackTrace();
188: return null;
189: }
190: result.start = start;
191: result.end = end;
192: return result;
193: }
194:
195: /**
196: * Converts interval to a string.
197: * @return the string representation of the interval.
198: */
199: public String toString() {
200: return getType() + "[" + start + ", " + end + "]";
201: }
202:
203: /**
204: * Dissects <em>selected</em> and <em>composed</em> text intervals.
205: * <p><i>This method is meant for internal usage only.</i>
206: *
207: * @param selected the interval with selected text.
208: * @param composed the interval with composed text.
209: * @return pairwise disjoint intervals.
210: */
211: static TextInterval[] dissect(final SelectedTextInterval selected,
212: final ComposedTextInterval composed) {
213: if (selected.isEmpty()) {
214: return new TextInterval[] {};
215: }
216: if (composed.isEmpty()) {
217: return new TextInterval[] { selected };
218: }
219: if (!selected.intersects(composed)) {
220: return new TextInterval[] { selected };
221: }
222:
223: if (composed.start > selected.start) {
224: if (composed.end >= selected.end) {
225: return new TextInterval[] {
226: selected.create(selected.start, composed.start),
227: composed };
228: } else {
229: return new TextInterval[] {
230: selected.create(selected.start, composed.start),
231: composed,
232: selected.create(composed.end, selected.end), };
233: }
234: } else {
235: if (composed.end >= selected.end) {
236: return new TextInterval[] { composed };
237: } else {
238: return new TextInterval[] { composed,
239: selected.create(composed.end, selected.end) };
240: }
241: }
242: }
243:
244: /**
245: * Dissects <em>unselected</em> and <em>selected or composed</em>
246: * text intervals.
247: * <p><i>This method is meant for internal usage only.</i>
248: *
249: * @param ordinary the interval with unselected text.
250: * @param selectedOrComposed the interval with selected or composed text.
251: * @return pairwise disjoint intervals.
252: */
253: static TextInterval[] dissect(
254: final UnselectedTextInterval ordinary,
255: final TextInterval selectedOrComposed) {
256: if (selectedOrComposed.isEmpty()) {
257: return new TextInterval[] { ordinary };
258: }
259: if (!ordinary.intersects(selectedOrComposed)) {
260: return new TextInterval[] { ordinary };
261: }
262:
263: if (ordinary.start >= selectedOrComposed.start) {
264: if (ordinary.end > selectedOrComposed.end) {
265: return new TextInterval[] {
266: selectedOrComposed.create(ordinary.start,
267: selectedOrComposed.end),
268: ordinary.create(selectedOrComposed.end,
269: ordinary.end) };
270: } else {
271: return new TextInterval[] { selectedOrComposed.create(
272: ordinary.start, ordinary.end) };
273: }
274: } else {
275: if (ordinary.end > selectedOrComposed.end) {
276: return new TextInterval[] {
277: ordinary.create(ordinary.start,
278: selectedOrComposed.start),
279: selectedOrComposed,
280: ordinary.create(selectedOrComposed.end,
281: ordinary.end) };
282: } else {
283: return new TextInterval[] {
284: ordinary.create(ordinary.start,
285: selectedOrComposed.start),
286: selectedOrComposed.create(
287: selectedOrComposed.start, ordinary.end) };
288: }
289: }
290: }
291: }
|