1 7 8 package javax.swing; 9 10 import java.applet.Applet ; 11 import java.awt.*; 12 import java.awt.event.WindowAdapter ; 13 import java.awt.event.WindowEvent ; 14 import java.util.ArrayList ; 15 import java.util.HashMap ; 16 import java.util.List ; 17 import java.util.Map ; 18 19 40 public class PopupFactory { 41 46 private static final Object SharedInstanceKey = 47 new StringBuffer ("PopupFactory.SharedInstanceKey"); 48 49 52 private static final int MAX_CACHE_SIZE = 5; 53 54 57 static final int LIGHT_WEIGHT_POPUP = 0; 58 59 62 static final int MEDIUM_WEIGHT_POPUP = 1; 63 64 67 static final int HEAVY_WEIGHT_POPUP = 2; 68 69 72 private int popupType = LIGHT_WEIGHT_POPUP; 73 74 78 static final StringBuffer forceHeavyWeightPopupKey = 79 new StringBuffer ("__force_heavy_weight_popup__"); 80 81 82 92 public static void setSharedInstance(PopupFactory factory) { 93 if (factory == null) { 94 throw new IllegalArgumentException ("PopupFactory can not be null"); 95 } 96 SwingUtilities.appContextPut(SharedInstanceKey, factory); 97 } 98 99 105 public static PopupFactory getSharedInstance() { 106 PopupFactory factory = (PopupFactory )SwingUtilities.appContextGet( 107 SharedInstanceKey); 108 109 if (factory == null) { 110 factory = new PopupFactory (); 111 setSharedInstance(factory); 112 } 113 return factory; 114 } 115 116 117 121 void setPopupType(int type) { 122 popupType = type; 123 } 124 125 128 int getPopupType() { 129 return popupType; 130 } 131 132 151 public Popup getPopup(Component owner, Component contents, 152 int x, int y) throws IllegalArgumentException { 153 if (contents == null) { 154 throw new IllegalArgumentException ( 155 "Popup.getPopup must be passed non-null contents"); 156 } 157 158 int popupType = getPopupType(owner, contents, x, y); 159 Popup popup = getPopup(owner, contents, x, y, popupType); 160 161 if (popup == null) { 162 popup = getPopup(owner, contents, x, y, HEAVY_WEIGHT_POPUP); 164 } 165 return popup; 166 } 167 168 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 ) && 180 !(contents instanceof JPopupMenu )) { 181 popupType = MEDIUM_WEIGHT_POPUP; 182 } 183 184 Component c = owner; 188 while (c != null) { 189 if (c instanceof JComponent ) { 190 if (((JComponent )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 206 private Popup 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 226 private Popup getHeadlessPopup(Component owner, Component contents, 227 int ownerX, int ownerY) { 228 return HeadlessPopup.getHeadlessPopup(owner, contents, ownerX, ownerY); 229 } 230 231 234 private Popup getLightWeightPopup(Component owner, Component contents, 235 int ownerX, int ownerY) { 236 return LightWeightPopup.getLightWeightPopup(owner, contents, ownerX, 237 ownerY); 238 } 239 240 243 private Popup getMediumWeightPopup(Component owner, Component contents, 244 int ownerX, int ownerY) { 245 return MediumWeightPopup.getMediumWeightPopup(owner, contents, 246 ownerX, ownerY); 247 } 248 249 252 private Popup 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 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 ) { 271 return true; 272 } 273 } 274 } 275 return false; 276 } 277 278 279 282 private static class HeavyWeightPopup extends Popup { 283 private static final Object heavyWeightPopupCacheKey = 284 new StringBuffer ("PopupFactory.heavyWeightPopupCache"); 285 286 290 static Popup 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 ) { 303 JPopupMenu jpm = (JPopupMenu ) contents; 304 Component popComps[] = jpm.getComponents(); 305 for(int i=0;i<popComps.length;i++) { 306 if(!(popComps[i] instanceof MenuElement ) && 307 !(popComps[i] instanceof JSeparator )) { 308 focusPopup = true; 309 break; 310 } 311 } 312 } 313 } 314 315 if (popup == null || 316 ((JWindow ) popup.getComponent()) 317 .getFocusableWindowState() != focusPopup) { 318 319 if(popup != null) { 320 popup._dispose(); 323 } 324 325 popup = new HeavyWeightPopup(); 326 } 327 328 popup.reset(owner, contents, ownerX, ownerY); 329 330 if(focusPopup) { 331 JWindow wnd = (JWindow ) popup.getComponent(); 332 wnd.setFocusableWindowState(true); 333 wnd.setName("###focusableSwingPopup###"); 336 } 337 338 return popup; 339 } 340 341 347 private static HeavyWeightPopup getRecycledHeavyWeightPopup(Window w) { 348 synchronized (HeavyWeightPopup.class) { 349 List cache; 350 Map heavyPopupCache = getHeavyWeightPopupCache(); 351 352 if (heavyPopupCache.containsKey(w)) { 353 cache = (List )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 372 private static Map getHeavyWeightPopupCache() { 373 synchronized (HeavyWeightPopup.class) { 374 Map cache = (Map )SwingUtilities.appContextGet( 375 heavyWeightPopupCacheKey); 376 377 if (cache == null) { 378 cache = new HashMap (2); 379 SwingUtilities.appContextPut(heavyWeightPopupCacheKey, 380 cache); 381 } 382 return cache; 383 } 384 } 385 386 389 private static void recycleHeavyWeightPopup(HeavyWeightPopup popup) { 390 synchronized (HeavyWeightPopup.class) { 391 List cache; 392 Object window = SwingUtilities.getWindowAncestor( 393 popup.getComponent()); 394 Map heavyPopupCache = getHeavyWeightPopupCache(); 395 396 if (window instanceof Popup.DefaultFrame || 397 !((Window)window).isVisible()) { 398 popup._dispose(); 404 return; 405 } else if (heavyPopupCache.containsKey(window)) { 406 cache = (List )heavyPopupCache.get(window); 407 } else { 408 cache = new ArrayList (); 409 heavyPopupCache.put(window, cache); 410 final Window w = (Window)window; 412 413 w.addWindowListener(new WindowAdapter () { 414 public void windowClosed(WindowEvent e) { 415 List popups; 416 417 synchronized(HeavyWeightPopup.class) { 418 Map heavyPopupCache2 = 419 getHeavyWeightPopupCache(); 420 421 popups = (List )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 public void hide() { 446 super.hide(); 447 recycleHeavyWeightPopup(this); 448 } 449 450 455 void dispose() { 456 } 457 458 void _dispose() { 459 super.dispose(); 460 } 461 } 462 463 464 465 469 private static class ContainerPopup extends Popup { 470 471 Component owner; 472 473 int x; 474 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 ) || (owner instanceof JDialog ) || 504 (owner instanceof JWindow )) { 505 owner = ((RootPaneContainer )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 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 || 552 parent instanceof JDialog || 553 parent instanceof JWindow ) { 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 ) { 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 ) { 574 break; 576 } 577 } 578 } 579 return false; 580 } 581 } 582 583 584 587 private static class HeadlessPopup extends ContainerPopup { 588 static Popup 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 609 private static class LightWeightPopup extends ContainerPopup { 610 private static final Object lightWeightPopupCacheKey = 611 new StringBuffer ("PopupFactory.lightPopupCache"); 612 613 618 static Popup 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 637 private static List getLightWeightPopupCache() { 638 List cache = (List )SwingUtilities.appContextGet( 639 lightWeightPopupCacheKey); 640 if (cache == null) { 641 cache = new ArrayList (); 642 SwingUtilities.appContextPut(lightWeightPopupCacheKey, cache); 643 } 644 return cache; 645 } 646 647 650 private static void recycleLightWeightPopup(LightWeightPopup popup) { 651 synchronized (LightWeightPopup.class) { 652 List lightPopupCache = getLightWeightPopupCache(); 653 if (lightPopupCache.size() < MAX_CACHE_SIZE) { 654 lightPopupCache.add(popup); 655 } 656 } 657 } 658 659 663 private static LightWeightPopup getRecycledLightWeightPopup() { 664 synchronized (LightWeightPopup.class) { 665 List 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 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 for (Container p = parent; p != null; p = p.getParent()) { 699 if (p instanceof JRootPane ) { 700 if (p.getParent() instanceof JInternalFrame ) { 701 continue; 702 } 703 parent = ((JRootPane )p).getLayeredPane(); 704 } else if(p instanceof Window) { 707 if (parent == null) { 708 parent = p; 709 } 710 break; 711 } else if (p instanceof JApplet ) { 712 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 ) { 725 ((JLayeredPane )parent).add(component, 726 JLayeredPane.POPUP_LAYER, 0); 727 } else { 728 parent.add(component); 729 } 730 } 731 732 Component createComponent(Component owner) { 733 JComponent component = new JPanel (new BorderLayout(), true); 734 735 component.setOpaque(true); 736 return component; 737 } 738 739 743 746 void reset(Component owner, Component contents, int ownerX, 747 int ownerY) { 748 super.reset(owner, contents, ownerX, ownerY); 749 750 JComponent component = (JComponent )getComponent(); 751 752 component.setLocation(ownerX, ownerY); 753 component.add(contents, BorderLayout.CENTER); 754 contents.invalidate(); 755 pack(); 756 } 757 } 758 759 760 763 private static class MediumWeightPopup extends ContainerPopup { 764 private static final Object mediumWeightPopupCacheKey = 765 new StringBuffer ("PopupFactory.mediumPopupCache"); 766 767 768 private JRootPane rootPane; 769 770 771 776 static Popup 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 795 private static List getMediumWeightPopupCache() { 796 List cache = (List )SwingUtilities.appContextGet( 797 mediumWeightPopupCacheKey); 798 799 if (cache == null) { 800 cache = new ArrayList (); 801 SwingUtilities.appContextPut(mediumWeightPopupCacheKey, cache); 802 } 803 return cache; 804 } 805 806 809 private static void recycleMediumWeightPopup(MediumWeightPopup popup) { 810 synchronized (MediumWeightPopup.class) { 811 List mediumPopupCache = getMediumWeightPopupCache(); 812 if (mediumPopupCache.size() < MAX_CACHE_SIZE) { 813 mediumPopupCache.add(popup); 814 } 815 } 816 } 817 818 822 private static MediumWeightPopup getRecycledMediumWeightPopup() { 823 synchronized (MediumWeightPopup.class) { 824 java.util.List 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 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 859 while (!(parent instanceof Window || parent instanceof Applet ) && 860 (parent!=null)) { 861 parent = parent.getParent(); 862 } 863 if (parent instanceof RootPaneContainer ) { 868 parent = ((RootPaneContainer )parent).getLayeredPane(); 869 Point p = SwingUtilities.convertScreenLocationToParent(parent, 870 x, y); 871 component.setVisible(false); 872 component.setLocation(p.x, p.y); 873 ((JLayeredPane )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 (); 890 rootPane.setOpaque(true); 895 component.add(rootPane, BorderLayout.CENTER); 896 return component; 897 } 898 899 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 |