Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / javax / swing / text / CompositeView.java
blobcd6645215428e401fd76c6d8862761da9b0543bb
1 /* CompositeView.java -- An abstract view that manages child views
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Insets;
42 import java.awt.Rectangle;
43 import java.awt.Shape;
45 import javax.swing.SwingConstants;
47 /**
48 * An abstract base implementation of {@link View} that manages child
49 * <code>View</code>s.
51 * @author Roman Kennke (roman@kennke.org)
53 public abstract class CompositeView
54 extends View
57 /**
58 * The child views of this <code>CompositeView</code>.
60 View[] children;
62 /**
63 * The allocation of this <code>View</code> minus its insets. This is
64 * initialized in {@link #getInsideAllocation} and reused and modified in
65 * {@link #childAllocation(int, Rectangle)}.
67 Rectangle insideAllocation;
69 /**
70 * The insets of this <code>CompositeView</code>. This is initialized
71 * in {@link #setInsets}.
73 Insets insets;
75 /**
76 * Creates a new <code>CompositeView</code> for the given
77 * <code>Element</code>.
79 * @param element the element that is rendered by this CompositeView
81 public CompositeView(Element element)
83 super(element);
84 children = new View[0];
85 insets = new Insets(0, 0, 0, 0);
88 /**
89 * Loads the child views of this <code>CompositeView</code>. This method
90 * is called from {@link #setParent} to initialize the child views of
91 * this composite view.
93 * @param f the view factory to use for creating new child views
95 * @see #setParent
97 protected void loadChildren(ViewFactory f)
99 Element el = getElement();
100 int count = el.getElementCount();
101 View[] newChildren = new View[count];
102 for (int i = 0; i < count; ++i)
104 Element child = el.getElement(i);
105 View view = f.create(child);
106 newChildren[i] = view;
108 replace(0, getViewCount(), newChildren);
112 * Sets the parent of this <code>View</code>.
113 * In addition to setting the parent, this calls {@link #loadChildren}, if
114 * this <code>View</code> does not already have its children initialized.
116 * @param parent the parent to set
118 public void setParent(View parent)
120 super.setParent(parent);
121 if (parent != null && ((children == null) || children.length == 0))
122 loadChildren(getViewFactory());
126 * Returns the number of child views.
128 * @return the number of child views
130 public int getViewCount()
132 return children.length;
136 * Returns the child view at index <code>n</code>.
138 * @param n the index of the requested child view
140 * @return the child view at index <code>n</code>
142 public View getView(int n)
144 return children[n];
148 * Replaces child views by some other child views. If there are no views to
149 * remove (<code>length == 0</code>), the result is a simple insert, if
150 * there are no children to add (<code>view == null</code>) the result
151 * is a simple removal.
153 * @param offset the start offset from where to remove children
154 * @param length the number of children to remove
155 * @param views the views that replace the removed children
157 public void replace(int offset, int length, View[] views)
159 // Check for null views to add.
160 for (int i = 0; i < views.length; ++i)
161 if (views[i] == null)
162 throw new NullPointerException("Added views must not be null");
164 int endOffset = offset + length;
166 // First we set the parent of the removed children to null.
167 for (int i = offset; i < endOffset; ++i)
168 children[i].setParent(null);
170 View[] newChildren = new View[children.length - length + views.length];
171 System.arraycopy(children, 0, newChildren, 0, offset);
172 System.arraycopy(views, 0, newChildren, offset, views.length);
173 System.arraycopy(children, offset + length, newChildren,
174 offset + views.length,
175 children.length - (offset + length));
176 children = newChildren;
178 // Finally we set the parent of the added children to this.
179 for (int i = 0; i < views.length; ++i)
180 views[i].setParent(this);
184 * Returns the allocation for the specified child <code>View</code>.
186 * @param index the index of the child view
187 * @param a the allocation for this view
189 * @return the allocation for the specified child <code>View</code>
191 public Shape getChildAllocation(int index, Shape a)
193 Rectangle r = getInsideAllocation(a);
194 childAllocation(index, r);
195 return r;
199 * Maps a position in the document into the coordinate space of the View.
200 * The output rectangle usually reflects the font height but has a width
201 * of zero.
203 * @param pos the position of the character in the model
204 * @param a the area that is occupied by the view
205 * @param bias either {@link Position.Bias#Forward} or
206 * {@link Position.Bias#Backward} depending on the preferred
207 * direction bias. If <code>null</code> this defaults to
208 * <code>Position.Bias.Forward</code>
210 * @return a rectangle that gives the location of the document position
211 * inside the view coordinate space
213 * @throws BadLocationException if <code>pos</code> is invalid
214 * @throws IllegalArgumentException if b is not one of the above listed
215 * valid values
217 public Shape modelToView(int pos, Shape a, Position.Bias bias)
218 throws BadLocationException
220 int childIndex = getViewIndex(pos, bias);
221 if (childIndex != -1)
223 View child = getView(childIndex);
224 Rectangle r = a.getBounds();
225 childAllocation(childIndex, r);
226 Shape result = child.modelToView(pos, r, bias);
227 if (result == null)
228 throw new AssertionError("" + child.getClass().getName()
229 + ".modelToView() must not return null");
230 return result;
232 else
233 throw new BadLocationException("No child view for the specified location",
234 pos);
238 * Maps a region in the document into the coordinate space of the View.
240 * @param p1 the beginning position inside the document
241 * @param b1 the direction bias for the beginning position
242 * @param p2 the end position inside the document
243 * @param b2 the direction bias for the end position
244 * @param a the area that is occupied by the view
246 * @return a rectangle that gives the span of the document region
247 * inside the view coordinate space
249 * @throws BadLocationException if <code>p1</code> or <code>p2</code> are
250 * invalid
251 * @throws IllegalArgumentException if b1 or b2 is not one of the above
252 * listed valid values
254 public Shape modelToView(int p1, Position.Bias b1,
255 int p2, Position.Bias b2, Shape a)
256 throws BadLocationException
258 // TODO: This is most likely not 100% ok, figure out what else is to
259 // do here.
260 return super.modelToView(p1, b1, p2, b2, a);
264 * Maps coordinates from the <code>View</code>'s space into a position
265 * in the document model.
267 * @param x the x coordinate in the view space, x >= 0
268 * @param y the y coordinate in the view space, y >= 0
269 * @param a the allocation of this <code>View</code>
270 * @param b the bias to use
272 * @return the position in the document that corresponds to the screen
273 * coordinates <code>x, y</code> >= 0
275 public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
277 if (x >= 0 && y >= 0)
279 Rectangle r = getInsideAllocation(a);
280 View view = getViewAtPoint((int) x, (int) y, r);
281 return view.viewToModel(x, y, a, b);
283 return 0;
287 * Returns the next model location that is visible in eiter north / south
288 * direction or east / west direction. This is used to determine the placement
289 * of the caret when navigating around the document with the arrow keys. This
290 * is a convenience method for {@link #getNextNorthSouthVisualPositionFrom}
291 * and {@link #getNextEastWestVisualPositionFrom}.
293 * @param pos
294 * the model position to start search from
295 * @param b
296 * the bias for <code>pos</code>
297 * @param a
298 * the allocated region for this view
299 * @param direction
300 * the direction from the current position, can be one of the
301 * following:
302 * <ul>
303 * <li>{@link SwingConstants#WEST}</li>
304 * <li>{@link SwingConstants#EAST}</li>
305 * <li>{@link SwingConstants#NORTH}</li>
306 * <li>{@link SwingConstants#SOUTH}</li>
307 * </ul>
308 * @param biasRet
309 * the bias of the return value gets stored here
310 * @return the position inside the model that represents the next visual
311 * location
312 * @throws BadLocationException
313 * if <code>pos</code> is not a valid location inside the document
314 * model
315 * @throws IllegalArgumentException
316 * if <code>direction</code> is invalid
318 public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
319 int direction, Position.Bias[] biasRet)
320 throws BadLocationException
322 int retVal = -1;
323 switch (direction)
325 case SwingConstants.WEST:
326 case SwingConstants.EAST:
327 retVal = getNextEastWestVisualPositionFrom(pos, b, a, direction,
328 biasRet);
329 break;
330 case SwingConstants.NORTH:
331 case SwingConstants.SOUTH:
332 retVal = getNextNorthSouthVisualPositionFrom(pos, b, a, direction,
333 biasRet);
334 break;
335 default:
336 throw new IllegalArgumentException("Illegal value for direction.");
338 return retVal;
342 * Returns the index of the child view that represents the specified
343 * model location.
345 * @param pos the model location for which to determine the child view index
346 * @param b the bias to be applied to <code>pos</code>
348 * @return the index of the child view that represents the specified
349 * model location
351 public int getViewIndex(int pos, Position.Bias b)
353 // FIXME: Handle bias somehow.
354 return getViewIndexAtPosition(pos);
358 * Returns <code>true</code> if the specified point lies before the
359 * given <code>Rectangle</code>, <code>false</code> otherwise.
361 * &quot;Before&quot; is typically defined as being to the left or above.
363 * @param x the X coordinate of the point
364 * @param y the Y coordinate of the point
365 * @param r the rectangle to test the point against
367 * @return <code>true</code> if the specified point lies before the
368 * given <code>Rectangle</code>, <code>false</code> otherwise
370 protected abstract boolean isBefore(int x, int y, Rectangle r);
373 * Returns <code>true</code> if the specified point lies after the
374 * given <code>Rectangle</code>, <code>false</code> otherwise.
376 * &quot;After&quot; is typically defined as being to the right or below.
378 * @param x the X coordinate of the point
379 * @param y the Y coordinate of the point
380 * @param r the rectangle to test the point against
382 * @return <code>true</code> if the specified point lies after the
383 * given <code>Rectangle</code>, <code>false</code> otherwise
385 protected abstract boolean isAfter(int x, int y, Rectangle r);
388 * Returns the child <code>View</code> at the specified location.
390 * @param x the X coordinate
391 * @param y the Y coordinate
392 * @param r the inner allocation of this <code>BoxView</code> on entry,
393 * the allocation of the found child on exit
395 * @return the child <code>View</code> at the specified location
397 protected abstract View getViewAtPoint(int x, int y, Rectangle r);
400 * Computes the allocation for a child <code>View</code>. The parameter
401 * <code>a</code> stores the allocation of this <code>CompositeView</code>
402 * and is then adjusted to hold the allocation of the child view.
404 * @param index the index of the child <code>View</code>
405 * @param a the allocation of this <code>CompositeView</code> before the
406 * call, the allocation of the child on exit
408 protected abstract void childAllocation(int index, Rectangle a);
411 * Returns the child <code>View</code> that contains the given model
412 * position. The given <code>Rectangle</code> gives the parent's allocation
413 * and is changed to the child's allocation on exit.
415 * @param pos the model position to query the child <code>View</code> for
416 * @param a the parent allocation on entry and the child allocation on exit
418 * @return the child view at the given model position
420 protected View getViewAtPosition(int pos, Rectangle a)
422 int i = getViewIndexAtPosition(pos);
423 View view = children[i];
424 childAllocation(i, a);
425 return view;
429 * Returns the index of the child <code>View</code> for the given model
430 * position.
432 * @param pos the model position for whicht the child <code>View</code> is
433 * queried
435 * @return the index of the child <code>View</code> for the given model
436 * position
438 protected int getViewIndexAtPosition(int pos)
440 int index = -1;
441 for (int i = 0; i < children.length; i++)
443 if (children[i].getStartOffset() <= pos
444 && children[i].getEndOffset() > pos)
446 index = i;
447 break;
450 return index;
454 * Returns the allocation that is given to this <code>CompositeView</code>
455 * minus this <code>CompositeView</code>'s insets.
457 * Also this translates from an immutable allocation to a mutable allocation
458 * that is typically reused and further narrowed, like in
459 * {@link #childAllocation}.
461 * @param a the allocation given to this <code>CompositeView</code>
463 * @return the allocation that is given to this <code>CompositeView</code>
464 * minus this <code>CompositeView</code>'s insets or
465 * <code>null</code> if a was <code>null</code>
467 protected Rectangle getInsideAllocation(Shape a)
469 if (a == null)
470 return null;
472 Rectangle alloc = a.getBounds();
473 // Initialize the inside allocation rectangle. This is done inside
474 // a synchronized block in order to avoid multiple threads creating
475 // this instance simultanously.
476 Rectangle inside;
477 synchronized(this)
479 inside = insideAllocation;
480 if (inside == null)
482 inside = new Rectangle();
483 insideAllocation = inside;
486 inside.x = alloc.x + insets.left;
487 inside.y = alloc.y + insets.top;
488 inside.width = alloc.width - insets.left - insets.right;
489 inside.height = alloc.height - insets.top - insets.bottom;
490 return inside;
494 * Sets the insets defined by attributes in <code>attributes</code>. This
495 * queries the attribute keys {@link StyleConstants#SpaceAbove},
496 * {@link StyleConstants#SpaceBelow}, {@link StyleConstants#LeftIndent} and
497 * {@link StyleConstants#RightIndent} and calls {@link #setInsets} to
498 * actually set the insets on this <code>CompositeView</code>.
500 * @param attributes the attributes from which to query the insets
502 protected void setParagraphInsets(AttributeSet attributes)
504 Float l = (Float) attributes.getAttribute(StyleConstants.LeftIndent);
505 short left = 0;
506 if (l != null)
507 left = l.shortValue();
508 Float r = (Float) attributes.getAttribute(StyleConstants.RightIndent);
509 short right = 0;
510 if (r != null)
511 right = r.shortValue();
512 Float t = (Float) attributes.getAttribute(StyleConstants.SpaceAbove);
513 short top = 0;
514 if (t != null)
515 top = t.shortValue();
516 Float b = (Float) attributes.getAttribute(StyleConstants.SpaceBelow);
517 short bottom = 0;
518 if (b != null)
519 bottom = b.shortValue();
520 setInsets(top, left, bottom, right);
524 * Sets the insets of this <code>CompositeView</code>.
526 * @param top the top inset
527 * @param left the left inset
528 * @param bottom the bottom inset
529 * @param right the right inset
531 protected void setInsets(short top, short left, short bottom, short right)
533 insets.top = top;
534 insets.left = left;
535 insets.bottom = bottom;
536 insets.right = right;
540 * Returns the left inset of this <code>CompositeView</code>.
542 * @return the left inset of this <code>CompositeView</code>
544 protected short getLeftInset()
546 return (short) insets.left;
550 * Returns the right inset of this <code>CompositeView</code>.
552 * @return the right inset of this <code>CompositeView</code>
554 protected short getRightInset()
556 return (short) insets.right;
560 * Returns the top inset of this <code>CompositeView</code>.
562 * @return the top inset of this <code>CompositeView</code>
564 protected short getTopInset()
566 return (short) insets.top;
570 * Returns the bottom inset of this <code>CompositeView</code>.
572 * @return the bottom inset of this <code>CompositeView</code>
574 protected short getBottomInset()
576 return (short) insets.bottom;
580 * Returns the next model location that is visible in north or south
581 * direction.
582 * This is used to determine the
583 * placement of the caret when navigating around the document with
584 * the arrow keys.
586 * @param pos the model position to start search from
587 * @param b the bias for <code>pos</code>
588 * @param a the allocated region for this view
589 * @param direction the direction from the current position, can be one of
590 * the following:
591 * <ul>
592 * <li>{@link SwingConstants#NORTH}</li>
593 * <li>{@link SwingConstants#SOUTH}</li>
594 * </ul>
595 * @param biasRet the bias of the return value gets stored here
597 * @return the position inside the model that represents the next visual
598 * location
600 * @throws BadLocationException if <code>pos</code> is not a valid location
601 * inside the document model
602 * @throws IllegalArgumentException if <code>direction</code> is invalid
604 protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b,
605 Shape a, int direction,
606 Position.Bias[] biasRet)
607 throws BadLocationException
609 // FIXME: Implement this correctly.
610 return pos;
614 * Returns the next model location that is visible in east or west
615 * direction.
616 * This is used to determine the
617 * placement of the caret when navigating around the document with
618 * the arrow keys.
620 * @param pos the model position to start search from
621 * @param b the bias for <code>pos</code>
622 * @param a the allocated region for this view
623 * @param direction the direction from the current position, can be one of
624 * the following:
625 * <ul>
626 * <li>{@link SwingConstants#EAST}</li>
627 * <li>{@link SwingConstants#WEST}</li>
628 * </ul>
629 * @param biasRet the bias of the return value gets stored here
631 * @return the position inside the model that represents the next visual
632 * location
634 * @throws BadLocationException if <code>pos</code> is not a valid location
635 * inside the document model
636 * @throws IllegalArgumentException if <code>direction</code> is invalid
638 protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b,
639 Shape a, int direction,
640 Position.Bias[] biasRet)
641 throws BadLocationException
643 // FIXME: Implement this correctly.
644 return pos;
648 * Determines if the next view in horinzontal direction is located to
649 * the east or west of the view at position <code>pos</code>. Usually
650 * the <code>View</code>s are laid out from the east to the west, so
651 * we unconditionally return <code>false</code> here. Subclasses that
652 * support bidirectional text may wish to override this method.
654 * @param pos the position in the document
655 * @param bias the bias to be applied to <code>pos</code>
657 * @return <code>true</code> if the next <code>View</code> is located
658 * to the EAST, <code>false</code> otherwise
660 protected boolean flipEastAndWestAtEnds(int pos, Position.Bias bias)
662 return false;