OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [javax/] [swing/] [JViewport.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* 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
    String scrollModeProp =
250
      System.getProperty("gnu.javax.swing.JViewport.scrollMode",
251
                         "BLIT");
252
    int myScrollMode;
253
    if (scrollModeProp.equalsIgnoreCase("simple"))
254
      myScrollMode = SIMPLE_SCROLL_MODE;
255
    else if (scrollModeProp.equalsIgnoreCase("backingstore"))
256
      myScrollMode = BACKINGSTORE_SCROLL_MODE;
257
    else
258
      myScrollMode = BLIT_SCROLL_MODE;
259
    setScrollMode(myScrollMode);
260
 
261
    updateUI();
262
    setLayout(createLayoutManager());
263
    lastPaintPosition = new Point();
264
    cachedBlitFrom = new Point();
265
    cachedBlitTo = new Point();
266
    cachedBlitSize = new Dimension();
267
    cachedBlitPaint = new Rectangle();
268
  }
269
 
270
  public Dimension getExtentSize()
271
  {
272
    if (extentSize == null)
273
      return toViewCoordinates(getSize());
274
    else
275
      return extentSize;
276
  }
277
 
278
  public Dimension toViewCoordinates(Dimension size)
279
  {
280
    return size;
281
  }
282
 
283
  public Point toViewCoordinates(Point p)
284
  {
285
    Point pos = getViewPosition();
286
    return new Point(p.x + pos.x,
287
                     p.y + pos.y);
288
  }
289
 
290
  public void setExtentSize(Dimension newSize)
291
  {
292
    extentSize = newSize;
293
    fireStateChanged();
294
  }
295
 
296
  /**
297
   * Returns the viewSize when set, or the preferred size of the set
298
   * Component view.  If no viewSize and no Component view is set an
299
   * empty Dimension is returned.
300
   */
301
  public Dimension getViewSize()
302
  {
303
    if (isViewSizeSet)
304
      return viewSize;
305
    else
306
      {
307
        Component view = getView();
308
        if (view != null)
309
          return view.getPreferredSize();
310
        else
311
          return new Dimension();
312
      }
313
  }
314
 
315
 
316
  public void setViewSize(Dimension newSize)
317
  {
318
    viewSize = newSize;
319
    Component view = getView();
320
    if (view != null)
321
      {
322
        if (newSize != view.getSize())
323
          {
324
            view.setSize(viewSize);
325
            fireStateChanged();
326
          }
327
      }
328
    isViewSizeSet = true;
329
  }
330
 
331
  /**
332
   * Get the viewport's position in view space. Despite confusing name,
333
   * this really does return the viewport's (0,0) position in view space,
334
   * not the view's position.
335
   */
336
 
337
  public Point getViewPosition()
338
  {
339
    Component view = getView();
340
    if (view == null)
341
      return new Point(0,0);
342
    else
343
      {
344
        Point p = view.getLocation();
345
        p.x = -p.x;
346
        p.y = -p.y;
347
        return p;
348
      }
349
  }
350
 
351
  public void setViewPosition(Point p)
352
  {
353
    if (getViewPosition().equals(p))
354
      return;
355
    Component view = getView();
356
    if (view != null)
357
      {
358
        Point q = new Point(-p.x, -p.y);
359
        view.setLocation(q);
360
        isViewSizeSet = false;
361
        fireStateChanged();
362
      }
363
    repaint();
364
  }
365
 
366
  public Rectangle getViewRect()
367
  {
368
    return new Rectangle(getViewPosition(),
369
                         getExtentSize());
370
  }
371
 
372
  /**
373
   * @deprecated 1.4
374
   */
375
  public boolean isBackingStoreEnabled()
376
  {
377
    return scrollMode == BACKINGSTORE_SCROLL_MODE;
378
  }
379
 
380
  /**
381
   * @deprecated 1.4
382
   */
383
  public void setBackingStoreEnabled(boolean b)
384
  {
385
    if (b && scrollMode != BACKINGSTORE_SCROLL_MODE)
386
      {
387
        scrollMode = BACKINGSTORE_SCROLL_MODE;
388
        fireStateChanged();
389
      }
390
  }
391
 
392
  public void setScrollMode(int mode)
393
  {
394
    scrollMode = mode;
395
    fireStateChanged();
396
  }
397
 
398
  public int getScrollMode()
399
  {
400
    return scrollMode;
401
  }
402
 
403
  public Component getView()
404
  {
405
    if (getComponentCount() == 0)
406
      return null;
407
 
408
    return getComponents()[0];
409
  }
410
 
411
  public void setView(Component v)
412
  {
413
    if (viewListener != null)
414
      getView().removeComponentListener(viewListener);
415
 
416
    if (v != null)
417
      {
418
        if (viewListener == null)
419
          viewListener = createViewListener();
420
        v.addComponentListener(viewListener);
421
        add(v);
422
        fireStateChanged();
423
      }
424
    revalidate();
425
    repaint();
426
  }
427
 
428
  public void reshape(int x, int y, int w, int h)
429
  {
430
    if (w != getWidth() || h != getHeight())
431
      sizeChanged = true;
432
    super.reshape(x, y, w, h);
433
    if (sizeChanged)
434
      {
435
        damaged = true;
436
        fireStateChanged();
437
      }
438
  }
439
 
440
  public final Insets getInsets()
441
  {
442
    return new Insets(0, 0, 0, 0);
443
  }
444
 
445
  public final Insets getInsets(Insets insets)
446
  {
447
    if (insets == null)
448
      return getInsets();
449
    insets.top = 0;
450
    insets.bottom = 0;
451
    insets.left = 0;
452
    insets.right = 0;
453
    return insets;
454
  }
455
 
456
 
457
  /**
458
   * Overridden to return <code>false</code>, so the JViewport's paint method
459
   * gets called instead of directly calling the children. This is necessary
460
   * in order to get a useful clipping and translation on the children.
461
   *
462
   * @return <code>false</code>
463
   */
464
  public boolean isOptimizedDrawingEnabled()
465
  {
466
    return false;
467
  }
468
 
469
  public void paint(Graphics g)
470
  {
471
    Component view = getView();
472
 
473
    if (view == null)
474
      return;
475
 
476
    Point pos = getViewPosition();
477
    Rectangle viewBounds = view.getBounds();
478
    Rectangle portBounds = getBounds();
479
 
480
    if (viewBounds.width == 0
481
        || viewBounds.height == 0
482
        || portBounds.width == 0
483
        || portBounds.height == 0)
484
      return;
485
 
486
    switch (getScrollMode())
487
      {
488
 
489
      case JViewport.BACKINGSTORE_SCROLL_MODE:
490
        paintBackingStore(g);
491
        break;
492
      case JViewport.BLIT_SCROLL_MODE:
493
        paintBlit(g);
494
        break;
495
      case JViewport.SIMPLE_SCROLL_MODE:
496
      default:
497
        paintSimple(g);
498
        break;
499
      }
500
    damaged = false;
501
  }
502
 
503
  public void addChangeListener(ChangeListener listener)
504
  {
505
    listenerList.add(ChangeListener.class, listener);
506
  }
507
 
508
  public void removeChangeListener(ChangeListener listener)
509
  {
510
    listenerList.remove(ChangeListener.class, listener);
511
  }
512
 
513
  public ChangeListener[] getChangeListeners()
514
  {
515
    return (ChangeListener[]) getListeners(ChangeListener.class);
516
  }
517
 
518
  /**
519
   * This method returns the String ID of the UI class of  Separator.
520
   *
521
   * @return The UI class' String ID.
522
   */
523
  public String getUIClassID()
524
  {
525
    return "ViewportUI";
526
  }
527
 
528
  /**
529
   * This method resets the UI used to the Look and Feel defaults..
530
   */
531
  public void updateUI()
532
  {
533
    setUI((ViewportUI) UIManager.getUI(this));
534
  }
535
 
536
  /**
537
   * This method returns the viewport's UI delegate.
538
   *
539
   * @return The viewport's UI delegate.
540
   */
541
  public ViewportUI getUI()
542
  {
543
    return (ViewportUI) ui;
544
  }
545
 
546
  /**
547
   * This method sets the viewport's UI delegate.
548
   *
549
   * @param ui The viewport's UI delegate.
550
   */
551
  public void setUI(ViewportUI ui)
552
  {
553
    super.setUI(ui);
554
  }
555
 
556
  public final void setBorder(Border border)
557
  {
558
    if (border != null)
559
      throw new IllegalArgumentException();
560
  }
561
 
562
  /**
563
   * Scrolls the view so that contentRect becomes visible.
564
   *
565
   * @param contentRect the rectangle to make visible within the view
566
   */
567
  public void scrollRectToVisible(Rectangle contentRect)
568
  {
569
    Component view = getView();
570
    if (view == null)
571
      return;
572
 
573
    Point pos = getViewPosition();
574
    Rectangle viewBounds = getView().getBounds();
575
    Rectangle portBounds = getBounds();
576
 
577
    if (isShowing())
578
      getView().validate();
579
 
580
    // If the bottom boundary of contentRect is below the port
581
    // boundaries, scroll up as necessary.
582
    if (contentRect.y + contentRect.height + viewBounds.y > portBounds.height)
583
      pos.y = contentRect.y + contentRect.height - portBounds.height;
584
    // If contentRect.y is above the port boundaries, scroll down to
585
    // contentRect.y.
586
    if (contentRect.y + viewBounds.y < 0)
587
      pos.y = contentRect.y;
588
    // If the right boundary of contentRect is right from the port
589
    // boundaries, scroll left as necessary.
590
    if (contentRect.x + contentRect.width + viewBounds.x > portBounds.width)
591
      pos.x = contentRect.x + contentRect.width - portBounds.width;
592
    // If contentRect.x is left from the port boundaries, scroll right to
593
    // contentRect.x.
594
    if (contentRect.x + viewBounds.x < 0)
595
      pos.x = contentRect.x;
596
    setViewPosition(pos);
597
  }
598
 
599
  /**
600
   * Returns the accessible context for this <code>JViewport</code>. This
601
   * will be an instance of {@link AccessibleJViewport}.
602
   *
603
   * @return the accessible context for this <code>JViewport</code>
604
   */
605
  public AccessibleContext getAccessibleContext()
606
  {
607
    if (accessibleContext == null)
608
      accessibleContext = new AccessibleJViewport();
609
    return accessibleContext;
610
  }
611
 
612
  /**
613
   * Forward repaint to parent to make sure only one paint is performed by the
614
   * RepaintManager.
615
   *
616
   * @param tm number of milliseconds to defer the repaint request
617
   * @param x the X coordinate of the upper left corner of the dirty area
618
   * @param y the Y coordinate of the upper left corner of the dirty area
619
   * @param w the width of the dirty area
620
   * @param h the height of the dirty area
621
   */
622
  public void repaint(long tm, int x, int y, int w, int h)
623
  {
624
    Component parent = getParent();
625
    if (parent != null)
626
      {
627
        parent.repaint(tm, x + getX(), y + getY(), w, h);
628
      }
629
  }
630
 
631
  protected void addImpl(Component comp, Object constraints, int index)
632
  {
633
    if (getComponentCount() > 0)
634
      remove(getComponents()[0]);
635
 
636
    super.addImpl(comp, constraints, index);
637
  }
638
 
639
  protected void fireStateChanged()
640
  {
641
    ChangeListener[] listeners = getChangeListeners();
642
    for (int i = 0; i < listeners.length; ++i)
643
      listeners[i].stateChanged(changeEvent);
644
  }
645
 
646
  /**
647
   * Creates a {@link ViewListener} that is supposed to listen for
648
   * size changes on the view component.
649
   *
650
   * @return a ViewListener instance
651
   */
652
  protected ViewListener createViewListener()
653
  {
654
    return new ViewListener();
655
  }
656
 
657
  /**
658
   * Creates the LayoutManager that is used for this viewport. Override
659
   * this method if you want to use a custom LayoutManager.
660
   *
661
   * @return a LayoutManager to use for this viewport
662
   */
663
  protected LayoutManager createLayoutManager()
664
  {
665
    return new ViewportLayout();
666
  }
667
 
668
  /**
669
   * Computes the parameters for the blitting scroll method. <code>dx</code>
670
   * and <code>dy</code> specifiy the X and Y offset by which the viewport
671
   * is scrolled. All other arguments are output parameters and are filled by
672
   * this method.
673
   *
674
   * <code>blitFrom</code> holds the position of the blit rectangle in the
675
   * viewport rectangle before scrolling, <code>blitTo</code> where the blitArea
676
   * is copied to.
677
   *
678
   * <code>blitSize</code> holds the size of the blit area and
679
   * <code>blitPaint</code> is the area of the view that needs to be painted.
680
   *
681
   * This method returns <code>true</code> if blitting is possible and
682
   * <code>false</code> if the viewport has to be repainted completetly without
683
   * blitting.
684
   *
685
   * @param dx the horizontal delta
686
   * @param dy the vertical delta
687
   * @param blitFrom the position from where to blit; set by this method
688
   * @param blitTo the position where to blit area is copied to; set by this
689
   *        method
690
   * @param blitSize the size of the blitted area; set by this method
691
   * @param blitPaint the area that needs repainting; set by this method
692
   *
693
   * @return <code>true</code> if blitting is possible,
694
   *         <code>false</code> otherwise
695
   */
696
  protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
697
                                Dimension blitSize, Rectangle blitPaint)
698
  {
699
    if ((dx != 0 && dy != 0) || damaged)
700
      // We cannot blit if the viewport is scrolled in both directions at
701
      // once.
702
      return false;
703
 
704
    Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
705
 
706
    // Compute the blitFrom and blitTo parameters.
707
    blitFrom.x = portBounds.x;
708
    blitFrom.y = portBounds.y;
709
    blitTo.x = portBounds.x;
710
    blitTo.y = portBounds.y;
711
 
712
    if (dy > 0)
713
      {
714
        blitFrom.y = portBounds.y + dy;
715
      }
716
    else if (dy < 0)
717
      {
718
        blitTo.y = portBounds.y - dy;
719
      }
720
    else if (dx > 0)
721
      {
722
        blitFrom.x = portBounds.x + dx;
723
      }
724
    else if (dx < 0)
725
      {
726
        blitTo.x = portBounds.x - dx;
727
      }
728
 
729
    // Compute size of the blit area.
730
    if (dx != 0)
731
      {
732
        blitSize.width = portBounds.width - Math.abs(dx);
733
        blitSize.height = portBounds.height;
734
      }
735
    else if (dy != 0)
736
      {
737
        blitSize.width = portBounds.width;
738
        blitSize.height = portBounds.height - Math.abs(dy);
739
      }
740
 
741
    // Compute the blitPaint parameter.
742
    blitPaint.setBounds(portBounds);
743
    if (dy > 0)
744
      {
745
        blitPaint.y = portBounds.y + portBounds.height - dy;
746
        blitPaint.height = dy;
747
      }
748
    else if (dy < 0)
749
      {
750
        blitPaint.height = -dy;
751
      }
752
    if (dx > 0)
753
      {
754
        blitPaint.x = portBounds.x + portBounds.width - dx;
755
        blitPaint.width = dx;
756
      }
757
    else if (dx < 0)
758
      {
759
        blitPaint.width = -dx;
760
      }
761
 
762
    return true;
763
  }
764
 
765
  /**
766
   * Paints the viewport in case we have a scrollmode of
767
   * {@link #SIMPLE_SCROLL_MODE}.
768
   *
769
   * This simply paints the view directly on the surface of the viewport.
770
   *
771
   * @param g the graphics context to use
772
   */
773
  void paintSimple(Graphics g)
774
  {
775
    Point pos = getViewPosition();
776
    Component view = getView();
777
    boolean translated = false;
778
    try
779
      {
780
        g.translate(-pos.x, -pos.y);
781
        translated = true;
782
        view.paint(g);
783
      }
784
    finally
785
      {
786
        if (translated)
787
          g.translate (pos.x, pos.y);
788
      }
789
  }
790
 
791
  /**
792
   * Paints the viewport in case we have a scroll mode of
793
   * {@link #BACKINGSTORE_SCROLL_MODE}.
794
   *
795
   * This method uses a backing store image to paint the view to, which is then
796
   * subsequently painted on the screen. This should make scrolling more
797
   * smooth.
798
   *
799
   * @param g the graphics context to use
800
   */
801
  void paintBackingStore(Graphics g)
802
  {
803
    // If we have no backing store image yet or the size of the component has
804
    // changed, we need to rebuild the backing store.
805
    if (backingStoreImage == null || sizeChanged)
806
      {
807
        backingStoreImage = createImage(getWidth(), getHeight());
808
        sizeChanged = false;
809
        Graphics g2 = backingStoreImage.getGraphics();
810
        paintSimple(g2);
811
        g2.dispose();
812
      }
813
    // Otherwise we can perform the blitting on the backing store image:
814
    // First we move the part that remains visible after scrolling, then
815
    // we only need to paint the bit that becomes newly visible.
816
    else
817
      {
818
        Graphics g2 = backingStoreImage.getGraphics();
819
        Point viewPosition = getViewPosition();
820
        int dx = viewPosition.x - lastPaintPosition.x;
821
        int dy = viewPosition.y - lastPaintPosition.y;
822
        boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
823
                                      cachedBlitSize, cachedBlitPaint);
824
        if (canBlit)
825
          {
826
            // Copy the part that remains visible during scrolling.
827
            g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
828
                        cachedBlitSize.width, cachedBlitSize.height,
829
                        cachedBlitTo.x - cachedBlitFrom.x,
830
                        cachedBlitTo.y - cachedBlitFrom.y);
831
            // Now paint the part that becomes newly visible.
832
            g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y,
833
                       cachedBlitPaint.width, cachedBlitPaint.height);
834
            paintSimple(g2);
835
          }
836
        // If blitting is not possible for some reason, fall back to repainting
837
        // everything.
838
        else
839
          {
840
            paintSimple(g2);
841
          }
842
        g2.dispose();
843
      }
844
    // Actually draw the backingstore image to the graphics context.
845
    g.drawImage(backingStoreImage, 0, 0, this);
846
    // Update the lastPaintPosition so that we know what is already drawn when
847
    // we paint the next time.
848
    lastPaintPosition.setLocation(getViewPosition());
849
  }
850
 
851
  /**
852
   * Paints the viewport in case we have a scrollmode of
853
   * {@link #BLIT_SCROLL_MODE}.
854
   *
855
   * This paints the viewport using a backingstore and a blitting algorithm.
856
   * Only the newly exposed area of the view is painted from the view painting
857
   * methods, the remainder is copied from the backing store.
858
   *
859
   * @param g the graphics context to use
860
   */
861
  void paintBlit(Graphics g)
862
  {
863
    // We cannot perform blitted painting as it is described in Sun's API docs.
864
    // There it is suggested that this painting method should blit directly
865
    // on the parent window's surface. This is not possible because when using
866
    // Swing's double buffering (at least our implementation), it would
867
    // immediatly be painted when the buffer is painted on the screen. For this
868
    // to work we would need a kind of hole in the buffer image. And honestly
869
    // I find this method not very elegant.
870
    // The alternative, blitting directly on the buffer image, is also not
871
    // possible because the buffer image gets cleared everytime when an opaque
872
    // parent component is drawn on it.
873
 
874
    // What we do instead is falling back to the backing store approach which
875
    // is in fact a mixed blitting/backing store approach where the blitting
876
    // is performed on the backing store image and this is then drawn to the
877
    // graphics context. This is very robust and works independent of the
878
    // painting mechanism that is used by Swing. And it should have comparable
879
    // performance characteristics as the blitting method.
880
    paintBackingStore(g);
881
  }
882
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.