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/] [RepaintManager.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* RepaintManager.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.Image;
44
import java.awt.Rectangle;
45
import java.awt.image.VolatileImage;
46
import java.util.ArrayList;
47
import java.util.Collections;
48
import java.util.Comparator;
49
import java.util.HashMap;
50
import java.util.Iterator;
51
 
52
/**
53
 * <p>The repaint manager holds a set of dirty regions, invalid components,
54
 * and a double buffer surface.  The dirty regions and invalid components
55
 * are used to coalesce multiple revalidate() and repaint() calls in the
56
 * component tree into larger groups to be refreshed "all at once"; the
57
 * double buffer surface is used by root components to paint
58
 * themselves.</p>
59
 *
60
 * <p>In general, painting is very confusing in swing. see <a
61
 * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this
62
 * document</a> for more details.</p>
63
 *
64
 * @author Graydon Hoare (graydon@redhat.com)
65
 */
66
public class RepaintManager
67
{
68
  /**
69
   * The current repaint managers, indexed by their ThreadGroups.
70
   */
71
  static HashMap currentRepaintManagers;
72
 
73
  /**
74
   * <p>A helper class which is placed into the system event queue at
75
   * various times in order to facilitate repainting and layout. There is
76
   * typically only one of these objects active at any time. When the
77
   * {@link RepaintManager} is told to queue a repaint, it checks to see if
78
   * a {@link RepaintWorker} is "live" in the system event queue, and if
79
   * not it inserts one using {@link SwingUtilities#invokeLater}.</p>
80
   *
81
   * <p>When the {@link RepaintWorker} comes to the head of the system
82
   * event queue, its {@link RepaintWorker#run} method is executed by the
83
   * swing paint thread, which revalidates all invalid components and
84
   * repaints any damage in the swing scene.</p>
85
   */
86
  protected class RepaintWorker
87
    implements Runnable
88
  {
89
 
90
    boolean live;
91
 
92
    public RepaintWorker()
93
    {
94
      live = false;
95
    }
96
 
97
    public synchronized void setLive(boolean b)
98
    {
99
      live = b;
100
    }
101
 
102
    public synchronized boolean isLive()
103
    {
104
      return live;
105
    }
106
 
107
    public void run()
108
    {
109
      ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
110
      RepaintManager rm =
111
        (RepaintManager) currentRepaintManagers.get(threadGroup);
112
      setLive(false);
113
      rm.validateInvalidComponents();
114
      rm.paintDirtyRegions();
115
    }
116
 
117
  }
118
 
119
  /**
120
   * Compares two components using their depths in the component hierarchy.
121
   * A component with a lesser depth (higher level components) are sorted
122
   * before components with a deeper depth (low level components). This is used
123
   * to order paint requests, so that the higher level components are painted
124
   * before the low level components get painted.
125
   *
126
   * @author Roman Kennke (kennke@aicas.com)
127
   */
128
  private class ComponentComparator implements Comparator
129
  {
130
 
131
    /**
132
     * Compares two components.
133
     *
134
     * @param o1 the first component
135
     * @param o2 the second component
136
     *
137
     * @return a negative integer, if <code>o1</code> is higher in the
138
     *         hierarchy than <code>o2</code>, zero, if both are at the same
139
     *         level and a positive integer, if <code>o1</code> is deeper in
140
     *         the hierarchy than <code>o2</code>
141
     */
142
    public int compare(Object o1, Object o2)
143
    {
144
      if (o1 instanceof JComponent && o2 instanceof JComponent)
145
        {
146
          JComponent c1 = (JComponent) o1;
147
          JComponent c2 = (JComponent) o2;
148
          return getDepth(c1) - getDepth(c2);
149
        }
150
      else
151
        throw new ClassCastException("This comparator can only be used with "
152
                                     + "JComponents");
153
    }
154
 
155
    /**
156
     * Computes the depth for a given JComponent.
157
     *
158
     * @param c the component to compute the depth for
159
     *
160
     * @return the depth of the component
161
     */
162
    private int getDepth(JComponent c)
163
    {
164
      Component comp = c;
165
      int depth = 0;
166
      while (comp != null)
167
        {
168
          comp = comp.getParent();
169
          depth++;
170
        }
171
      return depth;
172
    }
173
  }
174
 
175
  /**
176
   * A table storing the dirty regions of components.  The keys of this
177
   * table are components, the values are rectangles. Each component maps
178
   * to exactly one rectangle.  When more regions are marked as dirty on a
179
   * component, they are union'ed with the existing rectangle.
180
   *
181
   * @see #addDirtyRegion
182
   * @see #getDirtyRegion
183
   * @see #isCompletelyDirty
184
   * @see #markCompletelyClean
185
   * @see #markCompletelyDirty
186
   */
187
  HashMap dirtyComponents;
188
 
189
  HashMap workDirtyComponents;
190
 
191
  /**
192
   * Stores the order in which the components get repainted.
193
   */
194
  ArrayList repaintOrder;
195
  ArrayList workRepaintOrder;
196
 
197
  /**
198
   * The comparator used for ordered inserting into the repaintOrder list.
199
   */
200
  Comparator comparator;
201
 
202
  /**
203
   * A single, shared instance of the helper class. Any methods which mark
204
   * components as invalid or dirty eventually activate this instance. It
205
   * is added to the event queue if it is not already active, otherwise
206
   * reused.
207
   *
208
   * @see #addDirtyRegion
209
   * @see #addInvalidComponent
210
   */
211
  RepaintWorker repaintWorker;
212
 
213
  /**
214
   * The set of components which need revalidation, in the "layout" sense.
215
   * There is no additional information about "what kind of layout" they
216
   * need (as there is with dirty regions), so it is just a vector rather
217
   * than a table.
218
   *
219
   * @see #addInvalidComponent
220
   * @see #removeInvalidComponent
221
   * @see #validateInvalidComponents
222
   */
223
  ArrayList invalidComponents;
224
  ArrayList workInvalidComponents;
225
 
226
  /**
227
   * Whether or not double buffering is enabled on this repaint
228
   * manager. This is merely a hint to clients; the RepaintManager will
229
   * always return an offscreen buffer when one is requested.
230
   *
231
   * @see #isDoubleBufferingEnabled
232
   * @see #setDoubleBufferingEnabled
233
   */
234
  boolean doubleBufferingEnabled;
235
 
236
  /**
237
   * The current offscreen buffer. This is reused for all requests for
238
   * offscreen drawing buffers. It grows as necessary, up to {@link
239
   * #doubleBufferMaximumSize}, but there is only one shared instance.
240
   *
241
   * @see #getOffscreenBuffer
242
   * @see #doubleBufferMaximumSize
243
   */
244
  Image doubleBuffer;
245
 
246
  /**
247
   * The maximum width and height to allocate as a double buffer. Requests
248
   * beyond this size are ignored.
249
   *
250
   * @see #paintDirtyRegions
251
   * @see #getDoubleBufferMaximumSize
252
   * @see #setDoubleBufferMaximumSize
253
   */
254
  Dimension doubleBufferMaximumSize;
255
 
256
 
257
  /**
258
   * Create a new RepaintManager object.
259
   */
260
  public RepaintManager()
261
  {
262
    dirtyComponents = new HashMap();
263
    workDirtyComponents = new HashMap();
264
    repaintOrder = new ArrayList();
265
    workRepaintOrder = new ArrayList();
266
    invalidComponents = new ArrayList();
267
    workInvalidComponents = new ArrayList();
268
    repaintWorker = new RepaintWorker();
269
    doubleBufferMaximumSize = new Dimension(2000,2000);
270
    doubleBufferingEnabled = true;
271
  }
272
 
273
  /**
274
   * Returns the <code>RepaintManager</code> for the current thread's
275
   * thread group. The default implementation ignores the
276
   * <code>component</code> parameter and returns the same repaint manager
277
   * for all components.
278
   *
279
   * @param component a component to look up the manager of
280
   *
281
   * @return the current repaint manager for the calling thread's thread group
282
   *         and the specified component
283
   *
284
   * @see #setCurrentManager
285
   */
286
  public static RepaintManager currentManager(Component component)
287
  {
288
    if (currentRepaintManagers == null)
289
      currentRepaintManagers = new HashMap();
290
    ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
291
    RepaintManager currentManager =
292
      (RepaintManager) currentRepaintManagers.get(threadGroup);
293
    if (currentManager == null)
294
      {
295
        currentManager = new RepaintManager();
296
        currentRepaintManagers.put(threadGroup, currentManager);
297
      }
298
    return currentManager;
299
  }
300
 
301
  /**
302
   * Returns the <code>RepaintManager</code> for the current thread's
303
   * thread group. The default implementation ignores the
304
   * <code>component</code> parameter and returns the same repaint manager
305
   * for all components.
306
   *
307
   * This method is only here for backwards compatibility with older versions
308
   * of Swing and simply forwards to {@link #currentManager(Component)}.
309
   *
310
   * @param component a component to look up the manager of
311
   *
312
   * @return the current repaint manager for the calling thread's thread group
313
   *         and the specified component
314
   *
315
   * @see #setCurrentManager
316
   */
317
  public static RepaintManager currentManager(JComponent component)
318
  {
319
    return currentManager((Component)component);
320
  }
321
 
322
  /**
323
   * Sets the repaint manager for the calling thread's thread group.
324
   *
325
   * @param manager the repaint manager to set for the current thread's thread
326
   *        group
327
   *
328
   * @see #currentManager(Component)
329
   */
330
  public static void setCurrentManager(RepaintManager manager)
331
  {
332
    if (currentRepaintManagers == null)
333
      currentRepaintManagers = new HashMap();
334
 
335
    ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
336
    currentRepaintManagers.put(threadGroup, manager);
337
  }
338
 
339
  /**
340
   * Add a component to the {@link #invalidComponents} vector. If the
341
   * {@link #repaintWorker} class is not active, insert it in the system
342
   * event queue.
343
   *
344
   * @param component The component to add
345
   *
346
   * @see #removeInvalidComponent
347
   */
348
  public synchronized void addInvalidComponent(JComponent component)
349
  {
350
    Component ancestor = component.getParent();
351
 
352
    while (ancestor != null
353
           && (! (ancestor instanceof JComponent)
354
               || ! ((JComponent) ancestor).isValidateRoot() ))
355
      ancestor = ancestor.getParent();
356
 
357
    if (ancestor != null
358
        && ancestor instanceof JComponent
359
        && ((JComponent) ancestor).isValidateRoot())
360
      component = (JComponent) ancestor;
361
 
362
    if (invalidComponents.contains(component))
363
      return;
364
 
365
    invalidComponents.add(component);
366
 
367
    if (! repaintWorker.isLive())
368
      {
369
        repaintWorker.setLive(true);
370
        SwingUtilities.invokeLater(repaintWorker);
371
      }
372
  }
373
 
374
  /**
375
   * Remove a component from the {@link #invalidComponents} vector.
376
   *
377
   * @param component The component to remove
378
   *
379
   * @see #addInvalidComponent
380
   */
381
  public synchronized void removeInvalidComponent(JComponent component)
382
  {
383
    invalidComponents.remove(component);
384
  }
385
 
386
  /**
387
   * Add a region to the set of dirty regions for a specified component.
388
   * This involves union'ing the new region with any existing dirty region
389
   * associated with the component. If the {@link #repaintWorker} class
390
   * is not active, insert it in the system event queue.
391
   *
392
   * @param component The component to add a dirty region for
393
   * @param x The left x coordinate of the new dirty region
394
   * @param y The top y coordinate of the new dirty region
395
   * @param w The width of the new dirty region
396
   * @param h The height of the new dirty region
397
   *
398
   * @see #addDirtyRegion
399
   * @see #getDirtyRegion
400
   * @see #isCompletelyDirty
401
   * @see #markCompletelyClean
402
   * @see #markCompletelyDirty
403
   */
404
  public synchronized void addDirtyRegion(JComponent component, int x, int y,
405
                                          int w, int h)
406
  {
407
    if (w == 0 || h == 0 || !component.isShowing())
408
      return;
409
    Rectangle r = new Rectangle(x, y, w, h);
410
    if (dirtyComponents.containsKey(component))
411
      r = r.union((Rectangle)dirtyComponents.get(component));
412
    else
413
      insertInRepaintOrder(component);
414
    dirtyComponents.put(component, r);
415
    if (! repaintWorker.isLive())
416
      {
417
        repaintWorker.setLive(true);
418
        SwingUtilities.invokeLater(repaintWorker);
419
      }
420
  }
421
 
422
  /**
423
   * Inserts a component into the repaintOrder list in an ordered fashion,
424
   * using a binary search.
425
   *
426
   * @param c the component to be inserted
427
   */
428
  private void insertInRepaintOrder(JComponent c)
429
  {
430
    if (comparator == null)
431
      comparator = new ComponentComparator();
432
    int insertIndex = Collections.binarySearch(repaintOrder, c, comparator);
433
    if (insertIndex < 0)
434
      insertIndex = -(insertIndex + 1);
435
    repaintOrder.add(insertIndex, c);
436
  }
437
 
438
  /**
439
   * Get the dirty region associated with a component, or <code>null</code>
440
   * if the component has no dirty region.
441
   *
442
   * @param component The component to get the dirty region of
443
   *
444
   * @return The dirty region of the component
445
   *
446
   * @see #dirtyComponents
447
   * @see #addDirtyRegion
448
   * @see #isCompletelyDirty
449
   * @see #markCompletelyClean
450
   * @see #markCompletelyDirty
451
   */
452
  public Rectangle getDirtyRegion(JComponent component)
453
  {
454
    Rectangle dirty = (Rectangle) dirtyComponents.get(component);
455
    if (dirty == null)
456
      dirty = new Rectangle();
457
    return dirty;
458
  }
459
 
460
  /**
461
   * Mark a component as dirty over its entire bounds.
462
   *
463
   * @param component The component to mark as dirty
464
   *
465
   * @see #dirtyComponents
466
   * @see #addDirtyRegion
467
   * @see #getDirtyRegion
468
   * @see #isCompletelyDirty
469
   * @see #markCompletelyClean
470
   */
471
  public void markCompletelyDirty(JComponent component)
472
  {
473
    Rectangle r = component.getBounds();
474
    addDirtyRegion(component, r.x, r.y, r.width, r.height);
475
    component.isCompletelyDirty = true;
476
  }
477
 
478
  /**
479
   * Remove all dirty regions for a specified component
480
   *
481
   * @param component The component to mark as clean
482
   *
483
   * @see #dirtyComponents
484
   * @see #addDirtyRegion
485
   * @see #getDirtyRegion
486
   * @see #isCompletelyDirty
487
   * @see #markCompletelyDirty
488
   */
489
  public void markCompletelyClean(JComponent component)
490
  {
491
    synchronized (this)
492
      {
493
        dirtyComponents.remove(component);
494
      }
495
    component.isCompletelyDirty = false;
496
  }
497
 
498
  /**
499
   * Return <code>true</code> if the specified component is completely
500
   * contained within its dirty region, otherwise <code>false</code>
501
   *
502
   * @param component The component to check for complete dirtyness
503
   *
504
   * @return Whether the component is completely dirty
505
   *
506
   * @see #dirtyComponents
507
   * @see #addDirtyRegion
508
   * @see #getDirtyRegion
509
   * @see #isCompletelyDirty
510
   * @see #markCompletelyClean
511
   */
512
  public boolean isCompletelyDirty(JComponent component)
513
  {
514
    if (! dirtyComponents.containsKey(component))
515
      return false;
516
    return component.isCompletelyDirty;
517
  }
518
 
519
  /**
520
   * Validate all components which have been marked invalid in the {@link
521
   * #invalidComponents} vector.
522
   */
523
  public void validateInvalidComponents()
524
  {
525
    // In order to keep the blocking of application threads minimal, we switch
526
    // the invalidComponents field with the workInvalidComponents field and
527
    // work with the workInvalidComponents field.
528
    synchronized(this)
529
    {
530
      ArrayList swap = invalidComponents;
531
      invalidComponents = workInvalidComponents;
532
      workInvalidComponents = swap;
533
    }
534
    for (Iterator i = workInvalidComponents.iterator(); i.hasNext(); )
535
      {
536
        JComponent comp = (JComponent) i.next();
537
        if (! (comp.isVisible() && comp.isShowing()))
538
          continue;
539
        comp.validate();
540
      }
541
    workInvalidComponents.clear();
542
  }
543
 
544
  /**
545
   * Repaint all regions of all components which have been marked dirty in
546
   * the {@link #dirtyComponents} table.
547
   */
548
  public synchronized void paintDirtyRegions()
549
  {
550
    // In order to keep the blocking of application threads minimal, we switch
551
    // the dirtyComponents field with the workdirtyComponents field and the
552
    // repaintOrder field with the workRepaintOrder field and work with the
553
    // work* fields.
554
    synchronized(this)
555
    {
556
      ArrayList swap = workRepaintOrder;
557
      workRepaintOrder = repaintOrder;
558
      repaintOrder = swap;
559
      HashMap swap2 = workDirtyComponents;
560
      workDirtyComponents = dirtyComponents;
561
      dirtyComponents = swap2;
562
    }
563
    for (Iterator i = workRepaintOrder.iterator(); i.hasNext();)
564
      {
565
        JComponent comp = (JComponent) i.next();
566
        // If a component is marked completely clean in the meantime, then skip
567
        // it.
568
        Rectangle damaged = (Rectangle) workDirtyComponents.get(comp);
569
        if (damaged == null || damaged.isEmpty())
570
          continue;
571
        comp.paintImmediately(damaged);
572
      }
573
    workRepaintOrder.clear();
574
    workDirtyComponents.clear();
575
  }
576
 
577
  /**
578
   * Get an offscreen buffer for painting a component's image. This image
579
   * may be smaller than the proposed dimensions, depending on the value of
580
   * the {@link #doubleBufferMaximumSize} property.
581
   *
582
   * @param component The component to return an offscreen buffer for
583
   * @param proposedWidth The proposed width of the offscreen buffer
584
   * @param proposedHeight The proposed height of the offscreen buffer
585
   *
586
   * @return A shared offscreen buffer for painting
587
   *
588
   * @see #doubleBuffer
589
   */
590
  public Image getOffscreenBuffer(Component component, int proposedWidth,
591
                                  int proposedHeight)
592
  {
593
    if (doubleBuffer == null
594
        || (((doubleBuffer.getWidth(null) < proposedWidth)
595
             || (doubleBuffer.getHeight(null) < proposedHeight))
596
            && (proposedWidth < doubleBufferMaximumSize.width)
597
            && (proposedHeight < doubleBufferMaximumSize.height)))
598
      {
599
        doubleBuffer = component.createImage(proposedWidth, proposedHeight);
600
      }
601
    return doubleBuffer;
602
  }
603
 
604
  /**
605
   * Creates and returns a volatile offscreen buffer for the specified
606
   * component that can be used as a double buffer. The returned image
607
   * is a {@link VolatileImage}. Its size will be <code>(proposedWidth,
608
   * proposedHeight)</code> except when the maximum double buffer size
609
   * has been set in this RepaintManager.
610
   *
611
   * @param comp the Component for which to create a volatile buffer
612
   * @param proposedWidth the proposed width of the buffer
613
   * @param proposedHeight the proposed height of the buffer
614
   *
615
   * @since 1.4
616
   *
617
   * @see VolatileImage
618
   */
619
  public Image getVolatileOffscreenBuffer(Component comp, int proposedWidth,
620
                                          int proposedHeight)
621
  {
622
    int maxWidth = doubleBufferMaximumSize.width;
623
    int maxHeight = doubleBufferMaximumSize.height;
624
    return comp.createVolatileImage(Math.min(maxWidth, proposedWidth),
625
                                    Math.min(maxHeight, proposedHeight));
626
  }
627
 
628
 
629
  /**
630
   * Get the value of the {@link #doubleBufferMaximumSize} property.
631
   *
632
   * @return The current value of the property
633
   *
634
   * @see #setDoubleBufferMaximumSize
635
   */
636
  public Dimension getDoubleBufferMaximumSize()
637
  {
638
    return doubleBufferMaximumSize;
639
  }
640
 
641
  /**
642
   * Set the value of the {@link #doubleBufferMaximumSize} property.
643
   *
644
   * @param size The new value of the property
645
   *
646
   * @see #getDoubleBufferMaximumSize
647
   */
648
  public void setDoubleBufferMaximumSize(Dimension size)
649
  {
650
    doubleBufferMaximumSize = size;
651
  }
652
 
653
  /**
654
   * Set the value of the {@link #doubleBufferingEnabled} property.
655
   *
656
   * @param buffer The new value of the property
657
   *
658
   * @see #isDoubleBufferingEnabled
659
   */
660
  public void setDoubleBufferingEnabled(boolean buffer)
661
  {
662
    doubleBufferingEnabled = buffer;
663
  }
664
 
665
  /**
666
   * Get the value of the {@link #doubleBufferingEnabled} property.
667
   *
668
   * @return The current value of the property
669
   *
670
   * @see #setDoubleBufferingEnabled
671
   */
672
  public boolean isDoubleBufferingEnabled()
673
  {
674
    return doubleBufferingEnabled;
675
  }
676
 
677
  public String toString()
678
  {
679
    return "RepaintManager";
680
  }
681
}

powered by: WebSVN 2.1.0

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