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.Rectangle;
023: import java.awt.Shape;
024:
025: import javax.swing.text.Position.Bias;
026:
027: import org.apache.harmony.awt.text.TextUtils;
028:
029: import org.apache.harmony.x.swing.internal.nls.Messages;
030:
031: public abstract class CompositeView extends View {
032: private View[] children;
033: private final Rectangle rect = new Rectangle();
034: private short topInset;
035: private short leftInset;
036: private short bottomInset;
037: private short rightInset;
038:
039: public CompositeView(final Element element) {
040: super (element);
041: children = new View[0];
042: }
043:
044: protected abstract void childAllocation(int index, Rectangle rc);
045:
046: protected abstract boolean isAfter(int x, int y, Rectangle rc);
047:
048: protected abstract boolean isBefore(int x, int y, Rectangle rc);
049:
050: protected abstract View getViewAtPoint(int x, int y, Rectangle alloc);
051:
052: @Override
053: public Shape getChildAllocation(final int index, final Shape shape) {
054: Rectangle rc = getInsideAllocation(shape);
055: childAllocation(index, rc);
056:
057: return rc;
058: }
059:
060: @Override
061: public View getView(final int index) {
062: return children[index];
063: }
064:
065: @Override
066: public int getViewIndex(final int pos, final Bias bias) {
067: int offset = bias == Bias.Backward ? pos - 1 : pos;
068: if (offset < getStartOffset() || offset >= getEndOffset()) {
069: return -1;
070: }
071:
072: return getViewIndexAtPosition(offset);
073: }
074:
075: @Override
076: public int getViewCount() {
077: return children.length;
078: }
079:
080: @Override
081: public void replace(final int index, final int length,
082: final View[] views) {
083: int toAdd = views != null ? views.length : 0;
084:
085: for (int i = index; i < index + length; i++) {
086: if (children[i].getParent() == this ) {
087: children[i].setParent(null);
088: }
089: }
090:
091: for (int i = 0; i < toAdd; i++) {
092: views[i].setParent(this );
093: }
094:
095: if (length == toAdd) {
096: if (views != null) {
097: System.arraycopy(views, 0, children, index, toAdd);
098: }
099: } else {
100: View[] newArray = new View[children.length - length + toAdd];
101: System.arraycopy(children, 0, newArray, 0, index);
102: if (views != null) {
103: System.arraycopy(views, 0, newArray, index, toAdd);
104: }
105: System.arraycopy(children, index + length, newArray, index
106: + toAdd, children.length - (index + length));
107:
108: children = newArray;
109: }
110: }
111:
112: @Override
113: public void setParent(final View parentView) {
114: super .setParent(parentView);
115:
116: if (parentView != null && getViewCount() == 0) {
117: loadChildren(getViewFactory());
118: }
119: }
120:
121: @Override
122: public Shape modelToView(final int pos, final Shape shape,
123: final Bias bias) throws BadLocationException {
124: int index = getViewIndexAtPosition(bias == Bias.Backward ? pos - 1
125: : pos);
126: if (index != -1) {
127: return getView(index).modelToView(pos,
128: getChildAllocation(index, shape), bias);
129: }
130:
131: throw new BadLocationException(Messages.getString(
132: "swing.83", pos), pos); //$NON-NLS-1$
133: }
134:
135: @Override
136: public Shape modelToView(final int p1, final Bias b1, final int p2,
137: final Bias b2, final Shape shape)
138: throws BadLocationException {
139:
140: // TODO should throw IllegalArgumentException for invalid bias arg
141: int index1 = getViewIndex(p1, b1);
142: if (index1 == -1) {
143: throw new BadLocationException(Messages.getString(
144: "swing.83", p1), p1); //$NON-NLS-1$
145: }
146:
147: int index2 = getViewIndex(p2, b2);
148: if (index2 == -1) {
149: throw new BadLocationException(Messages.getString(
150: "swing.83", p2), p2); //$NON-NLS-1$
151: }
152:
153: Rectangle rc1;
154: Rectangle rc2;
155: if (index1 == index2) {
156: // Both positions are on the same line
157:
158: Rectangle alloc = (Rectangle) getChildAllocation(index1,
159: shape);
160: rc1 = (Rectangle) getView(index1)
161: .modelToView(p1, alloc, b1);
162: rc2 = (Rectangle) getView(index1)
163: .modelToView(p2, alloc, b2);
164: } else if (Math.abs(index2 - index1) == 1) {
165: // Positions are on adjacent lines
166:
167: // Get "preferred" span for view @ index1
168: Rectangle alloc = (Rectangle) getChildAllocation(index1,
169: shape);
170: View view1 = getView(index1);
171: rc1 = (Rectangle) view1.modelToView(view1.getStartOffset(),
172: alloc, Bias.Forward); // first char position
173: rc2 = (Rectangle) view1.modelToView(view1.getEndOffset(),
174: alloc, Bias.Forward); // last char position
175: rc1 = rc1.union(rc2); // first line (painted with text)
176:
177: rc2 = (Rectangle) getView(index2).modelToView(p2,
178: getChildAllocation(index2, shape), b2);
179: } else {
180: // Positions on different lines and the lines are not adjacent
181:
182: rc1 = new Rectangle((Rectangle) getChildAllocation(index1,
183: shape));
184: rc2 = (Rectangle) getChildAllocation(index2, shape);
185: }
186:
187: return rc1.union(rc2);
188: }
189:
190: @Override
191: public int viewToModel(final float x, final float y,
192: final Shape shape, final Bias[] biasReturn) {
193: biasReturn[0] = Bias.Forward;
194:
195: Rectangle bounds = getInsideAllocation(shape);
196:
197: if (isBefore((int) x, (int) y, bounds)) {
198: return getStartOffset();
199: } else if (isAfter((int) x, (int) y, bounds)) {
200: biasReturn[0] = Bias.Backward;
201: return getEndOffset() - 1;
202: } else {
203: // The point lies within the bounds
204: View v = getViewAtPoint((int) x, (int) y, bounds);
205: if (v != null) {
206: return v.viewToModel(x, y, bounds, biasReturn);
207: } else {
208: return -1;
209: }
210: }
211: }
212:
213: @Override
214: public int getNextVisualPositionFrom(final int pos,
215: final Bias bias, final Shape shape, final int direction,
216: final Bias[] biasRet) throws BadLocationException {
217:
218: if (direction == WEST || direction == EAST) {
219: return getNextEastWestVisualPositionFrom(pos, bias, shape,
220: direction, biasRet);
221: } else if (direction == NORTH || direction == SOUTH) {
222: return getNextNorthSouthVisualPositionFrom(pos, bias,
223: shape, direction, biasRet);
224: }
225:
226: throw new IllegalArgumentException(Messages
227: .getString("swing.84")); //$NON-NLS-1$
228: }
229:
230: protected void loadChildren(final ViewFactory factory) {
231: if (factory == null) {
232: return;
233: }
234:
235: final int count = getElement().getElementCount();
236:
237: View[] views = new View[count];
238:
239: for (int i = 0; i < count; i++) {
240: views[i] = factory.create(getElement().getElement(i));
241: }
242:
243: replace(0, children.length, views);
244: }
245:
246: protected int getViewIndexAtPosition(final int pos) {
247: if (pos >= getEndOffset()) {
248: return getViewCount() - 1;
249: }
250: if (pos < getStartOffset()) {
251: return getViewCount() > 0 ? 0 : -1;
252: }
253:
254: final int count = getViewCount();
255: for (int i = 0; i < count; i++) {
256: View view = getView(i);
257: if (view.getStartOffset() <= pos
258: && pos < view.getEndOffset()) {
259:
260: return i;
261: }
262: }
263:
264: return -1;
265: }
266:
267: protected View getViewAtPosition(final int pos,
268: final Rectangle alloc) {
269: int index = getViewIndexAtPosition(pos);
270: if (index != -1) {
271: childAllocation(index, alloc);
272: return getView(index);
273: }
274: return null;
275: }
276:
277: protected short getTopInset() {
278: return topInset;
279: }
280:
281: protected short getLeftInset() {
282: return leftInset;
283: }
284:
285: protected short getBottomInset() {
286: return bottomInset;
287: }
288:
289: protected short getRightInset() {
290: return rightInset;
291: }
292:
293: protected void setInsets(final short top, final short left,
294: final short bottom, final short right) {
295: topInset = top;
296: leftInset = left;
297: bottomInset = bottom;
298: rightInset = right;
299: }
300:
301: protected void setParagraphInsets(final AttributeSet attrs) {
302: setInsets((short) StyleConstants.getSpaceAbove(attrs),
303: (short) StyleConstants.getLeftIndent(attrs),
304: (short) StyleConstants.getSpaceBelow(attrs),
305: (short) StyleConstants.getRightIndent(attrs));
306: }
307:
308: protected Rectangle getInsideAllocation(final Shape shape) {
309: if (shape == null) {
310: return null;
311: }
312:
313: rect.setBounds(shape.getBounds());
314: rect.x += getLeftInset();
315: rect.y += getTopInset();
316: rect.width -= (getLeftInset() + getRightInset());
317: rect.height -= (getTopInset() + getBottomInset());
318: return rect;
319: }
320:
321: protected int getNextEastWestVisualPositionFrom(final int pos,
322: final Position.Bias bias, final Shape shape,
323: final int direction, final Bias[] biasRet)
324: throws BadLocationException {
325:
326: if (direction == WEST || direction == EAST) {
327: return TextUtils.getNextVisualPositionFrom(getTextKit(),
328: this , pos, bias, shape, direction, biasRet);
329: }
330:
331: throw new IllegalArgumentException(Messages
332: .getString("swing.84")); //$NON-NLS-1$
333: }
334:
335: protected int getNextNorthSouthVisualPositionFrom(final int pos,
336: final Position.Bias bias, final Shape shape,
337: final int direction, final Bias[] biasRet)
338: throws BadLocationException {
339:
340: if (direction == NORTH || direction == SOUTH) {
341: return TextUtils.getNextVisualPositionFrom(getTextKit(),
342: this , pos, bias, shape, direction, biasRet);
343: }
344:
345: throw new IllegalArgumentException(Messages
346: .getString("swing.84")); //$NON-NLS-1$
347: }
348:
349: protected boolean flipEastAndWestAtEnds(final int position,
350: final Bias bias) {
351: return false;
352: }
353: }
|