GNU Classpath (0.20) | |
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: if (ec != null && shape != null) 451: preferenceChanged(null, true, true); 452: Container c = getContainer(); 453: if (c != null) 454: c.repaint(); 455: } 456: 457: /** 458: * Maps a position in the document into the coordinate space of the View. 459: * The output rectangle usually reflects the font height but has a width 460: * of zero. 461: * 462: * @param pos the position of the character in the model 463: * @param a the area that is occupied by the view 464: * @param b either {@link Position.Bias#Forward} or 465: * {@link Position.Bias#Backward} depending on the preferred 466: * direction bias. If <code>null</code> this defaults to 467: * <code>Position.Bias.Forward</code> 468: * 469: * @return a rectangle that gives the location of the document position 470: * inside the view coordinate space 471: * 472: * @throws BadLocationException if <code>pos</code> is invalid 473: * @throws IllegalArgumentException if b is not one of the above listed 474: * valid values 475: */ 476: public abstract Shape modelToView(int pos, Shape a, Position.Bias b) 477: throws BadLocationException; 478: 479: /** 480: * Maps a region in the document into the coordinate space of the View. 481: * 482: * @param p1 the beginning position inside the document 483: * @param b1 the direction bias for the beginning position 484: * @param p2 the end position inside the document 485: * @param b2 the direction bias for the end position 486: * @param a the area that is occupied by the view 487: * 488: * @return a rectangle that gives the span of the document region 489: * inside the view coordinate space 490: * 491: * @throws BadLocationException if <code>p1</code> or <code>p2</code> are 492: * invalid 493: * @throws IllegalArgumentException if b1 or b2 is not one of the above 494: * listed valid values 495: */ 496: public Shape modelToView(int p1, Position.Bias b1, 497: int p2, Position.Bias b2, Shape a) 498: throws BadLocationException 499: { 500: if (b1 != Position.Bias.Forward && b1 != Position.Bias.Backward) 501: throw new IllegalArgumentException 502: ("b1 must be either Position.Bias.Forward or Position.Bias.Backward"); 503: if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward) 504: throw new IllegalArgumentException 505: ("b2 must be either Position.Bias.Forward or Position.Bias.Backward"); 506: Shape s1 = modelToView(p1, a, b1); 507: Shape s2 = modelToView(p2, a, b2); 508: return s1.getBounds().union(s2.getBounds()); 509: } 510: 511: /** 512: * Maps a position in the document into the coordinate space of the View. 513: * The output rectangle usually reflects the font height but has a width 514: * of zero. 515: * 516: * This method is deprecated and calls 517: * {@link #modelToView(int, Position.Bias, int, Position.Bias, Shape)} with 518: * a bias of {@link Position.Bias#Forward}. 519: * 520: * @param pos the position of the character in the model 521: * @param a the area that is occupied by the view 522: * 523: * @return a rectangle that gives the location of the document position 524: * inside the view coordinate space 525: * 526: * @throws BadLocationException if <code>pos</code> is invalid 527: * 528: * @deprecated Use {@link #modelToView(int, Shape, Position.Bias)} instead. 529: */ 530: public Shape modelToView(int pos, Shape a) throws BadLocationException 531: { 532: return modelToView(pos, a, Position.Bias.Forward); 533: } 534: 535: /** 536: * Maps coordinates from the <code>View</code>'s space into a position 537: * in the document model. 538: * 539: * @param x the x coordinate in the view space 540: * @param y the y coordinate in the view space 541: * @param a the allocation of this <code>View</code> 542: * @param b the bias to use 543: * 544: * @return the position in the document that corresponds to the screen 545: * coordinates <code>x, y</code> 546: */ 547: public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] b); 548: 549: /** 550: * Maps coordinates from the <code>View</code>'s space into a position 551: * in the document model. This method is deprecated and only there for 552: * compatibility. 553: * 554: * @param x the x coordinate in the view space 555: * @param y the y coordinate in the view space 556: * @param a the allocation of this <code>View</code> 557: * 558: * @return the position in the document that corresponds to the screen 559: * coordinates <code>x, y</code> 560: * 561: * @deprecated Use {@link #viewToModel(float, float, Shape, Position.Bias[])} 562: * instead. 563: */ 564: public int viewToModel(float x, float y, Shape a) 565: { 566: return viewToModel(x, y, a, new Position.Bias[0]); 567: } 568: 569: /** 570: * Dumps the complete View hierarchy. This method can be used for debugging 571: * purposes. 572: */ 573: void dump() 574: { 575: // Climb up the hierarchy to the parent. 576: View parent = getParent(); 577: if (parent != null) 578: parent.dump(); 579: else 580: dump(0); 581: } 582: 583: /** 584: * Dumps the view hierarchy below this View with the specified indentation 585: * level. 586: * 587: * @param indent the indentation level to be used for this view 588: */ 589: void dump(int indent) 590: { 591: for (int i = 0; i < indent; ++i) 592: System.out.print('.'); 593: System.out.println(this); 594: 595: int count = getViewCount(); 596: for (int i = 0; i < count; ++i) 597: getView(i).dump(indent + 1); 598: } 599: 600: /** 601: * Returns the document position that is (visually) nearest to the given 602: * document position <code>pos</code> in the given direction <code>d</code>. 603: * 604: * @param pos the document position 605: * @param b the bias for <code>pos</code> 606: * @param a the allocation for this view 607: * @param d the direction, must be either {@link SwingConstants#NORTH}, 608: * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or 609: * {@link SwingConstants#EAST} 610: * @param biasRet an array of {@link Position.Bias} that can hold at least 611: * one element, which is filled with the bias of the return position 612: * on method exit 613: * 614: * @return the document position that is (visually) nearest to the given 615: * document position <code>pos</code> in the given direction 616: * <code>d</code> 617: * 618: * @throws BadLocationException if <code>pos</code> is not a valid offset in 619: * the document model 620: * @throws IllegalArgumentException if <code>d</code> is not a valid direction 621: */ 622: public int getNextVisualPositionFrom(int pos, Position.Bias b, 623: Shape a, int d, 624: Position.Bias[] biasRet) 625: throws BadLocationException 626: { 627: int ret = pos; 628: switch (d) 629: { 630: case WEST: 631: ret = pos - 1; 632: break; 633: case EAST: 634: ret = pos + 1; 635: break; 636: case NORTH: 637: // TODO: Implement this 638: break; 639: case SOUTH: 640: // TODO: Implement this 641: break; 642: default: 643: throw new IllegalArgumentException("Illegal value for d"); 644: } 645: return ret; 646: } 647: }
GNU Classpath (0.20) |