Frames | No Frames |
1: /* View.java -- 2: Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 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. 10: 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. 15: 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. 20: 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. 25: 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. */ 37: 38: 39: package javax.swing.text; 40: 41: import java.awt.Container; 42: import java.awt.Graphics; 43: import java.awt.Rectangle; 44: import java.awt.Shape; 45: 46: import javax.swing.SwingConstants; 47: import javax.swing.event.DocumentEvent; 48: 49: public abstract class View implements SwingConstants 50: { 51: public static final int BadBreakWeight = 0; 52: public static final int ExcellentBreakWeight = 2000; 53: public static final int ForcedBreakWeight = 3000; 54: public static final int GoodBreakWeight = 1000; 55: 56: public static final int X_AXIS = 0; 57: public static final int Y_AXIS = 1; 58: 59: private float width, height; 60: private Element elt; 61: private View parent; 62: 63: /** 64: * Creates a new <code>View</code> instance. 65: * 66: * @param elem an <code>Element</code> value 67: */ 68: public View(Element elem) 69: { 70: elt = elem; 71: } 72: 73: public abstract void paint(Graphics g, Shape s); 74: 75: public void setParent(View parent) 76: { 77: this.parent = parent; 78: } 79: 80: public View getParent() 81: { 82: return parent; 83: } 84: 85: public Container getContainer() 86: { 87: View parent = getParent(); 88: if (parent == null) 89: return null; 90: else 91: return parent.getContainer(); 92: } 93: 94: public Document getDocument() 95: { 96: return getElement().getDocument(); 97: } 98: 99: public Element getElement() 100: { 101: return elt; 102: } 103: 104: public abstract float getPreferredSpan(int axis); 105: 106: public int getResizeWeight(int axis) 107: { 108: return 0; 109: } 110: 111: public float getMaximumSpan(int axis) 112: { 113: if (getResizeWeight(axis) <= 0) 114: return getPreferredSpan(axis); 115: 116: return Integer.MAX_VALUE; 117: } 118: 119: public float getMinimumSpan(int axis) 120: { 121: if (getResizeWeight(axis) <= 0) 122: return getPreferredSpan(axis); 123: 124: return Integer.MAX_VALUE; 125: } 126: 127: public void setSize(float width, float height) 128: { 129: // The default implementation does nothing. 130: } 131: 132: public float getAlignment(int axis) 133: { 134: return 0.5f; 135: } 136: 137: public AttributeSet getAttributes() 138: { 139: return getElement().getAttributes(); 140: } 141: 142: public boolean isVisible() 143: { 144: return true; 145: } 146: 147: public int getViewCount() 148: { 149: return 0; 150: } 151: 152: public View getView(int index) 153: { 154: return null; 155: } 156: 157: public ViewFactory getViewFactory() 158: { 159: View parent = getParent(); 160: return parent != null ? parent.getViewFactory() : null; 161: } 162: 163: public void replace(int offset, int length, View[] views) 164: { 165: // Default implementation does nothing. 166: } 167: 168: public void insert(int offset, View view) 169: { 170: View[] array = { view }; 171: replace(offset, 1, array); 172: } 173: 174: public void append(View view) 175: { 176: View[] array = { view }; 177: int offset = getViewCount(); 178: replace(offset, 0, array); 179: } 180: 181: public void removeAll() 182: { 183: replace(0, getViewCount(), new View[0]); 184: } 185: 186: public void remove(int index) 187: { 188: replace(index, 1, null); 189: } 190: 191: public View createFragment(int p0, int p1) 192: { 193: // The default implementation doesn't support fragmentation. 194: return this; 195: } 196: 197: public int getStartOffset() 198: { 199: return getElement().getStartOffset(); 200: } 201: 202: public int getEndOffset() 203: { 204: return getElement().getEndOffset(); 205: } 206: 207: public Shape getChildAllocation(int index, Shape a) 208: { 209: return null; 210: } 211: 212: /** 213: * @since 1.4 214: */ 215: public int getViewIndex(float x, float y, Shape allocation) 216: { 217: return -1; 218: } 219: 220: /** 221: * @since 1.4 222: */ 223: public String getToolTipText(float x, float y, Shape allocation) 224: { 225: int index = getViewIndex(x, y, allocation); 226: 227: if (index < -1) 228: return null; 229: 230: Shape childAllocation = getChildAllocation(index, allocation); 231: 232: if (childAllocation.getBounds().contains(x, y)) 233: return getView(index).getToolTipText(x, y, childAllocation); 234: 235: return null; 236: } 237: 238: /** 239: * @since 1.3 240: */ 241: public Graphics getGraphics() 242: { 243: return getContainer().getGraphics(); 244: } 245: 246: public void preferenceChanged(View child, boolean width, boolean height) 247: { 248: if (parent != null) 249: parent.preferenceChanged(this, width, height); 250: } 251: 252: public int getBreakWeight(int axis, float pos, float len) 253: { 254: return BadBreakWeight; 255: } 256: 257: public View breakView(int axis, int offset, float pos, float len) 258: { 259: return this; 260: } 261: 262: /** 263: * @since 1.3 264: */ 265: public int getViewIndex(int pos, Position.Bias b) 266: { 267: return -1; 268: } 269: 270: /** 271: * Receive notification about an insert update to the text model. 272: * 273: * The default implementation of this method does the following: 274: * <ul> 275: * <li>Call {@link #updateChildren} if the element that this view is 276: * responsible for has changed. This makes sure that the children can 277: * correctly represent the model.<li> 278: * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to 279: * the child views.<li> 280: * <li>Call {@link #updateLayout}. Gives the view a chance to either 281: * repair its layout, reschedule layout or do nothing at all.</li> 282: * </ul> 283: * 284: * @param ev the DocumentEvent that describes the change 285: * @param shape the shape of the view 286: * @param vf the ViewFactory for creating child views 287: */ 288: public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) 289: { 290: Element el = getElement(); 291: DocumentEvent.ElementChange ec = ev.getChange(el); 292: if (ec != null) 293: updateChildren(ec, ev, vf); 294: forwardUpdate(ec, ev, shape, vf); 295: updateLayout(ec, ev, shape); 296: } 297: 298: /** 299: * Receive notification about a remove update to the text model. 300: * 301: * The default implementation of this method does the following: 302: * <ul> 303: * <li>Call {@link #updateChildren} if the element that this view is 304: * responsible for has changed. This makes sure that the children can 305: * correctly represent the model.<li> 306: * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to 307: * the child views.<li> 308: * <li>Call {@link #updateLayout}. Gives the view a chance to either 309: * repair its layout, reschedule layout or do nothing at all.</li> 310: * </ul> 311: * 312: * @param ev the DocumentEvent that describes the change 313: * @param shape the shape of the view 314: * @param vf the ViewFactory for creating child views 315: */ 316: public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) 317: { 318: Element el = getElement(); 319: DocumentEvent.ElementChange ec = ev.getChange(el); 320: if (ec != null) 321: updateChildren(ec, ev, vf); 322: forwardUpdate(ec, ev, shape, vf); 323: updateLayout(ec, ev, shape); 324: } 325: 326: /** 327: * Receive notification about a change update to the text model. 328: * 329: * The default implementation of this method does the following: 330: * <ul> 331: * <li>Call {@link #updateChildren} if the element that this view is 332: * responsible for has changed. This makes sure that the children can 333: * correctly represent the model.<li> 334: * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to 335: * the child views.<li> 336: * <li>Call {@link #updateLayout}. Gives the view a chance to either 337: * repair its layout, reschedule layout or do nothing at all.</li> 338: * </ul> 339: * 340: * @param ev the DocumentEvent that describes the change 341: * @param shape the shape of the view 342: * @param vf the ViewFactory for creating child views 343: */ 344: public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) 345: { 346: Element el = getElement(); 347: DocumentEvent.ElementChange ec = ev.getChange(el); 348: if (ec != null) 349: updateChildren(ec, ev, vf); 350: forwardUpdate(ec, ev, shape, vf); 351: updateLayout(ec, ev, shape); 352: } 353: 354: /** 355: * Updates the list of children that is returned by {@link #getView} 356: * and {@link #getViewCount}. 357: * 358: * Element that are specified as beeing added in the ElementChange record are 359: * assigned a view for using the ViewFactory. Views of Elements that 360: * are specified as beeing removed are removed from the list. 361: * 362: * @param ec the ElementChange record that describes the change of the 363: * element 364: * @param ev the DocumentEvent describing the change of the document model 365: * @param vf the ViewFactory to use for creating new views 366: * 367: * @return whether or not the child views represent the child elements of 368: * the element that this view is responsible for. Some views may 369: * create views that are responsible only for parts of the element 370: * that they are responsible for and should then return false. 371: * 372: * @since 1.3 373: */ 374: protected boolean updateChildren(DocumentEvent.ElementChange ec, 375: DocumentEvent ev, 376: ViewFactory vf) 377: { 378: Element[] added = ec.getChildrenAdded(); 379: Element[] removed = ec.getChildrenRemoved(); 380: int index = ec.getIndex(); 381: 382: View[] newChildren = new View[added.length]; 383: for (int i = 0; i < added.length; ++i) 384: newChildren[i] = vf.create(added[i]); 385: replace(index, removed.length, newChildren); 386: 387: return true; 388: } 389: 390: /** 391: * Forwards the DocumentEvent to child views that need to get notified 392: * of the change to the model. This calles {@link #forwardUpdateToView} 393: * for each View that must be forwarded to. 394: * 395: * @param ec the ElementChange describing the element changes (may be 396: * <code>null</code> if there were no changes) 397: * @param ev the DocumentEvent describing the changes to the model 398: * @param shape the current allocation of the view 399: * @param vf the ViewFactory used to create new Views 400: * 401: * @since 1.3 402: */ 403: protected void forwardUpdate(DocumentEvent.ElementChange ec, 404: DocumentEvent ev, Shape shape, ViewFactory vf) 405: { 406: int count = getViewCount(); 407: for (int i = 0; i < count; i++) 408: { 409: View child = getView(i); 410: forwardUpdateToView(child, ev, shape, vf); 411: } 412: } 413: 414: /** 415: * Forwards an update event to the given child view. This calls 416: * {@link #insertUpdate}, {@link #removeUpdate} or {@link #changedUpdate}, 417: * depending on the type of document event. 418: * 419: * @param view the View to forward the event to 420: * @param ev the DocumentEvent to forward 421: * @param shape the current allocation of the View 422: * @param vf the ViewFactory used to create new Views 423: * 424: * @since 1.3 425: */ 426: protected void forwardUpdateToView(View view, DocumentEvent ev, Shape shape, 427: ViewFactory vf) 428: { 429: DocumentEvent.EventType type = ev.getType(); 430: if (type == DocumentEvent.EventType.INSERT) 431: view.insertUpdate(ev, shape, vf); 432: else if (type == DocumentEvent.EventType.REMOVE) 433: view.removeUpdate(ev, shape, vf); 434: else if (type == DocumentEvent.EventType.CHANGE) 435: view.changedUpdate(ev, shape, vf); 436: } 437: 438: /** 439: * Updates the layout. 440: * 441: * @param ec the ElementChange that describes the changes to the element 442: * @param ev the DocumentEvent that describes the changes to the model 443: * @param shape the current allocation for this view 444: * 445: * @since 1.3 446: */ 447: protected void updateLayout(DocumentEvent.ElementChange ec, 448: DocumentEvent ev, Shape shape) 449: { 450: Rectangle b = shape.getBounds(); 451: if (ec != null) 452: preferenceChanged(this, true, true); 453: } 454: 455: /** 456: * Maps a position in the document into the coordinate space of the View. 457: * The output rectangle usually reflects the font height but has a width 458: * of zero. 459: * 460: * @param pos the position of the character in the model 461: * @param a the area that is occupied by the view 462: * @param b either {@link Position.Bias#Forward} or 463: * {@link Position.Bias#Backward} depending on the preferred 464: * direction bias. If <code>null</code> this defaults to 465: * <code>Position.Bias.Forward</code> 466: * 467: * @return a rectangle that gives the location of the document position 468: * inside the view coordinate space 469: * 470: * @throws BadLocationException if <code>pos</code> is invalid 471: * @throws IllegalArgumentException if b is not one of the above listed 472: * valid values 473: */ 474: public abstract Shape modelToView(int pos, Shape a, Position.Bias b) 475: throws BadLocationException; 476: 477: /** 478: * Maps a region in the document into the coordinate space of the View. 479: * 480: * @param p1 the beginning position inside the document 481: * @param b1 the direction bias for the beginning position 482: * @param p2 the end position inside the document 483: * @param b2 the direction bias for the end position 484: * @param a the area that is occupied by the view 485: * 486: * @return a rectangle that gives the span of the document region 487: * inside the view coordinate space 488: * 489: * @throws BadLocationException if <code>p1</code> or <code>p2</code> are 490: * invalid 491: * @throws IllegalArgumentException if b1 or b2 is not one of the above 492: * listed valid values 493: */ 494: public Shape modelToView(int p1, Position.Bias b1, 495: int p2, Position.Bias b2, Shape a) 496: throws BadLocationException 497: { 498: if (b1 != Position.Bias.Forward && b1 != Position.Bias.Backward) 499: throw new IllegalArgumentException 500: ("b1 must be either Position.Bias.Forward or Position.Bias.Backward"); 501: if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward) 502: throw new IllegalArgumentException 503: ("b2 must be either Position.Bias.Forward or Position.Bias.Backward"); 504: Shape s1 = modelToView(p1, a, b1); 505: Shape s2 = modelToView(p2, a, b2); 506: return s1.getBounds().union(s2.getBounds()); 507: } 508: 509: /** 510: * Maps a position in the document into the coordinate space of the View. 511: * The output rectangle usually reflects the font height but has a width 512: * of zero. 513: * 514: * This method is deprecated and calls 515: * {@link #modelToView(int, Position.Bias, int, Position.Bias, Shape)} with 516: * a bias of {@link Position.Bias#Forward}. 517: * 518: * @param pos the position of the character in the model 519: * @param a the area that is occupied by the view 520: * 521: * @return a rectangle that gives the location of the document position 522: * inside the view coordinate space 523: * 524: * @throws BadLocationException if <code>pos</code> is invalid 525: * 526: * @deprecated Use {@link #modelToView(int, Shape, Position.Bias)} instead. 527: */ 528: public Shape modelToView(int pos, Shape a) throws BadLocationException 529: { 530: return modelToView(pos, a, Position.Bias.Forward); 531: } 532: 533: /** 534: * Maps coordinates from the <code>View</code>'s space into a position 535: * in the document model. 536: * 537: * @param x the x coordinate in the view space 538: * @param y the y coordinate in the view space 539: * @param a the allocation of this <code>View</code> 540: * @param b the bias to use 541: * 542: * @return the position in the document that corresponds to the screen 543: * coordinates <code>x, y</code> 544: */ 545: public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] b); 546: 547: /** 548: * Maps coordinates from the <code>View</code>'s space into a position 549: * in the document model. This method is deprecated and only there for 550: * compatibility. 551: * 552: * @param x the x coordinate in the view space 553: * @param y the y coordinate in the view space 554: * @param a the allocation of this <code>View</code> 555: * 556: * @return the position in the document that corresponds to the screen 557: * coordinates <code>x, y</code> 558: * 559: * @deprecated Use {@link #viewToModel(float, float, Shape, Position.Bias[])} 560: * instead. 561: */ 562: public int viewToModel(float x, float y, Shape a) 563: { 564: return viewToModel(x, y, a, new Position.Bias[0]); 565: } 566: 567: /** 568: * Dumps the complete View hierarchy. This method can be used for debugging 569: * purposes. 570: */ 571: void dump() 572: { 573: // Climb up the hierarchy to the parent. 574: View parent = getParent(); 575: if (parent != null) 576: parent.dump(); 577: else 578: dump(0); 579: } 580: 581: /** 582: * Dumps the view hierarchy below this View with the specified indentation 583: * level. 584: * 585: * @param indent the indentation level to be used for this view 586: */ 587: void dump(int indent) 588: { 589: for (int i = 0; i < indent; ++i) 590: System.out.print('.'); 591: System.out.println(this); 592: 593: int count = getViewCount(); 594: for (int i = 0; i < count; ++i) 595: getView(i).dump(indent + 1); 596: } 597: 598: /** 599: * Returns the document position that is (visually) nearest to the given 600: * document position <code>pos</code> in the given direction <code>d</code>. 601: * 602: * @param c the text component 603: * @param pos the document position 604: * @param b the bias for <code>pos</code> 605: * @param d the direction, must be either {@link SwingConstants#NORTH}, 606: * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or 607: * {@link SwingConstants#EAST} 608: * @param biasRet an array of {@link Position.Bias} that can hold at least 609: * one element, which is filled with the bias of the return position 610: * on method exit 611: * 612: * @return the document position that is (visually) nearest to the given 613: * document position <code>pos</code> in the given direction 614: * <code>d</code> 615: * 616: * @throws BadLocationException if <code>pos</code> is not a valid offset in 617: * the document model 618: */ 619: public abstract int getNextVisualPositionFrom(JTextComponent c, int pos, 620: Position.Bias b, int d, 621: Position.Bias[] biasRet) 622: throws BadLocationException; 623: }