GNU Classpath (0.18) | ||
Frames | No Frames |
1: /* BasicTextUI.java -- 2: Copyright (C) 2002, 2003, 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.plaf.basic; 40: 41: import java.awt.Container; 42: import java.awt.Dimension; 43: import java.awt.Graphics; 44: import java.awt.Insets; 45: import java.awt.Point; 46: import java.awt.Rectangle; 47: import java.awt.Shape; 48: import java.awt.event.FocusEvent; 49: import java.awt.event.FocusListener; 50: import java.beans.PropertyChangeEvent; 51: import java.beans.PropertyChangeListener; 52: 53: import javax.swing.Action; 54: import javax.swing.ActionMap; 55: import javax.swing.InputMap; 56: import javax.swing.JComponent; 57: import javax.swing.SwingUtilities; 58: import javax.swing.UIDefaults; 59: import javax.swing.UIManager; 60: import javax.swing.event.DocumentEvent; 61: import javax.swing.event.DocumentListener; 62: import javax.swing.plaf.ActionMapUIResource; 63: import javax.swing.plaf.TextUI; 64: import javax.swing.plaf.UIResource; 65: import javax.swing.text.BadLocationException; 66: import javax.swing.text.Caret; 67: import javax.swing.text.DefaultCaret; 68: import javax.swing.text.DefaultEditorKit; 69: import javax.swing.text.DefaultHighlighter; 70: import javax.swing.text.Document; 71: import javax.swing.text.EditorKit; 72: import javax.swing.text.Element; 73: import javax.swing.text.Highlighter; 74: import javax.swing.text.JTextComponent; 75: import javax.swing.text.Keymap; 76: import javax.swing.text.PlainView; 77: import javax.swing.text.Position; 78: import javax.swing.text.View; 79: import javax.swing.text.ViewFactory; 80: 81: /** 82: * The abstract base class from which the UI classes for Swings text 83: * components are derived. This provides most of the functionality for 84: * the UI classes. 85: * 86: * @author original author unknown 87: * @author Roman Kennke (roman@kennke.org) 88: */ 89: public abstract class BasicTextUI extends TextUI 90: implements ViewFactory 91: { 92: /** 93: * A {@link DefaultCaret} that implements {@link UIResource}. 94: */ 95: public static class BasicCaret extends DefaultCaret 96: implements UIResource 97: { 98: public BasicCaret() 99: { 100: } 101: } 102: 103: /** 104: * A {@link DefaultHighlighter} that implements {@link UIResource}. 105: */ 106: public static class BasicHighlighter extends DefaultHighlighter 107: implements UIResource 108: { 109: public BasicHighlighter() 110: { 111: } 112: } 113: 114: /** 115: * This view forms the root of the View hierarchy. However, it delegates 116: * most calls to another View which is the real root of the hierarchy. 117: * The purpose is to make sure that all Views in the hierarchy, including 118: * the (real) root have a well-defined parent to which they can delegate 119: * calls like {@link #preferenceChanged}, {@link #getViewFactory} and 120: * {@link #getContainer}. 121: */ 122: private class RootView extends View 123: { 124: /** The real root view. */ 125: private View view; 126: 127: /** 128: * Creates a new RootView. 129: */ 130: public RootView() 131: { 132: super(null); 133: } 134: 135: /** 136: * Returns the ViewFactory for this RootView. If the current EditorKit 137: * provides a ViewFactory, this is used. Otherwise the TextUI itself 138: * is returned as a ViewFactory. 139: * 140: * @return the ViewFactory for this RootView 141: */ 142: public ViewFactory getViewFactory() 143: { 144: ViewFactory factory = null; 145: EditorKit editorKit = BasicTextUI.this.getEditorKit(getComponent()); 146: factory = editorKit.getViewFactory(); 147: if (factory == null) 148: factory = BasicTextUI.this; 149: return factory; 150: } 151: 152: /** 153: * Indicates that the preferences of one of the child view has changed. 154: * This calls revalidate on the text component. 155: * 156: * @param view the child view which's preference has changed 157: * @param width <code>true</code> if the width preference has changed 158: * @param height <code>true</code> if the height preference has changed 159: */ 160: public void preferenceChanged(View view, boolean width, boolean height) 161: { 162: textComponent.revalidate(); 163: } 164: 165: /** 166: * Sets the real root view. 167: * 168: * @param v the root view to set 169: */ 170: public void setView(View v) 171: { 172: if (view != null) 173: view.setParent(null); 174: 175: if (v != null) 176: v.setParent(null); 177: 178: view = v; 179: } 180: 181: /** 182: * Returns the real root view, regardless of the index. 183: * 184: * @param index not used here 185: * 186: * @return the real root view, regardless of the index. 187: */ 188: public View getView(int index) 189: { 190: return view; 191: } 192: 193: /** 194: * Returns <code>1</code> since the RootView always contains one 195: * child, that is the real root of the View hierarchy. 196: * 197: * @return <code>1</code> since the RootView always contains one 198: * child, that is the real root of the View hierarchy 199: */ 200: public int getViewCount() 201: { 202: if (view != null) 203: return 1; 204: else 205: return 0; 206: } 207: 208: /** 209: * Returns the <code>Container</code> that contains this view. This 210: * normally will be the text component that is managed by this TextUI. 211: * 212: * @return the <code>Container</code> that contains this view 213: */ 214: public Container getContainer() 215: { 216: return textComponent; 217: } 218: 219: /** 220: * Returns the preferred span along the specified <code>axis</code>. 221: * This is delegated to the real root view. 222: * 223: * @param axis the axis for which the preferred span is queried 224: * 225: * @return the preferred span along the axis 226: */ 227: public float getPreferredSpan(int axis) 228: { 229: if (view != null) 230: return view.getPreferredSpan(axis); 231: 232: return Integer.MAX_VALUE; 233: } 234: 235: /** 236: * Paints the view. This is delegated to the real root view. 237: * 238: * @param g the <code>Graphics</code> context to paint to 239: * @param s the allocation for the View 240: */ 241: public void paint(Graphics g, Shape s) 242: { 243: if (view != null) 244: view.paint(g, s); 245: } 246: 247: 248: /** 249: * Maps a position in the document into the coordinate space of the View. 250: * The output rectangle usually reflects the font height but has a width 251: * of zero. 252: * 253: * This is delegated to the real root view. 254: * 255: * @param pos the position of the character in the model 256: * @param a the area that is occupied by the view 257: * @param bias either {@link Position.Bias.Forward} or 258: * {@link Position.Bias.Backward} depending on the preferred 259: * direction bias. If <code>null</code> this defaults to 260: * <code>Position.Bias.Forward</code> 261: * 262: * @return a rectangle that gives the location of the document position 263: * inside the view coordinate space 264: * 265: * @throws BadLocationException if <code>pos</code> is invalid 266: * @throws IllegalArgumentException if b is not one of the above listed 267: * valid values 268: */ 269: public Shape modelToView(int position, Shape a, Position.Bias bias) 270: throws BadLocationException 271: { 272: return ((View) view).modelToView(position, a, bias); 273: } 274: 275: /** 276: * Maps coordinates from the <code>View</code>'s space into a position 277: * in the document model. 278: * 279: * @param x the x coordinate in the view space 280: * @param y the y coordinate in the view space 281: * @param a the allocation of this <code>View</code> 282: * @param b the bias to use 283: * 284: * @return the position in the document that corresponds to the screen 285: * coordinates <code>x, y</code> 286: */ 287: public int viewToModel(float x, float y, Shape a, Position.Bias[] b) 288: { 289: return view.viewToModel(x, y, a, b); 290: } 291: 292: /** 293: * Notification about text insertions. These are forwarded to the 294: * real root view. 295: * 296: * @param ev the DocumentEvent describing the change 297: * @param shape the current allocation of the view's display 298: * @param vf the ViewFactory to use for creating new Views 299: */ 300: public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) 301: { 302: view.insertUpdate(ev, shape, vf); 303: } 304: 305: /** 306: * Notification about text removals. These are forwarded to the 307: * real root view. 308: * 309: * @param ev the DocumentEvent describing the change 310: * @param shape the current allocation of the view's display 311: * @param vf the ViewFactory to use for creating new Views 312: */ 313: public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) 314: { 315: view.removeUpdate(ev, shape, vf); 316: } 317: 318: /** 319: * Notification about text changes. These are forwarded to the 320: * real root view. 321: * 322: * @param ev the DocumentEvent describing the change 323: * @param shape the current allocation of the view's display 324: * @param vf the ViewFactory to use for creating new Views 325: */ 326: public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) 327: { 328: view.changedUpdate(ev, shape, vf); 329: } 330: } 331: 332: /** 333: * Receives notifications when properties of the text component change. 334: */ 335: class UpdateHandler implements PropertyChangeListener 336: { 337: /** 338: * Notifies when a property of the text component changes. 339: * 340: * @param event the PropertyChangeEvent describing the change 341: */ 342: public void propertyChange(PropertyChangeEvent event) 343: { 344: if (event.getPropertyName().equals("document")) 345: { 346: // Document changed. 347: modelChanged(); 348: } 349: } 350: } 351: 352: /** 353: * Listens for changes on the underlying model and forwards notifications 354: * to the View. This also updates the caret position of the text component. 355: * 356: * TODO: Maybe this should somehow be handled through EditorKits 357: */ 358: class DocumentHandler implements DocumentListener 359: { 360: /** 361: * Notification about a document change event. 362: * 363: * @param ev the DocumentEvent describing the change 364: */ 365: public void changedUpdate(DocumentEvent ev) 366: { 367: Dimension size = textComponent.getSize(); 368: rootView.changedUpdate(ev, new Rectangle(0, 0, size.width, size.height), 369: rootView.getViewFactory()); 370: } 371: 372: /** 373: * Notification about a document insert event. 374: * 375: * @param ev the DocumentEvent describing the insertion 376: */ 377: public void insertUpdate(DocumentEvent ev) 378: { 379: Dimension size = textComponent.getSize(); 380: rootView.insertUpdate(ev, new Rectangle(0, 0, size.width, size.height), 381: rootView.getViewFactory()); 382: int caretPos = textComponent.getCaretPosition(); 383: if (caretPos >= ev.getOffset()) 384: textComponent.setCaretPosition(caretPos + ev.getLength()); 385: } 386: 387: /** 388: * Notification about a document removal event. 389: * 390: * @param ev the DocumentEvent describing the removal 391: */ 392: public void removeUpdate(DocumentEvent ev) 393: { 394: Dimension size = textComponent.getSize(); 395: rootView.removeUpdate(ev, new Rectangle(0, 0, size.width, size.height), 396: rootView.getViewFactory()); 397: int caretPos = textComponent.getCaretPosition(); 398: if (caretPos >= ev.getOffset()) 399: textComponent.setCaretPosition(ev.getOffset()); 400: } 401: } 402: 403: /** 404: * The EditorKit used by this TextUI. 405: */ 406: // FIXME: should probably be non-static. 407: static EditorKit kit = new DefaultEditorKit(); 408: 409: /** 410: * The root view. 411: */ 412: RootView rootView = new RootView(); 413: 414: /** 415: * The text component that we handle. 416: */ 417: JTextComponent textComponent; 418: 419: /** 420: * Receives notification when the model changes. 421: */ 422: UpdateHandler updateHandler = new UpdateHandler(); 423: 424: /** The DocumentEvent handler. */ 425: DocumentHandler documentHandler = new DocumentHandler(); 426: 427: /** 428: * Creates a new <code>BasicTextUI</code> instance. 429: */ 430: public BasicTextUI() 431: { 432: } 433: 434: /** 435: * Creates a {@link Caret} that should be installed into the text component. 436: * 437: * @return a caret that should be installed into the text component 438: */ 439: protected Caret createCaret() 440: { 441: return new BasicCaret(); 442: } 443: 444: /** 445: * Creates a {@link Highlighter} that should be installed into the text 446: * component. 447: * 448: * @return a <code>Highlighter</code> for the text component 449: */ 450: protected Highlighter createHighlighter() 451: { 452: return new BasicHighlighter(); 453: } 454: 455: /** 456: * The text component that is managed by this UI. 457: * 458: * @return the text component that is managed by this UI 459: */ 460: protected final JTextComponent getComponent() 461: { 462: return textComponent; 463: } 464: 465: /** 466: * Installs this UI on the text component. 467: * 468: * @param c the text component on which to install the UI 469: */ 470: public void installUI(final JComponent c) 471: { 472: super.installUI(c); 473: c.setOpaque(true); 474: 475: textComponent = (JTextComponent) c; 476: 477: Document doc = textComponent.getDocument(); 478: if (doc == null) 479: { 480: doc = getEditorKit(textComponent).createDefaultDocument(); 481: textComponent.setDocument(doc); 482: } 483: 484: textComponent.addPropertyChangeListener(updateHandler); 485: modelChanged(); 486: 487: installDefaults(); 488: installListeners(); 489: installKeyboardActions(); 490: } 491: 492: /** 493: * Installs UI defaults on the text components. 494: */ 495: protected void installDefaults() 496: { 497: Caret caret = textComponent.getCaret(); 498: if (caret == null) 499: { 500: caret = createCaret(); 501: textComponent.setCaret(caret); 502: } 503: 504: Highlighter highlighter = textComponent.getHighlighter(); 505: if (highlighter == null) 506: textComponent.setHighlighter(createHighlighter()); 507: 508: String prefix = getPropertyPrefix(); 509: UIDefaults defaults = UIManager.getLookAndFeelDefaults(); 510: textComponent.setBackground(defaults.getColor(prefix + ".background")); 511: textComponent.setForeground(defaults.getColor(prefix + ".foreground")); 512: textComponent.setMargin(defaults.getInsets(prefix + ".margin")); 513: textComponent.setBorder(defaults.getBorder(prefix + ".border")); 514: textComponent.setFont(defaults.getFont(prefix + ".font")); 515: 516: caret.setBlinkRate(defaults.getInt(prefix + ".caretBlinkRate")); 517: } 518: 519: /** 520: * This FocusListener triggers repaints on focus shift. 521: */ 522: private FocusListener focuslistener = new FocusListener() { 523: public void focusGained(FocusEvent e) 524: { 525: textComponent.repaint(); 526: } 527: public void focusLost(FocusEvent e) 528: { 529: textComponent.repaint(); 530: } 531: }; 532: 533: /** 534: * Install all listeners on the text component. 535: */ 536: protected void installListeners() 537: { 538: textComponent.addFocusListener(focuslistener); 539: installDocumentListeners(); 540: } 541: 542: /** 543: * Installs the document listeners on the textComponent's model. 544: */ 545: private void installDocumentListeners() 546: { 547: Document doc = textComponent.getDocument(); 548: if (doc != null) 549: doc.addDocumentListener(documentHandler); 550: } 551: 552: /** 553: * Returns the name of the keymap for this type of TextUI. 554: * 555: * This is implemented so that the classname of this TextUI 556: * without the package prefix is returned. This way subclasses 557: * don't have to override this method. 558: * 559: * @return the name of the keymap for this TextUI 560: */ 561: protected String getKeymapName() 562: { 563: String fullClassName = getClass().getName(); 564: int index = fullClassName.lastIndexOf('.'); 565: String className = fullClassName.substring(index + 1); 566: return className; 567: } 568: 569: /** 570: * Creates the {@link Keymap} that is installed on the text component. 571: * 572: * @return the {@link Keymap} that is installed on the text component 573: */ 574: protected Keymap createKeymap() 575: { 576: String prefix = getPropertyPrefix(); 577: UIDefaults defaults = UIManager.getLookAndFeelDefaults(); 578: JTextComponent.KeyBinding[] bindings = 579: (JTextComponent.KeyBinding[]) defaults.get(prefix + ".keyBindings"); 580: if (bindings == null) 581: { 582: bindings = new JTextComponent.KeyBinding[0]; 583: defaults.put(prefix + ".keyBindings", bindings); 584: } 585: 586: Keymap km = JTextComponent.addKeymap(getKeymapName(), 587: JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP)); 588: JTextComponent.loadKeymap(km, bindings, textComponent.getActions()); 589: return km; 590: } 591: 592: /** 593: * Installs the keyboard actions on the text components. 594: */ 595: protected void installKeyboardActions() 596: { 597: // load any bindings for the older Keymap interface 598: Keymap km = JTextComponent.getKeymap(getKeymapName()); 599: if (km == null) 600: km = createKeymap(); 601: textComponent.setKeymap(km); 602: 603: // load any bindings for the newer InputMap / ActionMap interface 604: SwingUtilities.replaceUIInputMap(textComponent, 605: JComponent.WHEN_FOCUSED, 606: getInputMap(JComponent.WHEN_FOCUSED)); 607: SwingUtilities.replaceUIActionMap(textComponent, getActionMap()); 608: } 609: 610: /** 611: * Gets the input map for the specified <code>condition</code>. 612: * 613: * @param condition the condition for the InputMap 614: * 615: * @return the InputMap for the specified condition 616: */ 617: InputMap getInputMap(int condition) 618: { 619: String prefix = getPropertyPrefix(); 620: UIDefaults defaults = UIManager.getLookAndFeelDefaults(); 621: switch (condition) 622: { 623: case JComponent.WHEN_IN_FOCUSED_WINDOW: 624: // FIXME: is this the right string? nobody seems to use it. 625: return (InputMap) defaults.get(prefix + ".windowInputMap"); 626: case JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: 627: return (InputMap) defaults.get(prefix + ".ancestorInputMap"); 628: default: 629: case JComponent.WHEN_FOCUSED: 630: return (InputMap) defaults.get(prefix + ".focusInputMap"); 631: } 632: } 633: 634: /** 635: * Returns the ActionMap to be installed on the text component. 636: * 637: * @return the ActionMap to be installed on the text component 638: */ 639: // FIXME: The UIDefaults have no entries for .actionMap, so this should 640: // be handled somehow different. 641: ActionMap getActionMap() 642: { 643: String prefix = getPropertyPrefix(); 644: UIDefaults defaults = UIManager.getLookAndFeelDefaults(); 645: ActionMap am = (ActionMap) defaults.get(prefix + ".actionMap"); 646: if (am == null) 647: { 648: am = createActionMap(); 649: defaults.put(prefix + ".actionMap", am); 650: } 651: return am; 652: } 653: 654: /** 655: * Creates an ActionMap to be installed on the text component. 656: * 657: * @return an ActionMap to be installed on the text component 658: */ 659: ActionMap createActionMap() 660: { 661: Action[] actions = textComponent.getActions(); 662: ActionMap am = new ActionMapUIResource(); 663: for (int i = 0; i < actions.length; ++i) 664: { 665: String name = (String) actions[i].getValue(Action.NAME); 666: if (name != null) 667: am.put(name, actions[i]); 668: } 669: return am; 670: } 671: 672: /** 673: * Uninstalls this TextUI from the text component. 674: * 675: * @param component the text component to uninstall the UI from 676: */ 677: public void uninstallUI(final JComponent component) 678: { 679: super.uninstallUI(component); 680: rootView.setView(null); 681: 682: textComponent.removePropertyChangeListener(updateHandler); 683: 684: uninstallDefaults(); 685: uninstallListeners(); 686: uninstallKeyboardActions(); 687: 688: textComponent = null; 689: } 690: 691: /** 692: * Uninstalls all default properties that have previously been installed by 693: * this UI. 694: */ 695: protected void uninstallDefaults() 696: { 697: // Do nothing here. 698: } 699: 700: /** 701: * Uninstalls all listeners that have previously been installed by 702: * this UI. 703: */ 704: protected void uninstallListeners() 705: { 706: textComponent.removeFocusListener(focuslistener); 707: } 708: 709: /** 710: * Uninstalls all keyboard actions that have previously been installed by 711: * this UI. 712: */ 713: protected void uninstallKeyboardActions() 714: { 715: // FIXME: Uninstall keyboard actions here. 716: } 717: 718: /** 719: * Returns the property prefix by which the text component's UIDefaults 720: * are looked up. 721: * 722: * @return the property prefix by which the text component's UIDefaults 723: * are looked up 724: */ 725: protected abstract String getPropertyPrefix(); 726: 727: /** 728: * Returns the preferred size of the text component. 729: * 730: * @param c not used here 731: * 732: * @return the preferred size of the text component 733: */ 734: public Dimension getPreferredSize(JComponent c) 735: { 736: View v = getRootView(textComponent); 737: 738: float w = v.getPreferredSpan(View.X_AXIS); 739: float h = v.getPreferredSpan(View.Y_AXIS); 740: 741: return new Dimension((int) w, (int) h); 742: } 743: 744: /** 745: * Returns the maximum size for text components that use this UI. 746: * 747: * This returns (Integer.MAX_VALUE, Integer.MAX_VALUE). 748: * 749: * @param c not used here 750: * 751: * @return the maximum size for text components that use this UI 752: */ 753: public Dimension getMaximumSize(JComponent c) 754: { 755: // Sun's implementation returns Integer.MAX_VALUE here, so do we. 756: return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 757: } 758: 759: /** 760: * Paints the text component. 761: * 762: * @param g the <code>Graphics</code> context to paint to 763: * @param c not used here 764: */ 765: public final void paint(Graphics g, JComponent c) 766: { 767: paintSafely(g); 768: } 769: 770: /** 771: * Actually performs the painting. 772: * 773: * @param g the <code>Graphics</code> context to paint to 774: */ 775: protected void paintSafely(Graphics g) 776: { 777: Caret caret = textComponent.getCaret(); 778: Highlighter highlighter = textComponent.getHighlighter(); 779: 780: if (textComponent.isOpaque()) 781: paintBackground(g); 782: 783: if (highlighter != null 784: && textComponent.getSelectionStart() != textComponent.getSelectionEnd()) 785: highlighter.paint(g); 786: 787: rootView.paint(g, getVisibleEditorRect()); 788: 789: if (caret != null && textComponent.hasFocus()) 790: caret.paint(g); 791: } 792: 793: /** 794: * Paints the background of the text component. 795: * 796: * @param g the <code>Graphics</code> context to paint to 797: */ 798: protected void paintBackground(Graphics g) 799: { 800: g.setColor(textComponent.getBackground()); 801: g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight()); 802: } 803: 804: /** 805: * Marks the specified range inside the text component's model as 806: * damaged and queues a repaint request. 807: * 808: * @param t the text component 809: * @param p0 the start location inside the document model of the range that 810: * is damaged 811: * @param p1 the end location inside the document model of the range that 812: * is damaged 813: */ 814: public void damageRange(JTextComponent t, int p0, int p1) 815: { 816: damageRange(t, p0, p1, null, null); 817: } 818: 819: /** 820: * Marks the specified range inside the text component's model as 821: * damaged and queues a repaint request. This variant of this method 822: * allows a {@link Position.Bias} object to be specified for the start 823: * and end location of the range. 824: * 825: * @param t the text component 826: * @param p0 the start location inside the document model of the range that 827: * is damaged 828: * @param p1 the end location inside the document model of the range that 829: * is damaged 830: * @param firstBias the bias for the start location 831: * @param secondBias the bias for the end location 832: */ 833: public void damageRange(JTextComponent t, int p0, int p1, 834: Position.Bias firstBias, Position.Bias secondBias) 835: { 836: // TODO: Implement me. 837: } 838: 839: /** 840: * Returns the {@link EditorKit} used for the text component that is managed 841: * by this UI. 842: * 843: * @param t the text component 844: * 845: * @return the {@link EditorKit} used for the text component that is managed 846: * by this UI 847: */ 848: public EditorKit getEditorKit(JTextComponent t) 849: { 850: return kit; 851: } 852: 853: /** 854: * Gets the next position inside the document model that is visible on 855: * screen, starting from <code>pos</code>. 856: * 857: * @param t the text component 858: * @param pos the start positionn 859: * @param b the bias for pos 860: * @param direction the search direction 861: * @param biasRet filled by the method to indicate the bias of the return 862: * value 863: * 864: * @return the next position inside the document model that is visible on 865: * screen 866: */ 867: public int getNextVisualPositionFrom(JTextComponent t, int pos, 868: Position.Bias b, int direction, 869: Position.Bias[] biasRet) 870: throws BadLocationException 871: { 872: return 0; // TODO: Implement me. 873: } 874: 875: /** 876: * Returns the root {@link View} of a text component. 877: * 878: * @return the root {@link View} of a text component 879: */ 880: public View getRootView(JTextComponent t) 881: { 882: return rootView; 883: } 884: 885: /** 886: * Maps a position in the document into the coordinate space of the View. 887: * The output rectangle usually reflects the font height but has a width 888: * of zero. A bias of {@link Position.Bias.Forward} is used in this method. 889: * 890: * @param pos the position of the character in the model 891: * @param a the area that is occupied by the view 892: * 893: * @return a rectangle that gives the location of the document position 894: * inside the view coordinate space 895: * 896: * @throws BadLocationException if <code>pos</code> is invalid 897: * @throws IllegalArgumentException if b is not one of the above listed 898: * valid values 899: */ 900: public Rectangle modelToView(JTextComponent t, int pos) 901: throws BadLocationException 902: { 903: return modelToView(t, pos, Position.Bias.Forward); 904: } 905: 906: /** 907: * Maps a position in the document into the coordinate space of the View. 908: * The output rectangle usually reflects the font height but has a width 909: * of zero. 910: * 911: * @param pos the position of the character in the model 912: * @param a the area that is occupied by the view 913: * @param bias either {@link Position.Bias.Forward} or 914: * {@link Position.Bias.Backward} depending on the preferred 915: * direction bias. If <code>null</code> this defaults to 916: * <code>Position.Bias.Forward</code> 917: * 918: * @return a rectangle that gives the location of the document position 919: * inside the view coordinate space 920: * 921: * @throws BadLocationException if <code>pos</code> is invalid 922: * @throws IllegalArgumentException if b is not one of the above listed 923: * valid values 924: */ 925: public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias) 926: throws BadLocationException 927: { 928: return rootView.modelToView(pos, getVisibleEditorRect(), bias).getBounds(); 929: } 930: 931: /** 932: * Maps a point in the <code>View</code> coordinate space to a position 933: * inside a document model. 934: * 935: * @param t the text component 936: * @param pt the point to be mapped 937: * 938: * @return the position inside the document model that corresponds to 939: * <code>pt</code> 940: */ 941: public int viewToModel(JTextComponent t, Point pt) 942: { 943: return viewToModel(t, pt, null); 944: } 945: 946: /** 947: * Maps a point in the <code>View</code> coordinate space to a position 948: * inside a document model. 949: * 950: * @param t the text component 951: * @param pt the point to be mapped 952: * @param biasReturn filled in by the method to indicate the bias of the 953: * return value 954: * 955: * @return the position inside the document model that corresponds to 956: * <code>pt</code> 957: */ 958: public int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn) 959: { 960: return 0; // FIXME: Implement me. 961: } 962: 963: /** 964: * Creates a {@link View} for the specified {@link Element}. 965: * 966: * @param elem the <code>Element</code> to create a <code>View</code> for 967: * 968: * @see ViewFactory 969: */ 970: public View create(Element elem) 971: { 972: // Subclasses have to implement this to get this functionality. 973: return null; 974: } 975: 976: /** 977: * Creates a {@link View} for the specified {@link Element}. 978: * 979: * @param elem the <code>Element</code> to create a <code>View</code> for 980: * @param p0 the start offset 981: * @param p1 the end offset 982: * 983: * @see ViewFactory 984: */ 985: public View create(Element elem, int p0, int p1) 986: { 987: // Subclasses have to implement this to get this functionality. 988: return null; 989: } 990: 991: /** 992: * Returns the allocation to give the root view. 993: * 994: * @return the allocation to give the root view 995: * 996: * @specnote The allocation has nothing to do with visibility. According 997: * to the specs the naming of this method is unfortunate and 998: * has historical reasons 999: */ 1000: protected Rectangle getVisibleEditorRect() 1001: { 1002: int width = textComponent.getWidth(); 1003: int height = textComponent.getHeight(); 1004: 1005: if (width <= 0 || height <= 0) 1006: return null; 1007: 1008: Insets insets = textComponent.getInsets(); 1009: return new Rectangle(insets.left, insets.top, 1010: width - insets.left + insets.right, 1011: height - insets.top + insets.bottom); 1012: } 1013: 1014: /** 1015: * Sets the root view for the text component. 1016: * 1017: * @param view the <code>View</code> to be set as root view 1018: */ 1019: protected final void setView(View view) 1020: { 1021: rootView.setView(view); 1022: view.setParent(rootView); 1023: } 1024: 1025: /** 1026: * Indicates that the model of a text component has changed. This 1027: * triggers a rebuild of the view hierarchy. 1028: */ 1029: protected void modelChanged() 1030: { 1031: if (textComponent == null || rootView == null) 1032: return; 1033: ViewFactory factory = rootView.getViewFactory(); 1034: if (factory == null) 1035: return; 1036: Document doc = textComponent.getDocument(); 1037: if (doc == null) 1038: return; 1039: installDocumentListeners(); 1040: Element elem = doc.getDefaultRootElement(); 1041: if (elem == null) 1042: return; 1043: View view = factory.create(elem); 1044: setView(view); 1045: } 1046: }
GNU Classpath (0.18) |