001 /* 002 * $Id: BasicHyperlinkUI.java 3344 2009-05-25 01:46:59Z kschaefe $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 package org.jdesktop.swingx.plaf.basic; 022 023 import java.awt.Color; 024 import java.awt.Container; 025 import java.awt.Cursor; 026 import java.awt.Font; 027 import java.awt.FontMetrics; 028 import java.awt.Graphics; 029 import java.awt.Insets; 030 import java.awt.Rectangle; 031 import java.awt.Shape; 032 import java.beans.PropertyChangeEvent; 033 import java.beans.PropertyChangeListener; 034 import java.io.Reader; 035 import java.io.StringReader; 036 import java.lang.reflect.Method; 037 import java.net.URL; 038 import java.util.logging.Logger; 039 040 import javax.swing.AbstractButton; 041 import javax.swing.BorderFactory; 042 import javax.swing.ButtonModel; 043 import javax.swing.Icon; 044 import javax.swing.JComponent; 045 import javax.swing.JToolBar; 046 import javax.swing.LookAndFeel; 047 import javax.swing.SwingUtilities; 048 import javax.swing.UIManager; 049 import javax.swing.event.ChangeEvent; 050 import javax.swing.plaf.BorderUIResource; 051 import javax.swing.plaf.ComponentUI; 052 import javax.swing.plaf.basic.BasicButtonListener; 053 import javax.swing.plaf.basic.BasicButtonUI; 054 import javax.swing.plaf.basic.BasicGraphicsUtils; 055 import javax.swing.plaf.basic.BasicHTML; 056 import javax.swing.text.AttributeSet; 057 import javax.swing.text.BadLocationException; 058 import javax.swing.text.Document; 059 import javax.swing.text.Element; 060 import javax.swing.text.Position; 061 import javax.swing.text.View; 062 import javax.swing.text.ViewFactory; 063 import javax.swing.text.html.HTMLDocument; 064 import javax.swing.text.html.HTMLEditorKit; 065 import javax.swing.text.html.ImageView; 066 import javax.swing.text.html.StyleSheet; 067 068 import org.jdesktop.swingx.SwingXUtilities; 069 070 /** 071 * Basic implementation of the <code>JXHyperlink</code> UI. <br> 072 * This is copied from org.jdesktop.jdnc.plaf.basic.BasicLinkButtonUI 073 */ 074 public class BasicHyperlinkUI extends BasicButtonUI { 075 076 @SuppressWarnings("unused") 077 private static final Logger LOG = Logger.getLogger(BasicHyperlinkUI.class 078 .getName()); 079 080 public static ComponentUI createUI(JComponent c) { 081 return new BasicHyperlinkUI(); 082 } 083 084 private static Rectangle viewRect = new Rectangle(); 085 086 private static Rectangle textRect = new Rectangle(); 087 088 private static Rectangle iconRect = new Rectangle(); 089 090 // private static MouseListener handCursorListener = new HandCursor(); 091 092 protected int dashedRectGapX; 093 094 protected int dashedRectGapY; 095 096 protected int dashedRectGapWidth; 097 098 protected int dashedRectGapHeight; 099 100 private Color focusColor; 101 102 private View ulv; 103 104 private PropertyChangeListener pcListener = new PropertyChangeListener() { 105 106 public void propertyChange(PropertyChangeEvent evt) { 107 // this method is called from the edt. only other place where ulv is used is in 108 // painting which also happens on edt so it should be safe even without synchronization 109 // sole purpose of this call is to reinitialize view on every property change 110 ulv = null; 111 }}; 112 113 @Override 114 protected void installDefaults(AbstractButton b) { 115 super.installDefaults(b); 116 117 LookAndFeel.installProperty(b, "opaque", false); 118 b.setBorderPainted(false); 119 b.setRolloverEnabled(true); 120 if (SwingXUtilities.isUIInstallable(b.getBorder())) { 121 b.setBorder(new BorderUIResource(BorderFactory.createEmptyBorder(0, 1, 0, 0))); 122 } 123 124 dashedRectGapX = UIManager.getInt("ButtonUI.dashedRectGapX"); 125 dashedRectGapY = UIManager.getInt("ButtonUI.dashedRectGapY"); 126 dashedRectGapWidth = UIManager.getInt("ButtonUI.dashedRectGapWidth"); 127 dashedRectGapHeight = UIManager.getInt("ButtonUI.dashedRectGapHeight"); 128 focusColor = UIManager.getColor("ButtonUI.focus"); 129 130 b.setHorizontalAlignment(AbstractButton.LEADING); 131 } 132 133 @Override 134 protected void installListeners(AbstractButton b) { 135 super.installListeners(b); 136 // b.addMouseListener(handCursorListener); 137 b.addPropertyChangeListener(pcListener); 138 } 139 140 @Override 141 protected void uninstallListeners(AbstractButton b) { 142 super.uninstallListeners(b); 143 // b.removeMouseListener(handCursorListener); 144 b.removePropertyChangeListener(pcListener); 145 } 146 147 protected Color getFocusColor() { 148 return focusColor; 149 } 150 151 @Override 152 public void paint(Graphics g, JComponent c) { 153 AbstractButton b = (AbstractButton) c; 154 ButtonModel model = b.getModel(); 155 156 FontMetrics fm = g.getFontMetrics(); 157 158 Insets i = c.getInsets(); 159 160 viewRect.x = i.left; 161 viewRect.y = i.top; 162 viewRect.width = b.getWidth() - (i.right + viewRect.x); 163 viewRect.height = b.getHeight() - (i.bottom + viewRect.y); 164 165 textRect.x = textRect.y = textRect.width = textRect.height = 0; 166 iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0; 167 168 Font f = c.getFont(); 169 g.setFont(f); 170 171 // layout the text and icon 172 String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), b 173 .getIcon(), b.getVerticalAlignment(), b 174 .getHorizontalAlignment(), b.getVerticalTextPosition(), b 175 .getHorizontalTextPosition(), viewRect, iconRect, textRect, b 176 .getText() == null ? 0 : b.getIconTextGap()); 177 178 clearTextShiftOffset(); 179 180 // perform UI specific press action, e.g. Windows L&F shifts text 181 if (model.isArmed() && model.isPressed()) { 182 paintButtonPressed(g, b); 183 } 184 185 // Paint the Icon 186 if (b.getIcon() != null) { 187 paintIcon(g, c, iconRect); 188 } 189 190 // Composite oldComposite = ((Graphics2D) g).getComposite(); 191 // 192 // if (model.isRollover()) { 193 // ((Graphics2D) g).setComposite(AlphaComposite.getInstance( 194 // AlphaComposite.SRC_OVER, 0.5f)); 195 // } 196 197 if (text != null && !text.equals("")) { 198 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 199 if (v != null) { 200 paintHTMLText(g, b, textRect, text, v); 201 } else { 202 paintText(g, b, textRect, text); 203 } 204 } 205 206 if (b.isFocusPainted() && b.hasFocus()) { 207 // paint UI specific focus 208 paintFocus(g, b, viewRect, textRect, iconRect); 209 } 210 211 // ((Graphics2D) g).setComposite(oldComposite); 212 } 213 214 /** 215 * Method which renders the text of the current button if html. 216 * <p> 217 * @param g Graphics context 218 * @param b Current button to render 219 * @param textRect Bounding rectangle to render the text. 220 * @param text String to render 221 * @param v the View to use. 222 */ 223 protected void paintHTMLText(Graphics g, AbstractButton b, 224 Rectangle textRect, String text, View v) { 225 textRect.x += getTextShiftOffset(); 226 textRect.y += getTextShiftOffset(); 227 // fix #441-swingx - underline not painted for html 228 if (b.getModel().isRollover()) { 229 //paintUnderline(g, b, textRect, text); 230 if (ulv == null) { 231 ulv = ULHtml.createHTMLView(b, text); 232 } 233 ulv.paint(g, textRect); 234 } else { 235 v.paint(g, textRect); 236 } 237 textRect.x -= getTextShiftOffset(); 238 textRect.y -= getTextShiftOffset(); 239 } 240 241 /** 242 * {@inheritDoc} <p> 243 * Overridden to paint the underline on rollover. 244 */ 245 @Override 246 protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, 247 String text) { 248 //kgs -- SwingX #415: pixel-shift when disabled 249 //BasicButtonUI shifts disabled text to the left by 1 pixel 250 //we compensate for that here, so that all Hyperlinks paint 251 //at the same location regardless of state 252 if (!b.getModel().isEnabled()) { 253 textRect.x += 1; 254 } 255 256 super.paintText(g, b, textRect, text); 257 if (b.getModel().isRollover()) { 258 paintUnderline(g, b, textRect, text); 259 } 260 } 261 262 private void paintUnderline(Graphics g, AbstractButton b, Rectangle rect, 263 String text) { 264 // JW: copied from JXTable.LinkRenderer 265 FontMetrics fm = g.getFontMetrics(); 266 int descent = fm.getDescent(); 267 268 // REMIND(aim): should we be basing the underline on 269 // the font's baseline instead of the text bounds? 270 g.drawLine(rect.x + getTextShiftOffset(), 271 (rect.y + rect.height) - descent + 1 + getTextShiftOffset(), 272 rect.x + rect.width + getTextShiftOffset(), 273 (rect.y + rect.height) - descent + 1 + getTextShiftOffset()); 274 } 275 276 @Override 277 protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, 278 Rectangle textRect, Rectangle iconRect) { 279 if (b.getParent() instanceof JToolBar) { 280 // Windows doesn't draw the focus rect for buttons in a toolbar. 281 return; 282 } 283 284 // focus painted same color as text 285 g.setColor(getFocusColor()); 286 // paint the focus rect around the union of text rect and icon rect 287 // PENDING JW: duplicated to handle insets 288 Rectangle iconTextRect = getIconTextRect(b); 289 // PENDING JW: better factor handling of insets - the bare union doesn't respect insets 290 // Rectangle iconTextRect = textRect.union(iconRect); 291 BasicGraphicsUtils.drawDashedRect(g, iconTextRect.x, iconTextRect.y, 292 iconTextRect.width, iconTextRect.height); 293 // pre-#167-swingx: active area too large 294 // int width = b.getWidth(); 295 // int height = b.getHeight(); 296 // BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, 297 // width - dashedRectGapWidth, height - dashedRectGapHeight); 298 } 299 300 @Override 301 protected void paintButtonPressed(Graphics g, AbstractButton b) { 302 // setTextShiftOffset(); 303 } 304 305 306 @Override 307 protected BasicButtonListener createButtonListener(AbstractButton b) { 308 return new BasicHyperlinkListener(b); 309 } 310 311 /** 312 * {@inheritDoc} <p> 313 * 314 * Overridden to return true if the position is inside the union of the 315 * text and icon rectangle, false otherwise. 316 */ 317 @Override 318 public boolean contains(JComponent c, int x, int y) { 319 AbstractButton button = (AbstractButton) c; 320 return isInside(getIconTextRect(button), x, y); 321 } 322 323 /** 324 * @param iconTextRect 325 * @param point 326 * @return 327 */ 328 private boolean isInside(Rectangle iconTextRect, int x, int y) { 329 if (iconTextRect == null) return false; 330 return iconTextRect.contains(x, y); 331 } 332 333 /** 334 * C&p'ed from BasicGraphicsUtils (getPreferredButtonSize). 335 * 336 * @param b the button to analyse. 337 * @return the union of the text and icon rectangle of the AbstractButton 338 * or null if the button has children (??) 339 */ 340 protected Rectangle getIconTextRect(AbstractButton b) { 341 if (b.getComponentCount() > 0) { 342 return null; 343 } 344 345 Icon icon = (Icon) b.getIcon(); 346 String text = b.getText(); 347 348 Font font = b.getFont(); 349 FontMetrics fm = b.getFontMetrics(font); 350 351 Rectangle iconR = new Rectangle(); 352 Rectangle textR = new Rectangle(); 353 Rectangle viewR = new Rectangle(b.getSize()); 354 355 SwingUtilities.layoutCompoundLabel((JComponent) b, fm, text, icon, 356 b.getVerticalAlignment(), b.getHorizontalAlignment(), b 357 .getVerticalTextPosition(), b 358 .getHorizontalTextPosition(), viewR, iconR, textR, 359 (text == null ? 0 : b.getIconTextGap())); 360 361 /* 362 * The preferred size of the button is the size of the text and icon 363 * rectangles plus the buttons insets. 364 */ 365 366 Rectangle r = iconR.union(textR); 367 368 Insets insets = b.getInsets(); 369 r.width += insets.left + insets.right; 370 r.height += insets.top + insets.bottom; 371 // PENDING JW: why not? 372 // r.x -= insets.left; 373 r.y -= insets.top; 374 return r; 375 } 376 377 /** 378 * A BasicButtonListener specialized to the needs of a Hyperlink. 379 * 380 * @author Jeanette Winzenburg 381 */ 382 public static class BasicHyperlinkListener extends BasicButtonListener { 383 384 /** 385 * @param b 386 */ 387 public BasicHyperlinkListener(AbstractButton b) { 388 super(b); 389 } 390 391 392 @Override 393 public void stateChanged(ChangeEvent e) { 394 AbstractButton button = (AbstractButton) e.getSource(); 395 if (button.isRolloverEnabled()) { 396 button.setCursor(button.getModel().isRollover() ? 397 // PENDING JW: support customizable cursor 398 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) : null); 399 } 400 super.stateChanged(e); 401 } 402 } 403 404 static class ULHtml extends BasicHTML { 405 /** 406 * Create an html renderer for the given component and 407 * string of html. 408 */ 409 public static View createHTMLView(JComponent c, String html) { 410 BasicEditorKit kit = getFactory(); 411 Document doc = kit.createDefaultDocument(c.getFont(), 412 c.getForeground()); 413 Object base = c.getClientProperty(documentBaseKey); 414 if (base instanceof URL) { 415 ((HTMLDocument)doc).setBase((URL)base); 416 } 417 Reader r = new StringReader(html); 418 try { 419 kit.read(r, doc, 0); 420 } catch (Throwable e) { 421 } 422 ViewFactory f = kit.getViewFactory(); 423 View hview = f.create(doc.getDefaultRootElement()); 424 View v = new Renderer(c, f, hview); 425 return v; 426 } 427 428 static BasicEditorKit getFactory() { 429 if (basicHTMLFactory == null) { 430 basicHTMLViewFactory = new BasicHTMLViewFactory(); 431 basicHTMLFactory = new BasicEditorKit(); 432 } 433 return basicHTMLFactory; 434 } 435 436 /** 437 * The source of the html renderers 438 */ 439 private static BasicEditorKit basicHTMLFactory; 440 441 /** 442 * Creates the Views that visually represent the model. 443 */ 444 private static ViewFactory basicHTMLViewFactory; 445 446 /** 447 * Overrides to the default stylesheet. Should consider 448 * just creating a completely fresh stylesheet. 449 */ 450 private static final String styleChanges = 451 "p { margin-top: 0; margin-bottom: 0; margin-left: 0; margin-right: 0; text-decoration: underline }" + 452 "body { margin-top: 0; margin-bottom: 0; margin-left: 0; margin-right: 0; text-decoration: underline }"+ 453 "font {text-decoration: underline}"; 454 455 static class BasicEditorKit extends HTMLEditorKit { 456 /** Shared base style for all documents created by us use. */ 457 private static StyleSheet defaultStyles; 458 459 /** 460 * Overriden to return our own slimmed down style sheet. 461 */ 462 @Override 463 public StyleSheet getStyleSheet() { 464 if (defaultStyles == null) { 465 defaultStyles = new StyleSheet(); 466 StringReader r = new StringReader(styleChanges); 467 try { 468 defaultStyles.loadRules(r, null); 469 } catch (Throwable e) { 470 // don't want to die in static initialization... 471 // just display things wrong. 472 } 473 r.close(); 474 defaultStyles.addStyleSheet(super.getStyleSheet()); 475 } 476 return defaultStyles; 477 } 478 479 /** 480 * Sets the async policy to flush everything in one chunk, and 481 * to not display unknown tags. 482 */ 483 public Document createDefaultDocument(Font defaultFont, 484 Color foreground) { 485 StyleSheet styles = getStyleSheet(); 486 StyleSheet ss = new StyleSheet(); 487 ss.addStyleSheet(styles); 488 BasicDocument doc = new BasicDocument(ss, defaultFont, foreground); 489 doc.setAsynchronousLoadPriority(Integer.MAX_VALUE); 490 doc.setPreservesUnknownTags(false); 491 return doc; 492 } 493 494 /** 495 * Returns the ViewFactory that is used to make sure the Views don't 496 * load in the background. 497 */ 498 @Override 499 public ViewFactory getViewFactory() { 500 return basicHTMLViewFactory; 501 } 502 } 503 504 505 /** 506 * BasicHTMLViewFactory extends HTMLFactory to force images to be loaded 507 * synchronously. 508 */ 509 static class BasicHTMLViewFactory extends HTMLEditorKit.HTMLFactory { 510 @Override 511 public View create(Element elem) { 512 View view = super.create(elem); 513 514 if (view instanceof ImageView) { 515 ((ImageView)view).setLoadsSynchronously(true); 516 } 517 return view; 518 } 519 } 520 521 522 /** 523 * The subclass of HTMLDocument that is used as the model. getForeground 524 * is overridden to return the foreground property from the Component this 525 * was created for. 526 */ 527 static class BasicDocument extends HTMLDocument { 528 private static Class<?> clz; 529 private static Method displayPropertiesToCSS; 530 531 /** The host, that is where we are rendering. */ 532 // private JComponent host; 533 // --------- 1.5 x 1.6 incompatibility handling .... 534 static { 535 String j5 = "com.sun.java.swing.SwingUtilities2"; 536 String j6 = "sun.swing.SwingUtilities2"; 537 try { 538 // assume 1.6 539 clz = Class.forName(j6); 540 } catch (ClassNotFoundException e) { 541 // or maybe not .. 542 try { 543 clz = Class.forName(j5); 544 } catch (ClassNotFoundException e1) { 545 throw new RuntimeException("Failed to find SwingUtilities2. Check the classpath."); 546 } 547 } 548 try { 549 displayPropertiesToCSS = clz.getMethod("displayPropertiesToCSS", new Class[] { Font.class, Color.class}); 550 } catch (Exception e) { 551 throw new RuntimeException("Failed to use SwingUtilities2. Check the permissions and class version."); 552 } 553 } 554 555 private static String displayPropertiesToCSS(Font f, Color c) { 556 try { 557 return (String) displayPropertiesToCSS.invoke(null, new Object[] { f, c }); 558 } catch (Exception e) { 559 throw new RuntimeException(e); 560 } 561 } 562 563 // --------- EO 1.5 x 1.6 incompatibility handling .... 564 565 BasicDocument(StyleSheet s, Font defaultFont, Color foreground) { 566 super(s); 567 setPreservesUnknownTags(false); 568 setFontAndColor(defaultFont, foreground); 569 } 570 571 /** 572 * Sets the default font and default color. These are set by 573 * adding a rule for the body that specifies the font and color. 574 * This allows the html to override these should it wish to have 575 * a custom font or color. 576 */ 577 private void setFontAndColor(Font font, Color fg) { 578 getStyleSheet().addRule(displayPropertiesToCSS(font,fg)); 579 } 580 } 581 582 583 /** 584 * Root text view that acts as an HTML renderer. 585 */ 586 static class Renderer extends View { 587 588 Renderer(JComponent c, ViewFactory f, View v) { 589 super(null); 590 host = c; 591 factory = f; 592 view = v; 593 view.setParent(this); 594 // initially layout to the preferred size 595 setSize(view.getPreferredSpan(X_AXIS), view.getPreferredSpan(Y_AXIS)); 596 } 597 598 /** 599 * Fetches the attributes to use when rendering. At the root 600 * level there are no attributes. If an attribute is resolved 601 * up the view hierarchy this is the end of the line. 602 */ 603 @Override 604 public AttributeSet getAttributes() { 605 return null; 606 } 607 608 /** 609 * Determines the preferred span for this view along an axis. 610 * 611 * @param axis may be either X_AXIS or Y_AXIS 612 * @return the span the view would like to be rendered into. 613 * Typically the view is told to render into the span 614 * that is returned, although there is no guarantee. 615 * The parent may choose to resize or break the view. 616 */ 617 @Override 618 public float getPreferredSpan(int axis) { 619 if (axis == X_AXIS) { 620 // width currently laid out to 621 return width; 622 } 623 return view.getPreferredSpan(axis); 624 } 625 626 /** 627 * Determines the minimum span for this view along an axis. 628 * 629 * @param axis may be either X_AXIS or Y_AXIS 630 * @return the span the view would like to be rendered into. 631 * Typically the view is told to render into the span 632 * that is returned, although there is no guarantee. 633 * The parent may choose to resize or break the view. 634 */ 635 @Override 636 public float getMinimumSpan(int axis) { 637 return view.getMinimumSpan(axis); 638 } 639 640 /** 641 * Determines the maximum span for this view along an axis. 642 * 643 * @param axis may be either X_AXIS or Y_AXIS 644 * @return the span the view would like to be rendered into. 645 * Typically the view is told to render into the span 646 * that is returned, although there is no guarantee. 647 * The parent may choose to resize or break the view. 648 */ 649 @Override 650 public float getMaximumSpan(int axis) { 651 return Integer.MAX_VALUE; 652 } 653 654 /** 655 * Specifies that a preference has changed. 656 * Child views can call this on the parent to indicate that 657 * the preference has changed. The root view routes this to 658 * invalidate on the hosting component. 659 * <p> 660 * This can be called on a different thread from the 661 * event dispatching thread and is basically unsafe to 662 * propagate into the component. To make this safe, 663 * the operation is transferred over to the event dispatching 664 * thread for completion. It is a design goal that all view 665 * methods be safe to call without concern for concurrency, 666 * and this behavior helps make that true. 667 * 668 * @param child the child view 669 * @param width true if the width preference has changed 670 * @param height true if the height preference has changed 671 */ 672 @Override 673 public void preferenceChanged(View child, boolean width, boolean height) { 674 host.revalidate(); 675 host.repaint(); 676 } 677 678 /** 679 * Determines the desired alignment for this view along an axis. 680 * 681 * @param axis may be either X_AXIS or Y_AXIS 682 * @return the desired alignment, where 0.0 indicates the origin 683 * and 1.0 the full span away from the origin 684 */ 685 @Override 686 public float getAlignment(int axis) { 687 return view.getAlignment(axis); 688 } 689 690 /** 691 * Renders the view. 692 * 693 * @param g the graphics context 694 * @param allocation the region to render into 695 */ 696 @Override 697 public void paint(Graphics g, Shape allocation) { 698 Rectangle alloc = allocation.getBounds(); 699 view.setSize(alloc.width, alloc.height); 700 view.paint(g, allocation); 701 } 702 703 /** 704 * Sets the view parent. 705 * 706 * @param parent the parent view 707 */ 708 @Override 709 public void setParent(View parent) { 710 throw new Error("Can't set parent on root view"); 711 } 712 713 /** 714 * Returns the number of views in this view. Since 715 * this view simply wraps the root of the view hierarchy 716 * it has exactly one child. 717 * 718 * @return the number of views 719 * @see #getView 720 */ 721 @Override 722 public int getViewCount() { 723 return 1; 724 } 725 726 /** 727 * Gets the n-th view in this container. 728 * 729 * @param n the number of the view to get 730 * @return the view 731 */ 732 @Override 733 public View getView(int n) { 734 return view; 735 } 736 737 /** 738 * Provides a mapping from the document model coordinate space 739 * to the coordinate space of the view mapped to it. 740 * 741 * @param pos the position to convert 742 * @param a the allocated region to render into 743 * @return the bounding box of the given position 744 */ 745 @Override 746 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 747 return view.modelToView(pos, a, b); 748 } 749 750 /** 751 * Provides a mapping from the document model coordinate space 752 * to the coordinate space of the view mapped to it. 753 * 754 * @param p0 the position to convert >= 0 755 * @param b0 the bias toward the previous character or the 756 * next character represented by p0, in case the 757 * position is a boundary of two views. 758 * @param p1 the position to convert >= 0 759 * @param b1 the bias toward the previous character or the 760 * next character represented by p1, in case the 761 * position is a boundary of two views. 762 * @param a the allocated region to render into 763 * @return the bounding box of the given position is returned 764 * @exception BadLocationException if the given position does 765 * not represent a valid location in the associated document 766 * @exception IllegalArgumentException for an invalid bias argument 767 * @see View#viewToModel 768 */ 769 @Override 770 public Shape modelToView(int p0, Position.Bias b0, int p1, 771 Position.Bias b1, Shape a) throws BadLocationException { 772 return view.modelToView(p0, b0, p1, b1, a); 773 } 774 775 /** 776 * Provides a mapping from the view coordinate space to the logical 777 * coordinate space of the model. 778 * 779 * @param x x coordinate of the view location to convert 780 * @param y y coordinate of the view location to convert 781 * @param a the allocated region to render into 782 * @return the location within the model that best represents the 783 * given point in the view 784 */ 785 @Override 786 public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { 787 return view.viewToModel(x, y, a, bias); 788 } 789 790 /** 791 * Returns the document model underlying the view. 792 * 793 * @return the model 794 */ 795 @Override 796 public Document getDocument() { 797 return view.getDocument(); 798 } 799 800 /** 801 * Returns the starting offset into the model for this view. 802 * 803 * @return the starting offset 804 */ 805 @Override 806 public int getStartOffset() { 807 return view.getStartOffset(); 808 } 809 810 /** 811 * Returns the ending offset into the model for this view. 812 * 813 * @return the ending offset 814 */ 815 @Override 816 public int getEndOffset() { 817 return view.getEndOffset(); 818 } 819 820 /** 821 * Gets the element that this view is mapped to. 822 * 823 * @return the view 824 */ 825 @Override 826 public Element getElement() { 827 return view.getElement(); 828 } 829 830 /** 831 * Sets the view size. 832 * 833 * @param width the width 834 * @param height the height 835 */ 836 @Override 837 public void setSize(float width, float height) { 838 this.width = (int) width; 839 view.setSize(width, height); 840 } 841 842 /** 843 * Fetches the container hosting the view. This is useful for 844 * things like scheduling a repaint, finding out the host 845 * components font, etc. The default implementation 846 * of this is to forward the query to the parent view. 847 * 848 * @return the container 849 */ 850 @Override 851 public Container getContainer() { 852 return host; 853 } 854 855 /** 856 * Fetches the factory to be used for building the 857 * various view fragments that make up the view that 858 * represents the model. This is what determines 859 * how the model will be represented. This is implemented 860 * to fetch the factory provided by the associated 861 * EditorKit. 862 * 863 * @return the factory 864 */ 865 @Override 866 public ViewFactory getViewFactory() { 867 return factory; 868 } 869 870 private int width; 871 private View view; 872 private ViewFactory factory; 873 private JComponent host; 874 875 } 876 } 877 }