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