GNU Classpath (0.19) | ||
Frames | No Frames |
1: /* JViewport.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; 40: 41: import java.awt.Component; 42: import java.awt.Dimension; 43: import java.awt.Graphics; 44: import java.awt.Image; 45: import java.awt.Insets; 46: import java.awt.LayoutManager; 47: import java.awt.Point; 48: import java.awt.Rectangle; 49: import java.awt.event.ComponentAdapter; 50: import java.awt.event.ComponentEvent; 51: import java.io.Serializable; 52: 53: import javax.accessibility.Accessible; 54: import javax.accessibility.AccessibleContext; 55: import javax.accessibility.AccessibleRole; 56: import javax.swing.border.Border; 57: import javax.swing.event.ChangeEvent; 58: import javax.swing.event.ChangeListener; 59: import javax.swing.plaf.ViewportUI; 60: 61: /** 62: * 63: * <pre> 64: * _ 65: * +-------------------------------+ ...........Y1 \ 66: * | view | . \ 67: * | (this component's child) | . > VY 68: * | | . / = Y2-Y1 69: * | +------------------------------+ ....Y2_/ 70: * | | viewport | | . 71: * | | (this component) | | . 72: * | | | | . 73: * | | | | . 74: * | | | | . 75: * | | | | . 76: * | +------------------------------+ ....Y3 77: * | | . 78: * | . | . . 79: * | . | . . 80: * +---------.---------------------+ ...........Y4 81: * . . . . 82: * . . . . 83: * . . . . 84: * X1.......X2.....................X3.......X4 85: * \____ ___/ 86: * \/ 87: * VX = X2-X1 88: *</pre> 89: * 90: * <p>A viewport is, like all swing components, located at some position in 91: * the swing component tree; that location is exactly the same as any other 92: * components: the viewport's "bounds".</p> 93: * 94: * <p>But in terms of drawing its child, the viewport thinks of itself as 95: * covering a particular position <em>of the view's coordinate space</em>. 96: * For example, the {@link #getViewPosition} method returns 97: * the position <code>(VX,VY)</code> shown above, which is an position in 98: * "view space", even though this is <em>implemented</em> by positioning 99: * the underlying child at position <code>(-VX,-VY)</code></p> 100: * 101: */ 102: public class JViewport extends JComponent implements Accessible 103: { 104: /** 105: * Provides accessibility support for <code>JViewport</code>. 106: * 107: * @author Roman Kennke (roman@kennke.org) 108: */ 109: protected class AccessibleJViewport extends AccessibleJComponent 110: { 111: /** 112: * Creates a new instance of <code>AccessibleJViewport</code>. 113: */ 114: public AccessibleJViewport() 115: { 116: // Nothing to do here. 117: } 118: 119: /** 120: * Returns the accessible role of <code>JViewport</code>, which is 121: * {@link AccessibleRole#VIEWPORT}. 122: * 123: * @return the accessible role of <code>JViewport</code> 124: */ 125: public AccessibleRole getAccessibleRole() 126: { 127: return AccessibleRole.VIEWPORT; 128: } 129: } 130: 131: /** 132: * A {@link java.awt.event.ComponentListener} that listens for 133: * changes of the view's size. This triggers a revalidate() call on the 134: * viewport. 135: */ 136: protected class ViewListener extends ComponentAdapter implements Serializable 137: { 138: private static final long serialVersionUID = -2812489404285958070L; 139: 140: /** 141: * Creates a new instance of ViewListener. 142: */ 143: protected ViewListener() 144: { 145: // Nothing to do here. 146: } 147: 148: /** 149: * Receives notification when a component (in this case: the view 150: * component) changes it's size. This simply triggers a revalidate() on the 151: * viewport. 152: * 153: * @param ev the ComponentEvent describing the change 154: */ 155: public void componentResized(ComponentEvent ev) 156: { 157: revalidate(); 158: } 159: } 160: 161: public static final int SIMPLE_SCROLL_MODE = 0; 162: public static final int BLIT_SCROLL_MODE = 1; 163: public static final int BACKINGSTORE_SCROLL_MODE = 2; 164: 165: private static final long serialVersionUID = -6925142919680527970L; 166: 167: protected boolean scrollUnderway; 168: protected boolean isViewSizeSet; 169: 170: /** 171: * This flag indicates whether we use a backing store for drawing. 172: * 173: * @deprecated since JDK 1.3 174: */ 175: protected boolean backingStore; 176: 177: /** 178: * The backingstore image used for the backingstore and blit scroll methods. 179: */ 180: protected Image backingStoreImage; 181: 182: /** 183: * The position at which the view has been drawn the last time. This is used 184: * to determine the bittable area. 185: */ 186: protected Point lastPaintPosition; 187: 188: ChangeEvent changeEvent = new ChangeEvent(this); 189: 190: int scrollMode; 191: 192: /** 193: * The width and height of the Viewport's area in terms of view 194: * coordinates. Typically this will be the same as the width and height 195: * of the viewport's bounds, unless the viewport transforms units of 196: * width and height, which it may do, for example if it magnifies or 197: * rotates its view. 198: * 199: * @see #toViewCoordinates(Dimension) 200: */ 201: Dimension extentSize; 202: 203: /** 204: * The width and height of the view in its own coordinate space. 205: */ 206: Dimension viewSize; 207: 208: /** 209: * The ViewListener instance. 210: */ 211: ViewListener viewListener; 212: 213: /** 214: * Stores the location from where to blit. This is a cached Point object used 215: * in blitting calculations. 216: */ 217: Point cachedBlitFrom; 218: 219: /** 220: * Stores the location where to blit to. This is a cached Point object used 221: * in blitting calculations. 222: */ 223: Point cachedBlitTo; 224: 225: /** 226: * Stores the width of the blitted area. This is a cached Dimension object 227: * used in blitting calculations. 228: */ 229: Dimension cachedBlitSize; 230: 231: /** 232: * Stores the bounds of the area that needs to be repainted. This is a cached 233: * Rectangle object used in blitting calculations. 234: */ 235: Rectangle cachedBlitPaint; 236: 237: boolean damaged = true; 238: 239: /** 240: * A flag indicating if the size of the viewport has changed since the 241: * last repaint. This is used in double buffered painting to check if we 242: * need a new double buffer, or can reuse the old one. 243: */ 244: boolean sizeChanged = true; 245: 246: public JViewport() 247: { 248: setOpaque(true); 249: setScrollMode(BLIT_SCROLL_MODE); 250: updateUI(); 251: setLayout(createLayoutManager()); 252: lastPaintPosition = new Point(); 253: cachedBlitFrom = new Point(); 254: cachedBlitTo = new Point(); 255: cachedBlitSize = new Dimension(); 256: cachedBlitPaint = new Rectangle(); 257: } 258: 259: public Dimension getExtentSize() 260: { 261: if (extentSize == null) 262: return toViewCoordinates(getSize()); 263: else 264: return extentSize; 265: } 266: 267: public Dimension toViewCoordinates(Dimension size) 268: { 269: return size; 270: } 271: 272: public Point toViewCoordinates(Point p) 273: { 274: Point pos = getViewPosition(); 275: return new Point(p.x + pos.x, 276: p.y + pos.y); 277: } 278: 279: public void setExtentSize(Dimension newSize) 280: { 281: extentSize = newSize; 282: fireStateChanged(); 283: } 284: 285: /** 286: * Returns the viewSize when set, or the preferred size of the set 287: * Component view. If no viewSize and no Component view is set an 288: * empty Dimension is returned. 289: */ 290: public Dimension getViewSize() 291: { 292: if (isViewSizeSet) 293: return viewSize; 294: else 295: { 296: Component view = getView(); 297: if (view != null) 298: return view.getPreferredSize(); 299: else 300: return new Dimension(); 301: } 302: } 303: 304: 305: public void setViewSize(Dimension newSize) 306: { 307: viewSize = newSize; 308: Component view = getView(); 309: if (view != null) 310: { 311: if (newSize != view.getSize()) 312: { 313: view.setSize(viewSize); 314: fireStateChanged(); 315: } 316: } 317: isViewSizeSet = true; 318: } 319: 320: /** 321: * Get the viewport's position in view space. Despite confusing name, 322: * this really does return the viewport's (0,0) position in view space, 323: * not the view's position. 324: */ 325: 326: public Point getViewPosition() 327: { 328: Component view = getView(); 329: if (view == null) 330: return new Point(0,0); 331: else 332: { 333: Point p = view.getLocation(); 334: p.x = -p.x; 335: p.y = -p.y; 336: return p; 337: } 338: } 339: 340: public void setViewPosition(Point p) 341: { 342: if (getViewPosition().equals(p)) 343: return; 344: Component view = getView(); 345: if (view != null) 346: { 347: Point q = new Point(-p.x, -p.y); 348: view.setLocation(q); 349: isViewSizeSet = false; 350: fireStateChanged(); 351: } 352: repaint(); 353: } 354: 355: public Rectangle getViewRect() 356: { 357: return new Rectangle(getViewPosition(), 358: getExtentSize()); 359: } 360: 361: /** 362: * @deprecated 1.4 363: */ 364: public boolean isBackingStoreEnabled() 365: { 366: return scrollMode == BACKINGSTORE_SCROLL_MODE; 367: } 368: 369: /** 370: * @deprecated 1.4 371: */ 372: public void setBackingStoreEnabled(boolean b) 373: { 374: if (b && scrollMode != BACKINGSTORE_SCROLL_MODE) 375: { 376: scrollMode = BACKINGSTORE_SCROLL_MODE; 377: fireStateChanged(); 378: } 379: } 380: 381: public void setScrollMode(int mode) 382: { 383: scrollMode = mode; 384: fireStateChanged(); 385: } 386: 387: public int getScrollMode() 388: { 389: return scrollMode; 390: } 391: 392: public Component getView() 393: { 394: if (getComponentCount() == 0) 395: return null; 396: 397: return getComponents()[0]; 398: } 399: 400: public void setView(Component v) 401: { 402: if (viewListener != null) 403: getView().removeComponentListener(viewListener); 404: 405: if (v != null) 406: { 407: if (viewListener == null) 408: viewListener = createViewListener(); 409: v.addComponentListener(viewListener); 410: add(v); 411: fireStateChanged(); 412: } 413: revalidate(); 414: repaint(); 415: } 416: 417: public void reshape(int x, int y, int w, int h) 418: { 419: if (w != getWidth() || h != getHeight()) 420: sizeChanged = true; 421: super.reshape(x, y, w, h); 422: if (sizeChanged) 423: { 424: damaged = true; 425: fireStateChanged(); 426: } 427: } 428: 429: public final Insets getInsets() 430: { 431: return new Insets(0, 0, 0, 0); 432: } 433: 434: public final Insets getInsets(Insets insets) 435: { 436: if (insets == null) 437: return getInsets(); 438: insets.top = 0; 439: insets.bottom = 0; 440: insets.left = 0; 441: insets.right = 0; 442: return insets; 443: } 444: 445: 446: /** 447: * Overridden to return <code>false</code>, so the JViewport's paint method 448: * gets called instead of directly calling the children. This is necessary 449: * in order to get a useful clipping and translation on the children. 450: * 451: * @return <code>false</code> 452: */ 453: public boolean isOptimizedDrawingEnabled() 454: { 455: return false; 456: } 457: 458: public void paint(Graphics g) 459: { 460: Component view = getView(); 461: 462: if (view == null) 463: return; 464: 465: Point pos = getViewPosition(); 466: Rectangle viewBounds = view.getBounds(); 467: Rectangle portBounds = getBounds(); 468: 469: if (viewBounds.width == 0 470: || viewBounds.height == 0 471: || portBounds.width == 0 472: || portBounds.height == 0) 473: return; 474: 475: switch (getScrollMode()) 476: { 477: 478: case JViewport.BACKINGSTORE_SCROLL_MODE: 479: paintBackingStore(g); 480: break; 481: case JViewport.BLIT_SCROLL_MODE: 482: paintBlit(g); 483: break; 484: case JViewport.SIMPLE_SCROLL_MODE: 485: default: 486: paintSimple(g); 487: break; 488: } 489: damaged = false; 490: } 491: 492: public void addChangeListener(ChangeListener listener) 493: { 494: listenerList.add(ChangeListener.class, listener); 495: } 496: 497: public void removeChangeListener(ChangeListener listener) 498: { 499: listenerList.remove(ChangeListener.class, listener); 500: } 501: 502: public ChangeListener[] getChangeListeners() 503: { 504: return (ChangeListener[]) getListeners(ChangeListener.class); 505: } 506: 507: /** 508: * This method returns the String ID of the UI class of Separator. 509: * 510: * @return The UI class' String ID. 511: */ 512: public String getUIClassID() 513: { 514: return "ViewportUI"; 515: } 516: 517: /** 518: * This method resets the UI used to the Look and Feel defaults.. 519: */ 520: public void updateUI() 521: { 522: setUI((ViewportUI) UIManager.getUI(this)); 523: } 524: 525: /** 526: * This method returns the viewport's UI delegate. 527: * 528: * @return The viewport's UI delegate. 529: */ 530: public ViewportUI getUI() 531: { 532: return (ViewportUI) ui; 533: } 534: 535: /** 536: * This method sets the viewport's UI delegate. 537: * 538: * @param ui The viewport's UI delegate. 539: */ 540: public void setUI(ViewportUI ui) 541: { 542: super.setUI(ui); 543: } 544: 545: public final void setBorder(Border border) 546: { 547: if (border != null) 548: throw new IllegalArgumentException(); 549: } 550: 551: /** 552: * Scrolls the view so that contentRect becomes visible. 553: * 554: * @param contentRect the rectangle to make visible within the view 555: */ 556: public void scrollRectToVisible(Rectangle contentRect) 557: { 558: Component view = getView(); 559: if (view == null) 560: return; 561: 562: Point pos = getViewPosition(); 563: Rectangle viewBounds = getView().getBounds(); 564: Rectangle portBounds = getBounds(); 565: 566: if (isShowing()) 567: getView().validate(); 568: 569: // If the bottom boundary of contentRect is below the port 570: // boundaries, scroll up as necessary. 571: if (contentRect.y + contentRect.height + viewBounds.y > portBounds.height) 572: pos.y = contentRect.y + contentRect.height - portBounds.height; 573: // If contentRect.y is above the port boundaries, scroll down to 574: // contentRect.y. 575: if (contentRect.y + viewBounds.y < 0) 576: pos.y = contentRect.y; 577: // If the right boundary of contentRect is right from the port 578: // boundaries, scroll left as necessary. 579: if (contentRect.x + contentRect.width + viewBounds.x > portBounds.width) 580: pos.x = contentRect.x + contentRect.width - portBounds.width; 581: // If contentRect.x is left from the port boundaries, scroll right to 582: // contentRect.x. 583: if (contentRect.x + viewBounds.x < 0) 584: pos.x = contentRect.x; 585: setViewPosition(pos); 586: } 587: 588: /** 589: * Returns the accessible context for this <code>JViewport</code>. This 590: * will be an instance of {@link AccessibleJViewport}. 591: * 592: * @return the accessible context for this <code>JViewport</code> 593: */ 594: public AccessibleContext getAccessibleContext() 595: { 596: if (accessibleContext == null) 597: accessibleContext = new AccessibleJViewport(); 598: return accessibleContext; 599: } 600: 601: /** 602: * Forward repaint to parent to make sure only one paint is performed by the 603: * RepaintManager. 604: * 605: * @param tm number of milliseconds to defer the repaint request 606: * @param x the X coordinate of the upper left corner of the dirty area 607: * @param y the Y coordinate of the upper left corner of the dirty area 608: * @param w the width of the dirty area 609: * @param h the height of the dirty area 610: */ 611: public void repaint(long tm, int x, int y, int w, int h) 612: { 613: Component parent = getParent(); 614: if (parent != null) 615: { 616: parent.repaint(tm, x + getX(), y + getY(), w, h); 617: } 618: } 619: 620: protected void addImpl(Component comp, Object constraints, int index) 621: { 622: if (getComponentCount() > 0) 623: remove(getComponents()[0]); 624: 625: super.addImpl(comp, constraints, index); 626: } 627: 628: protected void fireStateChanged() 629: { 630: ChangeListener[] listeners = getChangeListeners(); 631: for (int i = 0; i < listeners.length; ++i) 632: listeners[i].stateChanged(changeEvent); 633: } 634: 635: /** 636: * Creates a {@link ViewListener} that is supposed to listen for 637: * size changes on the view component. 638: * 639: * @return a ViewListener instance 640: */ 641: protected ViewListener createViewListener() 642: { 643: return new ViewListener(); 644: } 645: 646: /** 647: * Creates the LayoutManager that is used for this viewport. Override 648: * this method if you want to use a custom LayoutManager. 649: * 650: * @return a LayoutManager to use for this viewport 651: */ 652: protected LayoutManager createLayoutManager() 653: { 654: return new ViewportLayout(); 655: } 656: 657: /** 658: * Computes the parameters for the blitting scroll method. <code>dx</code> 659: * and <code>dy</code> specifiy the X and Y offset by which the viewport 660: * is scrolled. All other arguments are output parameters and are filled by 661: * this method. 662: * 663: * <code>blitFrom</code> holds the position of the blit rectangle in the 664: * viewport rectangle before scrolling, <code>blitTo</code> where the blitArea 665: * is copied to. 666: * 667: * <code>blitSize</code> holds the size of the blit area and 668: * <code>blitPaint</code> is the area of the view that needs to be painted. 669: * 670: * This method returns <code>true</code> if blitting is possible and 671: * <code>false</code> if the viewport has to be repainted completetly without 672: * blitting. 673: * 674: * @param dx the horizontal delta 675: * @param dy the vertical delta 676: * @param blitFrom the position from where to blit; set by this method 677: * @param blitTo the position where to blit area is copied to; set by this 678: * method 679: * @param blitSize the size of the blitted area; set by this method 680: * @param blitPaint the area that needs repainting; set by this method 681: * 682: * @return <code>true</code> if blitting is possible, 683: * <code>false</code> otherwise 684: */ 685: protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo, 686: Dimension blitSize, Rectangle blitPaint) 687: { 688: if ((dx != 0 && dy != 0) || damaged) 689: // We cannot blit if the viewport is scrolled in both directions at 690: // once. 691: return false; 692: 693: Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds()); 694: 695: // Compute the blitFrom and blitTo parameters. 696: blitFrom.x = portBounds.x; 697: blitFrom.y = portBounds.y; 698: blitTo.x = portBounds.x; 699: blitTo.y = portBounds.y; 700: 701: if (dy > 0) 702: { 703: blitFrom.y = portBounds.y + dy; 704: } 705: else if (dy < 0) 706: { 707: blitTo.y = portBounds.y - dy; 708: } 709: else if (dx > 0) 710: { 711: blitFrom.x = portBounds.x + dx; 712: } 713: else if (dx < 0) 714: { 715: blitTo.x = portBounds.x - dx; 716: } 717: 718: // Compute size of the blit area. 719: if (dx != 0) 720: { 721: blitSize.width = portBounds.width - Math.abs(dx); 722: blitSize.height = portBounds.height; 723: } 724: else if (dy != 0) 725: { 726: blitSize.width = portBounds.width; 727: blitSize.height = portBounds.height - Math.abs(dy); 728: } 729: 730: // Compute the blitPaint parameter. 731: blitPaint.setBounds(portBounds); 732: if (dy > 0) 733: { 734: blitPaint.y = portBounds.y + portBounds.height - dy; 735: blitPaint.height = dy; 736: } 737: else if (dy < 0) 738: { 739: blitPaint.height = -dy; 740: } 741: if (dx > 0) 742: { 743: blitPaint.x = portBounds.x + portBounds.width - dx; 744: blitPaint.width = dx; 745: } 746: else if (dx < 0) 747: { 748: blitPaint.width = -dx; 749: } 750: 751: return true; 752: } 753: 754: /** 755: * Paints the viewport in case we have a scrollmode of 756: * {@link #SIMPLE_SCROLL_MODE}. 757: * 758: * This simply paints the view directly on the surface of the viewport. 759: * 760: * @param g the graphics context to use 761: */ 762: void paintSimple(Graphics g) 763: { 764: Point pos = getViewPosition(); 765: Component view = getView(); 766: boolean translated = false; 767: try 768: { 769: g.translate(-pos.x, -pos.y); 770: translated = true; 771: view.paint(g); 772: } 773: finally 774: { 775: if (translated) 776: g.translate (pos.x, pos.y); 777: } 778: } 779: 780: /** 781: * Paints the viewport in case we have a scroll mode of 782: * {@link #BACKINGSTORE_SCROLL_MODE}. 783: * 784: * This method uses a backing store image to paint the view to, which is then 785: * subsequently painted on the screen. This should make scrolling more 786: * smooth. 787: * 788: * @param g the graphics context to use 789: */ 790: void paintBackingStore(Graphics g) 791: { 792: // If we have no backing store image yet or the size of the component has 793: // changed, we need to rebuild the backing store. 794: if (backingStoreImage == null || sizeChanged) 795: { 796: backingStoreImage = createImage(getWidth(), getHeight()); 797: sizeChanged = false; 798: Graphics g2 = backingStoreImage.getGraphics(); 799: paintSimple(g2); 800: g2.dispose(); 801: } 802: // Otherwise we can perform the blitting on the backing store image: 803: // First we move the part that remains visible after scrolling, then 804: // we only need to paint the bit that becomes newly visible. 805: else 806: { 807: Graphics g2 = backingStoreImage.getGraphics(); 808: Point viewPosition = getViewPosition(); 809: int dx = viewPosition.x - lastPaintPosition.x; 810: int dy = viewPosition.y - lastPaintPosition.y; 811: boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo, 812: cachedBlitSize, cachedBlitPaint); 813: if (canBlit) 814: { 815: // Copy the part that remains visible during scrolling. 816: g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y, 817: cachedBlitSize.width, cachedBlitSize.height, 818: cachedBlitTo.x - cachedBlitFrom.x, 819: cachedBlitTo.y - cachedBlitFrom.y); 820: // Now paint the part that becomes newly visible. 821: g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y, 822: cachedBlitPaint.width, cachedBlitPaint.height); 823: paintSimple(g2); 824: } 825: // If blitting is not possible for some reason, fall back to repainting 826: // everything. 827: else 828: { 829: paintSimple(g2); 830: } 831: g2.dispose(); 832: } 833: // Actually draw the backingstore image to the graphics context. 834: g.drawImage(backingStoreImage, 0, 0, this); 835: // Update the lastPaintPosition so that we know what is already drawn when 836: // we paint the next time. 837: lastPaintPosition.setLocation(getViewPosition()); 838: } 839: 840: /** 841: * Paints the viewport in case we have a scrollmode of 842: * {@link #BLIT_SCROLL_MODE}. 843: * 844: * This paints the viewport using a backingstore and a blitting algorithm. 845: * Only the newly exposed area of the view is painted from the view painting 846: * methods, the remainder is copied from the backing store. 847: * 848: * @param g the graphics context to use 849: */ 850: void paintBlit(Graphics g) 851: { 852: // We cannot perform blitted painting as it is described in Sun's API docs. 853: // There it is suggested that this painting method should blit directly 854: // on the parent window's surface. This is not possible because when using 855: // Swing's double buffering (at least our implementation), it would 856: // immediatly be painted when the buffer is painted on the screen. For this 857: // to work we would need a kind of hole in the buffer image. And honestly 858: // I find this method not very elegant. 859: // The alternative, blitting directly on the buffer image, is also not 860: // possible because the buffer image gets cleared everytime when an opaque 861: // parent component is drawn on it. 862: 863: // What we do instead is falling back to the backing store approach which 864: // is in fact a mixed blitting/backing store approach where the blitting 865: // is performed on the backing store image and this is then drawn to the 866: // graphics context. This is very robust and works independent of the 867: // painting mechanism that is used by Swing. And it should have comparable 868: // performance characteristics as the blitting method. 869: paintBackingStore(g); 870: } 871: }
GNU Classpath (0.19) |