Merge from mainline.
[official-gcc.git] / libjava / classpath / javax / swing / text / View.java
blobd8ad5f5858e2f62481768657e9a572539f474d96
1 /* View.java --
2 Copyright (C) 2002, 2004, 2005, 2006 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.Container;
42 import java.awt.Graphics;
43 import java.awt.Rectangle;
44 import java.awt.Shape;
46 import javax.swing.SwingConstants;
47 import javax.swing.SwingUtilities;
48 import javax.swing.event.DocumentEvent;
50 public abstract class View implements SwingConstants
52 public static final int BadBreakWeight = 0;
53 public static final int ExcellentBreakWeight = 2000;
54 public static final int ForcedBreakWeight = 3000;
55 public static final int GoodBreakWeight = 1000;
57 public static final int X_AXIS = 0;
58 public static final int Y_AXIS = 1;
60 private float width, height;
61 private Element elt;
62 private View parent;
64 /**
65 * Creates a new <code>View</code> instance.
67 * @param elem an <code>Element</code> value
69 public View(Element elem)
71 elt = elem;
74 public abstract void paint(Graphics g, Shape s);
76 /**
77 * Sets the parent for this view. This is the first method that is beeing
78 * called on a view to setup the view hierarchy. This is also the last method
79 * beeing called when the view is disconnected from the view hierarchy, in
80 * this case <code>parent</code> is null.
82 * If <code>parent</code> is <code>null</code>, a call to this method also
83 * calls <code>setParent</code> on the children, thus disconnecting them from
84 * the view hierarchy. That means that super must be called when this method
85 * is overridden.
87 * @param parent the parent to set, <code>null</code> when this view is
88 * beeing disconnected from the view hierarchy
90 public void setParent(View parent)
92 if (parent == null)
94 int numChildren = getViewCount();
95 for (int i = 0; i < numChildren; i++)
96 getView(i).setParent(null);
99 this.parent = parent;
102 public View getParent()
104 return parent;
107 public Container getContainer()
109 View parent = getParent();
110 if (parent == null)
111 return null;
112 else
113 return parent.getContainer();
116 public Document getDocument()
118 return getElement().getDocument();
121 public Element getElement()
123 return elt;
127 * Returns the preferred span along the specified axis. Normally the view is
128 * rendered with the span returned here if that is possible.
130 * @param axis the axis
132 * @return the preferred span along the specified axis
134 public abstract float getPreferredSpan(int axis);
137 * Returns the resize weight of this view. A value of <code>0</code> or less
138 * means this view is not resizeable. Positive values make the view
139 * resizeable. The default implementation returns <code>0</code>
140 * unconditionally.
142 * @param axis the axis
144 * @return the resizability of this view along the specified axis
146 public int getResizeWeight(int axis)
148 return 0;
152 * Returns the maximum span along the specified axis. The default
153 * implementation will forward to
154 * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)}
155 * returns a value > 0, in which case this returns {@link Integer#MIN_VALUE}.
157 * @param axis the axis
159 * @return the maximum span along the specified axis
161 public float getMaximumSpan(int axis)
163 float max = Integer.MAX_VALUE;
164 if (getResizeWeight(axis) <= 0)
165 max = getPreferredSpan(axis);
166 return max;
170 * Returns the minimum span along the specified axis. The default
171 * implementation will forward to
172 * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)}
173 * returns a value > 0, in which case this returns <code>0</code>.
175 * @param axis the axis
177 * @return the minimum span along the specified axis
179 public float getMinimumSpan(int axis)
181 float min = 0;
182 if (getResizeWeight(axis) <= 0)
183 min = getPreferredSpan(axis);
184 return min;
187 public void setSize(float width, float height)
189 // The default implementation does nothing.
193 * Returns the alignment of this view along the baseline of the parent view.
194 * An alignment of <code>0.0</code> will align this view with the left edge
195 * along the baseline, an alignment of <code>0.5</code> will align it
196 * centered to the baseline, an alignment of <code>1.0</code> will align
197 * the right edge along the baseline.
199 * The default implementation returns 0.5 unconditionally.
201 * @param axis the axis
203 * @return the alignment of this view along the parents baseline for the
204 * specified axis
206 public float getAlignment(int axis)
208 return 0.5f;
211 public AttributeSet getAttributes()
213 return getElement().getAttributes();
216 public boolean isVisible()
218 return true;
221 public int getViewCount()
223 return 0;
226 public View getView(int index)
228 return null;
231 public ViewFactory getViewFactory()
233 View parent = getParent();
234 return parent != null ? parent.getViewFactory() : null;
238 * Replaces a couple of child views with new child views. If
239 * <code>length == 0</code> then this is a simple insertion, if
240 * <code>views == null</code> this only removes some child views.
242 * @param offset the offset at which to replace
243 * @param length the number of child views to be removed
244 * @param views the new views to be inserted, may be <code>null</code>
246 public void replace(int offset, int length, View[] views)
248 // Default implementation does nothing.
251 public void insert(int offset, View view)
253 View[] array = { view };
254 replace(offset, 1, array);
257 public void append(View view)
259 View[] array = { view };
260 int offset = getViewCount();
261 replace(offset, 0, array);
264 public void removeAll()
266 replace(0, getViewCount(), new View[0]);
269 public void remove(int index)
271 replace(index, 1, null);
274 public View createFragment(int p0, int p1)
276 // The default implementation doesn't support fragmentation.
277 return this;
280 public int getStartOffset()
282 return getElement().getStartOffset();
285 public int getEndOffset()
287 return getElement().getEndOffset();
290 public Shape getChildAllocation(int index, Shape a)
292 return null;
296 * @since 1.4
298 public int getViewIndex(float x, float y, Shape allocation)
300 return -1;
304 * @since 1.4
306 public String getToolTipText(float x, float y, Shape allocation)
308 int index = getViewIndex(x, y, allocation);
310 if (index < -1)
311 return null;
313 Shape childAllocation = getChildAllocation(index, allocation);
315 if (childAllocation.getBounds().contains(x, y))
316 return getView(index).getToolTipText(x, y, childAllocation);
318 return null;
322 * @since 1.3
324 public Graphics getGraphics()
326 return getContainer().getGraphics();
329 public void preferenceChanged(View child, boolean width, boolean height)
331 if (parent != null)
332 parent.preferenceChanged(this, width, height);
335 public int getBreakWeight(int axis, float pos, float len)
337 return BadBreakWeight;
340 public View breakView(int axis, int offset, float pos, float len)
342 return this;
346 * @since 1.3
348 public int getViewIndex(int pos, Position.Bias b)
350 return -1;
354 * Receive notification about an insert update to the text model.
356 * The default implementation of this method does the following:
357 * <ul>
358 * <li>Call {@link #updateChildren} if the element that this view is
359 * responsible for has changed. This makes sure that the children can
360 * correctly represent the model.<li>
361 * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to
362 * the child views.<li>
363 * <li>Call {@link #updateLayout}. Gives the view a chance to either
364 * repair its layout, reschedule layout or do nothing at all.</li>
365 * </ul>
367 * @param ev the DocumentEvent that describes the change
368 * @param shape the shape of the view
369 * @param vf the ViewFactory for creating child views
371 public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
373 Element el = getElement();
374 DocumentEvent.ElementChange ec = ev.getChange(el);
375 if (ec != null)
376 updateChildren(ec, ev, vf);
377 forwardUpdate(ec, ev, shape, vf);
378 updateLayout(ec, ev, shape);
382 * Receive notification about a remove update to the text model.
384 * The default implementation of this method does the following:
385 * <ul>
386 * <li>Call {@link #updateChildren} if the element that this view is
387 * responsible for has changed. This makes sure that the children can
388 * correctly represent the model.<li>
389 * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to
390 * the child views.<li>
391 * <li>Call {@link #updateLayout}. Gives the view a chance to either
392 * repair its layout, reschedule layout or do nothing at all.</li>
393 * </ul>
395 * @param ev the DocumentEvent that describes the change
396 * @param shape the shape of the view
397 * @param vf the ViewFactory for creating child views
399 public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
401 Element el = getElement();
402 DocumentEvent.ElementChange ec = ev.getChange(el);
403 if (ec != null)
404 updateChildren(ec, ev, vf);
405 forwardUpdate(ec, ev, shape, vf);
406 updateLayout(ec, ev, shape);
410 * Receive notification about a change update to the text model.
412 * The default implementation of this method does the following:
413 * <ul>
414 * <li>Call {@link #updateChildren} if the element that this view is
415 * responsible for has changed. This makes sure that the children can
416 * correctly represent the model.<li>
417 * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to
418 * the child views.<li>
419 * <li>Call {@link #updateLayout}. Gives the view a chance to either
420 * repair its layout, reschedule layout or do nothing at all.</li>
421 * </ul>
423 * @param ev the DocumentEvent that describes the change
424 * @param shape the shape of the view
425 * @param vf the ViewFactory for creating child views
427 public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
429 Element el = getElement();
430 DocumentEvent.ElementChange ec = ev.getChange(el);
431 if (ec != null)
432 updateChildren(ec, ev, vf);
433 forwardUpdate(ec, ev, shape, vf);
434 updateLayout(ec, ev, shape);
438 * Updates the list of children that is returned by {@link #getView}
439 * and {@link #getViewCount}.
441 * Element that are specified as beeing added in the ElementChange record are
442 * assigned a view for using the ViewFactory. Views of Elements that
443 * are specified as beeing removed are removed from the list.
445 * @param ec the ElementChange record that describes the change of the
446 * element
447 * @param ev the DocumentEvent describing the change of the document model
448 * @param vf the ViewFactory to use for creating new views
450 * @return whether or not the child views represent the child elements of
451 * the element that this view is responsible for. Some views may
452 * create views that are responsible only for parts of the element
453 * that they are responsible for and should then return false.
455 * @since 1.3
457 protected boolean updateChildren(DocumentEvent.ElementChange ec,
458 DocumentEvent ev,
459 ViewFactory vf)
461 Element[] added = ec.getChildrenAdded();
462 Element[] removed = ec.getChildrenRemoved();
463 int index = ec.getIndex();
465 View[] newChildren = new View[added.length];
466 for (int i = 0; i < added.length; ++i)
467 newChildren[i] = vf.create(added[i]);
468 replace(index, removed.length, newChildren);
470 return true;
474 * Forwards the DocumentEvent to child views that need to get notified
475 * of the change to the model. This calles {@link #forwardUpdateToView}
476 * for each View that must be forwarded to.
478 * If <code>ec</code> is not <code>null</code> (this means there have been
479 * structural changes to the element that this view is responsible for) this
480 * method should recognize this and don't notify newly added child views.
482 * @param ec the ElementChange describing the element changes (may be
483 * <code>null</code> if there were no changes)
484 * @param ev the DocumentEvent describing the changes to the model
485 * @param shape the current allocation of the view
486 * @param vf the ViewFactory used to create new Views
488 * @since 1.3
490 protected void forwardUpdate(DocumentEvent.ElementChange ec,
491 DocumentEvent ev, Shape shape, ViewFactory vf)
493 int count = getViewCount();
494 if (count > 0)
496 int startOffset = ev.getOffset();
497 int endOffset = startOffset + ev.getLength();
498 int startIndex = getViewIndex(startOffset, Position.Bias.Backward);
499 int endIndex = getViewIndex(endOffset, Position.Bias.Forward);
500 int index = -1;
501 int addLength = -1;
502 if (ec != null)
504 index = ec.getIndex();
505 addLength = ec.getChildrenAdded().length;
508 if (startIndex >= 0 && endIndex >= 0)
510 for (int i = startIndex; i <= endIndex; i++)
512 // Skip newly added child views.
513 if (index >= 0 && i >= index && i < (index+addLength))
514 continue;
515 View child = getView(i);
516 forwardUpdateToView(child, ev, shape, vf);
523 * Forwards an update event to the given child view. This calls
524 * {@link #insertUpdate}, {@link #removeUpdate} or {@link #changedUpdate},
525 * depending on the type of document event.
527 * @param view the View to forward the event to
528 * @param ev the DocumentEvent to forward
529 * @param shape the current allocation of the View
530 * @param vf the ViewFactory used to create new Views
532 * @since 1.3
534 protected void forwardUpdateToView(View view, DocumentEvent ev, Shape shape,
535 ViewFactory vf)
537 DocumentEvent.EventType type = ev.getType();
538 if (type == DocumentEvent.EventType.INSERT)
539 view.insertUpdate(ev, shape, vf);
540 else if (type == DocumentEvent.EventType.REMOVE)
541 view.removeUpdate(ev, shape, vf);
542 else if (type == DocumentEvent.EventType.CHANGE)
543 view.changedUpdate(ev, shape, vf);
547 * Updates the layout.
549 * @param ec the ElementChange that describes the changes to the element
550 * @param ev the DocumentEvent that describes the changes to the model
551 * @param shape the current allocation for this view
553 * @since 1.3
555 protected void updateLayout(DocumentEvent.ElementChange ec,
556 DocumentEvent ev, Shape shape)
558 if (ec != null && shape != null)
559 preferenceChanged(null, true, true);
560 Container c = getContainer();
561 if (c != null)
562 c.repaint();
566 * Maps a position in the document into the coordinate space of the View.
567 * The output rectangle usually reflects the font height but has a width
568 * of zero.
570 * @param pos the position of the character in the model
571 * @param a the area that is occupied by the view
572 * @param b either {@link Position.Bias#Forward} or
573 * {@link Position.Bias#Backward} depending on the preferred
574 * direction bias. If <code>null</code> this defaults to
575 * <code>Position.Bias.Forward</code>
577 * @return a rectangle that gives the location of the document position
578 * inside the view coordinate space
580 * @throws BadLocationException if <code>pos</code> is invalid
581 * @throws IllegalArgumentException if b is not one of the above listed
582 * valid values
584 public abstract Shape modelToView(int pos, Shape a, Position.Bias b)
585 throws BadLocationException;
588 * Maps a region in the document into the coordinate space of the View.
590 * @param p1 the beginning position inside the document
591 * @param b1 the direction bias for the beginning position
592 * @param p2 the end position inside the document
593 * @param b2 the direction bias for the end position
594 * @param a the area that is occupied by the view
596 * @return a rectangle that gives the span of the document region
597 * inside the view coordinate space
599 * @throws BadLocationException if <code>p1</code> or <code>p2</code> are
600 * invalid
601 * @throws IllegalArgumentException if b1 or b2 is not one of the above
602 * listed valid values
604 public Shape modelToView(int p1, Position.Bias b1,
605 int p2, Position.Bias b2, Shape a)
606 throws BadLocationException
608 if (b1 != Position.Bias.Forward && b1 != Position.Bias.Backward)
609 throw new IllegalArgumentException
610 ("b1 must be either Position.Bias.Forward or Position.Bias.Backward");
611 if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward)
612 throw new IllegalArgumentException
613 ("b2 must be either Position.Bias.Forward or Position.Bias.Backward");
614 Rectangle s1 = (Rectangle) modelToView(p1, a, b1);
615 Rectangle s2 = (Rectangle) modelToView(p2, a, b2);
616 return SwingUtilities.computeUnion(s1.x, s1.y, s1.width, s1.height, s2);
620 * Maps a position in the document into the coordinate space of the View.
621 * The output rectangle usually reflects the font height but has a width
622 * of zero.
624 * This method is deprecated and calls
625 * {@link #modelToView(int, Position.Bias, int, Position.Bias, Shape)} with
626 * a bias of {@link Position.Bias#Forward}.
628 * @param pos the position of the character in the model
629 * @param a the area that is occupied by the view
631 * @return a rectangle that gives the location of the document position
632 * inside the view coordinate space
634 * @throws BadLocationException if <code>pos</code> is invalid
636 * @deprecated Use {@link #modelToView(int, Shape, Position.Bias)} instead.
638 public Shape modelToView(int pos, Shape a) throws BadLocationException
640 return modelToView(pos, a, Position.Bias.Forward);
644 * Maps coordinates from the <code>View</code>'s space into a position
645 * in the document model.
647 * @param x the x coordinate in the view space
648 * @param y the y coordinate in the view space
649 * @param a the allocation of this <code>View</code>
650 * @param b the bias to use
652 * @return the position in the document that corresponds to the screen
653 * coordinates <code>x, y</code>
655 public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] b);
658 * Maps coordinates from the <code>View</code>'s space into a position
659 * in the document model. This method is deprecated and only there for
660 * compatibility.
662 * @param x the x coordinate in the view space
663 * @param y the y coordinate in the view space
664 * @param a the allocation of this <code>View</code>
666 * @return the position in the document that corresponds to the screen
667 * coordinates <code>x, y</code>
669 * @deprecated Use {@link #viewToModel(float, float, Shape, Position.Bias[])}
670 * instead.
672 public int viewToModel(float x, float y, Shape a)
674 return viewToModel(x, y, a, new Position.Bias[0]);
678 * Dumps the complete View hierarchy. This method can be used for debugging
679 * purposes.
681 protected void dump()
683 // Climb up the hierarchy to the parent.
684 View parent = getParent();
685 if (parent != null)
686 parent.dump();
687 else
688 dump(0);
692 * Dumps the view hierarchy below this View with the specified indentation
693 * level.
695 * @param indent the indentation level to be used for this view
697 void dump(int indent)
699 for (int i = 0; i < indent; ++i)
700 System.out.print('.');
701 System.out.println(this + "(" + getStartOffset() + "," + getEndOffset() + ": " + getElement());
703 int count = getViewCount();
704 for (int i = 0; i < count; ++i)
705 getView(i).dump(indent + 1);
709 * Returns the document position that is (visually) nearest to the given
710 * document position <code>pos</code> in the given direction <code>d</code>.
712 * @param pos the document position
713 * @param b the bias for <code>pos</code>
714 * @param a the allocation for this view
715 * @param d the direction, must be either {@link SwingConstants#NORTH},
716 * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
717 * {@link SwingConstants#EAST}
718 * @param biasRet an array of {@link Position.Bias} that can hold at least
719 * one element, which is filled with the bias of the return position
720 * on method exit
722 * @return the document position that is (visually) nearest to the given
723 * document position <code>pos</code> in the given direction
724 * <code>d</code>
726 * @throws BadLocationException if <code>pos</code> is not a valid offset in
727 * the document model
728 * @throws IllegalArgumentException if <code>d</code> is not a valid direction
730 public int getNextVisualPositionFrom(int pos, Position.Bias b,
731 Shape a, int d,
732 Position.Bias[] biasRet)
733 throws BadLocationException
735 int ret = pos;
736 Rectangle r;
737 View parent;
739 switch (d)
741 case EAST:
742 // TODO: take component orientation into account?
743 // Note: If pos is below zero the implementation will return
744 // pos + 1 regardless of whether that value is a correct offset
745 // in the document model. However this is what the RI does.
746 ret = Math.min(pos + 1, getEndOffset());
747 break;
748 case WEST:
749 // TODO: take component orientation into account?
750 ret = Math.max(pos - 1, getStartOffset());
751 break;
752 case NORTH:
753 // Try to find a suitable offset by examining the area above.
754 parent = getParent();
755 r = parent.modelToView(pos, a, b).getBounds();
756 ret = parent.viewToModel(r.x, r.y - 1, a, biasRet);
757 break;
758 case SOUTH:
759 // Try to find a suitable offset by examining the area below.
760 parent = getParent();
761 r = parent.modelToView(pos, a, b).getBounds();
762 ret = parent.viewToModel(r.x + r.width, r.y + r.height, a, biasRet);
763 break;
764 default:
765 throw new IllegalArgumentException("Illegal value for d");
768 return ret;