KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > PopupFactory


1 /*
2  * @(#)PopupFactory.java 1.24 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10 import java.applet.Applet JavaDoc;
11 import java.awt.*;
12 import java.awt.event.WindowAdapter JavaDoc;
13 import java.awt.event.WindowEvent JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
18
19 /**
20  * <code>PopupFactory</code>, as the name implies, is used to obtain
21  * instances of <code>Popup</code>s. <code>Popup</code>s are used to
22  * display a <code>Component</code> above all other <code>Component</code>s
23  * in a particular containment hierarchy. The general contract is that
24  * once you have obtained a <code>Popup</code> from a
25  * <code>PopupFactory</code>, you must invoke <code>hide</code> on the
26  * <code>Popup</code>. The typical usage is:
27  * <pre>
28  * PopupFactory factory = PopupFactory.getSharedInstance();
29  * Popup popup = factory.getPopup(owner, contents, x, y);
30  * popup.show();
31  * ...
32  * popup.hide();
33  * </pre>
34  *
35  * @see Popup
36  *
37  * @version 1.24 12/19/03
38  * @since 1.4
39  */

40 public class PopupFactory {
41     /**
42      * The shared instanceof <code>PopupFactory</code> is per
43      * <code>AppContext</code>. This is the key used in the
44      * <code>AppContext</code> to locate the <code>PopupFactory</code>.
45      */

46     private static final Object JavaDoc SharedInstanceKey =
47         new StringBuffer JavaDoc("PopupFactory.SharedInstanceKey");
48
49     /**
50      * Max number of items to store in any one particular cache.
51      */

52     private static final int MAX_CACHE_SIZE = 5;
53
54     /**
55      * Key used to indicate a light weight popup should be used.
56      */

57     static final int LIGHT_WEIGHT_POPUP = 0;
58
59     /**
60      * Key used to indicate a medium weight Popup should be used.
61      */

62     static final int MEDIUM_WEIGHT_POPUP = 1;
63
64     /*
65      * Key used to indicate a heavy weight Popup should be used.
66      */

67     static final int HEAVY_WEIGHT_POPUP = 2;
68
69     /**
70      * Default type of Popup to create.
71      */

72     private int popupType = LIGHT_WEIGHT_POPUP;
73
74     /**
75      * Key used for client property to force heavy weight popups for a
76      * component.
77      */

78     static final StringBuffer JavaDoc forceHeavyWeightPopupKey =
79             new StringBuffer JavaDoc("__force_heavy_weight_popup__");
80
81
82     /**
83      * Sets the <code>PopupFactory</code> that will be used to obtain
84      * <code>Popup</code>s.
85      * This will throw an <code>IllegalArgumentException</code> if
86      * <code>factory</code> is null.
87      *
88      * @param factory Shared PopupFactory
89      * @exception IllegalArgumentException if <code>factory</code> is null
90      * @see #getPopup
91      */

92     public static void setSharedInstance(PopupFactory JavaDoc factory) {
93         if (factory == null) {
94             throw new IllegalArgumentException JavaDoc("PopupFactory can not be null");
95         }
96         SwingUtilities.appContextPut(SharedInstanceKey, factory);
97     }
98
99     /**
100      * Returns the shared <code>PopupFactory</code> which can be used
101      * to obtain <code>Popup</code>s.
102      *
103      * @return Shared PopupFactory
104      */

105     public static PopupFactory JavaDoc getSharedInstance() {
106         PopupFactory JavaDoc factory = (PopupFactory JavaDoc)SwingUtilities.appContextGet(
107                          SharedInstanceKey);
108
109         if (factory == null) {
110             factory = new PopupFactory JavaDoc();
111             setSharedInstance(factory);
112         }
113         return factory;
114     }
115
116
117     /**
118      * Provides a hint as to the type of <code>Popup</code> that should
119      * be created.
120      */

121     void setPopupType(int type) {
122         popupType = type;
123     }
124
125     /**
126      * Returns the preferred type of Popup to create.
127      */

128     int getPopupType() {
129         return popupType;
130     }
131
132     /**
133      * Creates a <code>Popup</code> for the Component <code>owner</code>
134      * containing the Component <code>contents</code>. <code>owner</code>
135      * is used to determine which <code>Window</code> the new
136      * <code>Popup</code> will parent the <code>Component</code> the
137      * <code>Popup</code> creates to. A null <code>owner</code> implies there
138      * is no valid parent. <code>x</code> and
139      * <code>y</code> specify the preferred initial location to place
140      * the <code>Popup</code> at. Based on screen size, or other paramaters,
141      * the <code>Popup</code> may not display at <code>x</code> and
142      * <code>y</code>.
143      *
144      * @param owner Component mouse coordinates are relative to, may be null
145      * @param contents Contents of the Popup
146      * @param x Initial x screen coordinate
147      * @param y Initial y screen coordinate
148      * @exception IllegalArgumentException if contents is null
149      * @return Popup containing Contents
150      */

151     public Popup JavaDoc getPopup(Component owner, Component contents,
152                           int x, int y) throws IllegalArgumentException JavaDoc {
153         if (contents == null) {
154             throw new IllegalArgumentException JavaDoc(
155                           "Popup.getPopup must be passed non-null contents");
156         }
157
158     int popupType = getPopupType(owner, contents, x, y);
159         Popup JavaDoc popup = getPopup(owner, contents, x, y, popupType);
160
161         if (popup == null) {
162             // Didn't fit, force to heavy.
163
popup = getPopup(owner, contents, x, y, HEAVY_WEIGHT_POPUP);
164         }
165         return popup;
166     }
167
168     /**
169      * Returns the popup type to use for the specified parameters.
170      */

171     private int getPopupType(Component owner, Component contents,
172                              int ownerX, int ownerY) {
173         int popupType = getPopupType();
174
175     if (owner == null || invokerInHeavyWeightPopup(owner)) {
176         popupType = HEAVY_WEIGHT_POPUP;
177     }
178         else if (popupType == LIGHT_WEIGHT_POPUP &&
179                  !(contents instanceof JToolTip JavaDoc) &&
180                  !(contents instanceof JPopupMenu JavaDoc)) {
181             popupType = MEDIUM_WEIGHT_POPUP;
182         }
183
184         // Check if the parent component is an option pane. If so we need to
185
// force a heavy weight popup in order to have event dispatching work
186
// correctly.
187
Component c = owner;
188         while (c != null) {
189             if (c instanceof JComponent JavaDoc) {
190                 if (((JComponent JavaDoc)c).getClientProperty(
191                             forceHeavyWeightPopupKey) == Boolean.TRUE) {
192                     popupType = HEAVY_WEIGHT_POPUP;
193                     break;
194                 }
195             }
196             c = c.getParent();
197         }
198
199     return popupType;
200     }
201
202     /**
203      * Obtains the appropriate <code>Popup</code> based on
204      * <code>popupType</code>.
205      */

206     private Popup JavaDoc getPopup(Component owner, Component contents,
207                            int ownerX, int ownerY, int popupType) {
208         if (GraphicsEnvironment.isHeadless()) {
209             return getHeadlessPopup(owner, contents, ownerX, ownerY);
210         }
211
212     switch(popupType) {
213     case LIGHT_WEIGHT_POPUP:
214         return getLightWeightPopup(owner, contents, ownerX, ownerY);
215     case MEDIUM_WEIGHT_POPUP:
216         return getMediumWeightPopup(owner, contents, ownerX, ownerY);
217     case HEAVY_WEIGHT_POPUP:
218         return getHeavyWeightPopup(owner, contents, ownerX, ownerY);
219     }
220         return null;
221     }
222
223     /**
224      * Creates a headless popup
225      */

226     private Popup JavaDoc getHeadlessPopup(Component owner, Component contents,
227                                    int ownerX, int ownerY) {
228         return HeadlessPopup.getHeadlessPopup(owner, contents, ownerX, ownerY);
229     }
230
231     /**
232      * Creates a light weight popup.
233      */

234     private Popup JavaDoc getLightWeightPopup(Component owner, Component contents,
235                                          int ownerX, int ownerY) {
236         return LightWeightPopup.getLightWeightPopup(owner, contents, ownerX,
237                                                     ownerY);
238     }
239     
240     /**
241      * Creates a medium weight popup.
242      */

243     private Popup JavaDoc getMediumWeightPopup(Component owner, Component contents,
244                                           int ownerX, int ownerY) {
245         return MediumWeightPopup.getMediumWeightPopup(owner, contents,
246                                                       ownerX, ownerY);
247     }
248
249     /**
250      * Creates a heavy weight popup.
251      */

252     private Popup JavaDoc getHeavyWeightPopup(Component owner, Component contents,
253                                          int ownerX, int ownerY) {
254         if (GraphicsEnvironment.isHeadless()) {
255             return getMediumWeightPopup(owner, contents, ownerX, ownerY);
256         }
257         return HeavyWeightPopup.getHeavyWeightPopup(owner, contents, ownerX,
258                                                     ownerY);
259     }
260
261     /**
262      * Returns true if the Component <code>i</code> inside a heavy weight
263      * <code>Popup</code>.
264      */

265     private boolean invokerInHeavyWeightPopup(Component i) {
266     if (i != null) {
267         Container parent;
268         for(parent = i.getParent() ; parent != null ; parent =
269             parent.getParent()) {
270         if (parent instanceof Popup.HeavyWeightWindow JavaDoc) {
271             return true;
272                 }
273         }
274     }
275         return false;
276     }
277
278
279     /**
280      * Popup implementation that uses a Window as the popup.
281      */

282     private static class HeavyWeightPopup extends Popup JavaDoc {
283         private static final Object JavaDoc heavyWeightPopupCacheKey =
284                  new StringBuffer JavaDoc("PopupFactory.heavyWeightPopupCache");
285
286         /**
287          * Returns either a new or recycled <code>Popup</code> containing
288          * the specified children.
289          */

290         static Popup JavaDoc getHeavyWeightPopup(Component owner, Component contents,
291                                          int ownerX, int ownerY) {
292             Window window = (owner != null) ? SwingUtilities.
293                               getWindowAncestor(owner) : null;
294             HeavyWeightPopup popup = null;
295
296             if (window != null) {
297                 popup = getRecycledHeavyWeightPopup(window);
298             }
299
300             boolean focusPopup = false;
301             if(contents != null && contents.isFocusable()) {
302                 if(contents instanceof JPopupMenu JavaDoc) {
303                     JPopupMenu JavaDoc jpm = (JPopupMenu JavaDoc) contents;
304                     Component popComps[] = jpm.getComponents();
305                     for(int i=0;i<popComps.length;i++) {
306                         if(!(popComps[i] instanceof MenuElement JavaDoc) &&
307                            !(popComps[i] instanceof JSeparator JavaDoc)) {
308                             focusPopup = true;
309                             break;
310                         }
311                     }
312                 }
313             }
314
315             if (popup == null ||
316                 ((JWindow JavaDoc) popup.getComponent())
317                  .getFocusableWindowState() != focusPopup) {
318
319                 if(popup != null) {
320                     // The recycled popup can't serve us well
321
// dispose it and create new one
322
popup._dispose();
323                 }
324
325                 popup = new HeavyWeightPopup();
326             }
327
328             popup.reset(owner, contents, ownerX, ownerY);
329
330             if(focusPopup) {
331                 JWindow JavaDoc wnd = (JWindow JavaDoc) popup.getComponent();
332                 wnd.setFocusableWindowState(true);
333                 // Set window name. We need this in BasicPopupMenuUI
334
// to identify focusable popup window.
335
wnd.setName("###focusableSwingPopup###");
336             }
337
338             return popup;
339         }
340
341         /**
342          * Returns a previously disposed heavy weight <code>Popup</code>
343          * associated with <code>window</code>. This will return null if
344          * there is no <code>HeavyWeightPopup</code> associated with
345          * <code>window</code>.
346          */

347         private static HeavyWeightPopup getRecycledHeavyWeightPopup(Window w) {
348             synchronized (HeavyWeightPopup.class) {
349                 List JavaDoc cache;
350                 Map JavaDoc heavyPopupCache = getHeavyWeightPopupCache();
351
352                 if (heavyPopupCache.containsKey(w)) {
353                     cache = (List JavaDoc)heavyPopupCache.get(w);
354                 } else {
355                     return null;
356                 }
357                 int c;
358                 if ((c = cache.size()) > 0) {
359                     HeavyWeightPopup r = (HeavyWeightPopup)cache.get(0);
360                     cache.remove(0);
361                     return r;
362                 }
363                 return null;
364             }
365         }
366
367         /**
368          * Returns the cache to use for heavy weight popups. Maps from
369          * <code>Window</code> to a <code>List</code> of
370          * <code>HeavyWeightPopup</code>s.
371          */

372         private static Map JavaDoc getHeavyWeightPopupCache() {
373             synchronized (HeavyWeightPopup.class) {
374                 Map JavaDoc cache = (Map JavaDoc)SwingUtilities.appContextGet(
375                                   heavyWeightPopupCacheKey);
376
377                 if (cache == null) {
378                     cache = new HashMap JavaDoc(2);
379                     SwingUtilities.appContextPut(heavyWeightPopupCacheKey,
380                                                  cache);
381                 }
382                 return cache;
383             }
384         }
385
386         /**
387          * Recycles the passed in <code>HeavyWeightPopup</code>.
388          */

389         private static void recycleHeavyWeightPopup(HeavyWeightPopup popup) {
390             synchronized (HeavyWeightPopup.class) {
391                 List JavaDoc cache;
392                 Object JavaDoc window = SwingUtilities.getWindowAncestor(
393                                      popup.getComponent());
394                 Map JavaDoc heavyPopupCache = getHeavyWeightPopupCache();
395
396                 if (window instanceof Popup.DefaultFrame JavaDoc ||
397                                       !((Window)window).isVisible()) {
398                     // If the Window isn't visible, we don't cache it as we
399
// likely won't ever get a windowClosed event to clean up.
400
// We also don't cache DefaultFrames as this indicates
401
// there wasn't a valid Window parent, and thus we don't
402
// know when to clean up.
403
popup._dispose();
404                     return;
405                 } else if (heavyPopupCache.containsKey(window)) {
406                     cache = (List JavaDoc)heavyPopupCache.get(window);
407                 } else {
408                     cache = new ArrayList JavaDoc();
409                     heavyPopupCache.put(window, cache);
410                     // Clean up if the Window is closed
411
final Window w = (Window)window;
412
413                     w.addWindowListener(new WindowAdapter JavaDoc() {
414                         public void windowClosed(WindowEvent JavaDoc e) {
415                             List JavaDoc popups;
416
417                             synchronized(HeavyWeightPopup.class) {
418                                 Map JavaDoc heavyPopupCache2 =
419                                               getHeavyWeightPopupCache();
420
421                                 popups = (List JavaDoc)heavyPopupCache2.remove(w);
422                             }
423                             if (popups != null) {
424                                 for (int counter = popups.size() - 1;
425                                                    counter >= 0; counter--) {
426                                     ((HeavyWeightPopup)popups.get(counter)).
427                                                        _dispose();
428                                 }
429                             }
430                         }
431                     });
432                 }
433
434                 if(cache.size() < MAX_CACHE_SIZE) {
435                     cache.add(popup);
436                 } else {
437                     popup._dispose();
438                 }
439             }
440         }
441
442         //
443
// Popup methods
444
//
445
public void hide() {
446             super.hide();
447             recycleHeavyWeightPopup(this);
448         }
449
450         /**
451          * As we recycle the <code>Window</code>, we don't want to dispose it,
452          * thus this method does nothing, instead use <code>_dipose</code>
453          * which will handle the disposing.
454          */

455         void dispose() {
456         }
457
458         void _dispose() {
459             super.dispose();
460         }
461     }
462
463
464
465     /**
466      * ContainerPopup consolidates the common code used in the light/medium
467      * weight implementations of <code>Popup</code>.
468      */

469     private static class ContainerPopup extends Popup JavaDoc {
470         /** Component we are to be added to. */
471         Component owner;
472         /** Desired x location. */
473         int x;
474         /** Desired y location. */
475         int y;
476
477         public void hide() {
478             Component component = getComponent();
479
480             if (component != null) {
481                 Container parent = component.getParent();
482
483                 if (parent != null) {
484                     Rectangle bounds = component.getBounds();
485
486                     parent.remove(component);
487                     parent.repaint(bounds.x, bounds.y, bounds.width,
488                                    bounds.height);
489                 }
490             }
491             owner = null;
492         }
493         public void pack() {
494             Component component = getComponent();
495
496             if (component != null) {
497                 component.setSize(component.getPreferredSize());
498             }
499         }
500
501         void reset(Component owner, Component contents, int ownerX,
502                    int ownerY) {
503             if ((owner instanceof JFrame JavaDoc) || (owner instanceof JDialog JavaDoc) ||
504                                                  (owner instanceof JWindow JavaDoc)) {
505                 // Force the content to be added to the layered pane, otherwise
506
// we'll get an exception when adding to the RootPaneContainer.
507
owner = ((RootPaneContainer JavaDoc)owner).getLayeredPane();
508             }
509             super.reset(owner, contents, ownerX, ownerY);
510
511             x = ownerX;
512             y = ownerY;
513             this.owner = owner;
514         }
515
516         boolean overlappedByOwnedWindow() {
517             Component component = getComponent();
518             if(owner != null && component != null) {
519                 Window w = SwingUtilities.getWindowAncestor(owner);
520                 if (w == null) {
521                     return false;
522                 }
523                 Window[] ownedWindows = w.getOwnedWindows();
524                 if(ownedWindows != null) {
525                     Rectangle bnd = component.getBounds();
526                     for(int i=0; i<ownedWindows.length;i++) {
527                         Window owned = ownedWindows[i];
528                         if (owned.isVisible() &&
529                             bnd.intersects(owned.getBounds())) {
530
531                             return true;
532                         }
533                     }
534                 }
535             }
536             return false;
537         }
538
539         /**
540          * Returns true if the Popup can fit on the screen.
541          */

542         boolean fitsOnScreen() {
543             Component component = getComponent();
544
545             if (owner != null && component != null) {
546                 Container parent;
547                 int width = component.getWidth();
548                 int height = component.getHeight();
549                 for(parent = owner.getParent(); parent != null ;
550                     parent = parent.getParent()) {
551                     if (parent instanceof JFrame JavaDoc ||
552                         parent instanceof JDialog JavaDoc ||
553                         parent instanceof JWindow JavaDoc) {
554
555                         Rectangle r = parent.getBounds();
556                         Insets i = parent.getInsets();
557                         r.x += i.left;
558                         r.y += i.top;
559                         r.width -= (i.left + i.right);
560                         r.height -= (i.top + i.bottom);
561                         return SwingUtilities.isRectangleContainingRectangle(
562                                    r, new Rectangle(x, y, width, height));
563                                                   
564                     } else if (parent instanceof JApplet JavaDoc) {
565                         Rectangle r = parent.getBounds();
566                         Point p = parent.getLocationOnScreen();
567
568                         r.x = p.x;
569                         r.y = p.y;
570                         return SwingUtilities.isRectangleContainingRectangle(
571                             r, new Rectangle(x, y, width, height));
572                     } else if (parent instanceof Window ||
573                    parent instanceof Applet JavaDoc) {
574             // No suitable swing component found
575
break;
576             }
577                 }
578             }
579             return false;
580         }
581     }
582
583
584     /**
585      * Popup implementation that is used in headless environment.
586      */

587     private static class HeadlessPopup extends ContainerPopup {
588         static Popup JavaDoc getHeadlessPopup(Component owner, Component contents,
589                                       int ownerX, int ownerY) {
590             HeadlessPopup popup = new HeadlessPopup();
591             popup.reset(owner, contents, ownerX, ownerY);
592             return popup;
593         }
594
595         Component createComponent(Component owner) {
596             return new Panel(new BorderLayout());
597         }
598
599         public void show() {
600         }
601         public void hide() {
602         }
603     }
604
605
606     /**
607      * Popup implementation that uses a JPanel as the popup.
608      */

609     private static class LightWeightPopup extends ContainerPopup {
610         private static final Object JavaDoc lightWeightPopupCacheKey =
611                          new StringBuffer JavaDoc("PopupFactory.lightPopupCache");
612
613         /**
614          * Returns a light weight <code>Popup</code> implementation. If
615          * the <code>Popup</code> needs more space that in available in
616          * <code>owner</code>, this will return null.
617          */

618         static Popup JavaDoc getLightWeightPopup(Component owner, Component contents,
619                                          int ownerX, int ownerY) {
620             LightWeightPopup popup = getRecycledLightWeightPopup();
621
622             if (popup == null) {
623                 popup = new LightWeightPopup();
624             }
625             popup.reset(owner, contents, ownerX, ownerY);
626             if (!popup.fitsOnScreen() ||
627                  popup.overlappedByOwnedWindow()) {
628                 popup.hide();
629                 return null;
630             }
631             return popup;
632         }
633
634         /**
635          * Returns the cache to use for heavy weight popups.
636          */

637         private static List JavaDoc getLightWeightPopupCache() {
638             List JavaDoc cache = (List JavaDoc)SwingUtilities.appContextGet(
639                                    lightWeightPopupCacheKey);
640             if (cache == null) {
641                 cache = new ArrayList JavaDoc();
642                 SwingUtilities.appContextPut(lightWeightPopupCacheKey, cache);
643             }
644             return cache;
645         }
646
647         /**
648          * Recycles the LightWeightPopup <code>popup</code>.
649          */

650         private static void recycleLightWeightPopup(LightWeightPopup popup) {
651             synchronized (LightWeightPopup.class) {
652                 List JavaDoc lightPopupCache = getLightWeightPopupCache();
653                 if (lightPopupCache.size() < MAX_CACHE_SIZE) {
654                     lightPopupCache.add(popup);
655                 }
656             }
657         }
658
659         /**
660          * Returns a previously used <code>LightWeightPopup</code>, or null
661          * if none of the popups have been recycled.
662          */

663         private static LightWeightPopup getRecycledLightWeightPopup() {
664             synchronized (LightWeightPopup.class) {
665                 List JavaDoc lightPopupCache = getLightWeightPopupCache();
666                 int c;
667                 if((c = lightPopupCache.size()) > 0) {
668                     LightWeightPopup r = (LightWeightPopup)lightPopupCache.
669                                                get(0);
670                     lightPopupCache.remove(0);
671                     return r;
672                 }
673                 return null;
674             }
675         }
676
677
678
679         //
680
// Popup methods
681
//
682
public void hide() {
683             super.hide();
684
685             Container component = (Container)getComponent();
686
687             component.removeAll();
688             recycleLightWeightPopup(this);
689         }
690         public void show() {
691         Container parent = null;
692
693         if (owner != null) {
694         parent = (owner instanceof Container? (Container)owner : owner.getParent());
695             }
696
697             // Try to find a JLayeredPane and Window to add
698
for (Container p = parent; p != null; p = p.getParent()) {
699                 if (p instanceof JRootPane JavaDoc) {
700                     if (p.getParent() instanceof JInternalFrame JavaDoc) {
701                         continue;
702                     }
703                     parent = ((JRootPane JavaDoc)p).getLayeredPane();
704                     // Continue, so that if there is a higher JRootPane, we'll
705
// pick it up.
706
} else if(p instanceof Window) {
707                     if (parent == null) {
708                         parent = p;
709                     }
710                     break;
711                 } else if (p instanceof JApplet JavaDoc) {
712                     // Painting code stops at Applets, we don't want
713
// to add to a Component above an Applet otherwise
714
// you'll never see it painted.
715
break;
716                 }
717             }
718
719             Point p = SwingUtilities.convertScreenLocationToParent(parent, x,
720                                                                    y);
721             Component component = getComponent();
722
723             component.setLocation(p.x, p.y);
724             if (parent instanceof JLayeredPane JavaDoc) {
725                 ((JLayeredPane JavaDoc)parent).add(component,
726                                            JLayeredPane.POPUP_LAYER, 0);
727             } else {
728                 parent.add(component);
729             }
730         }
731
732         Component createComponent(Component owner) {
733             JComponent JavaDoc component = new JPanel JavaDoc(new BorderLayout(), true);
734
735             component.setOpaque(true);
736             return component;
737         }
738
739         //
740
// Local methods
741
//
742

743         /**
744          * Resets the <code>Popup</code> to an initial state.
745          */

746         void reset(Component owner, Component contents, int ownerX,
747                    int ownerY) {
748             super.reset(owner, contents, ownerX, ownerY);
749
750             JComponent JavaDoc component = (JComponent JavaDoc)getComponent();
751
752             component.setLocation(ownerX, ownerY);
753             component.add(contents, BorderLayout.CENTER);
754             contents.invalidate();
755             pack();
756         }
757     }
758
759
760     /**
761      * Popup implementation that uses a Panel as the popup.
762      */

763     private static class MediumWeightPopup extends ContainerPopup {
764         private static final Object JavaDoc mediumWeightPopupCacheKey =
765                              new StringBuffer JavaDoc("PopupFactory.mediumPopupCache");
766
767         /** Child of the panel. The contents are added to this. */
768     private JRootPane JavaDoc rootPane;
769
770
771         /**
772          * Returns a medium weight <code>Popup</code> implementation. If
773          * the <code>Popup</code> needs more space that in available in
774          * <code>owner</code>, this will return null.
775          */

776         static Popup JavaDoc getMediumWeightPopup(Component owner, Component contents,
777                                           int ownerX, int ownerY) {
778             MediumWeightPopup popup = getRecycledMediumWeightPopup();
779
780             if (popup == null) {
781                 popup = new MediumWeightPopup();
782             }
783             popup.reset(owner, contents, ownerX, ownerY);
784             if (!popup.fitsOnScreen() ||
785                  popup.overlappedByOwnedWindow()) {
786                 popup.hide();
787                 return null;
788             }
789             return popup;
790         }
791
792         /**
793          * Returns the cache to use for medium weight popups.
794          */

795         private static List JavaDoc getMediumWeightPopupCache() {
796             List JavaDoc cache = (List JavaDoc)SwingUtilities.appContextGet(
797                                     mediumWeightPopupCacheKey);
798
799             if (cache == null) {
800                 cache = new ArrayList JavaDoc();
801                 SwingUtilities.appContextPut(mediumWeightPopupCacheKey, cache);
802             }
803             return cache;
804         }
805
806         /**
807          * Recycles the MediumWeightPopup <code>popup</code>.
808          */

809         private static void recycleMediumWeightPopup(MediumWeightPopup popup) {
810             synchronized (MediumWeightPopup.class) {
811                 List JavaDoc mediumPopupCache = getMediumWeightPopupCache();
812                 if (mediumPopupCache.size() < MAX_CACHE_SIZE) {
813                     mediumPopupCache.add(popup);
814                 }
815             }
816         }
817
818         /**
819          * Returns a previously used <code>MediumWeightPopup</code>, or null
820          * if none of the popups have been recycled.
821          */

822         private static MediumWeightPopup getRecycledMediumWeightPopup() {
823             synchronized (MediumWeightPopup.class) {
824                 java.util.List JavaDoc mediumPopupCache =
825                                      getMediumWeightPopupCache();
826                 int c;
827                 if ((c=mediumPopupCache.size()) > 0) {
828                     MediumWeightPopup r = (MediumWeightPopup)mediumPopupCache.
829                                                  get(0);
830                     mediumPopupCache.remove(0);
831                     return r;
832                 }
833                 return null;
834             }
835         }
836
837
838         //
839
// Popup
840
//
841

842         public void hide() {
843             super.hide();
844             rootPane.getContentPane().removeAll();
845             recycleMediumWeightPopup(this);
846         }
847         public void show() {
848             Component component = getComponent();
849             Container parent = null;
850
851             if (owner != null) {
852         parent = owner.getParent();
853             }
854             /*
855               Find the top level window,
856               if it has a layered pane,
857               add to that, otherwise
858               add to the window. */

859             while (!(parent instanceof Window || parent instanceof Applet JavaDoc) &&
860                    (parent!=null)) {
861                 parent = parent.getParent();
862             }
863             // Set the visibility to false before adding to workaround a
864
// bug in Solaris in which the Popup gets added at the wrong
865
// location, which will result in a mouseExit, which will then
866
// result in the ToolTip being removed.
867
if (parent instanceof RootPaneContainer JavaDoc) {
868                 parent = ((RootPaneContainer JavaDoc)parent).getLayeredPane();
869                 Point p = SwingUtilities.convertScreenLocationToParent(parent,
870                                                                        x, y);
871                 component.setVisible(false);
872                 component.setLocation(p.x, p.y);
873                 ((JLayeredPane JavaDoc)parent).add(component, JLayeredPane.POPUP_LAYER,
874                                            0);
875             } else {
876                 Point p = SwingUtilities.convertScreenLocationToParent(parent,
877                                                                        x, y);
878
879                 component.setLocation(p.x, p.y);
880                 component.setVisible(false);
881                 parent.add(component);
882             }
883             component.setVisible(true);
884         }
885
886         Component createComponent(Component owner) {
887             Panel component = new Panel(new BorderLayout());
888
889         rootPane = new JRootPane JavaDoc();
890             // NOTE: this uses setOpaque vs LookAndFeel.installProperty as
891
// there is NO reason for the RootPane not to be opaque. For
892
// painting to work the contentPane must be opaque, therefor the
893
// RootPane can also be opaque.
894
rootPane.setOpaque(true);
895         component.add(rootPane, BorderLayout.CENTER);
896             return component;
897         }
898
899         /**
900          * Resets the <code>Popup</code> to an initial state.
901          */

902         void reset(Component owner, Component contents, int ownerX,
903                    int ownerY) {
904             super.reset(owner, contents, ownerX, ownerY);
905
906             Component component = getComponent();
907
908             component.setLocation(ownerX, ownerY);
909             rootPane.getContentPane().add(contents, BorderLayout.CENTER);
910             contents.invalidate();
911             component.validate();
912             pack();
913         }
914     }
915 }
916
Popular Tags