001: /*
002: * Copyright (c) 2005-2006 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.looks.common;
032:
033: import java.awt.Component;
034:
035: import javax.swing.LookAndFeel;
036: import javax.swing.Popup;
037: import javax.swing.PopupFactory;
038:
039: import com.jgoodies.looks.LookUtils;
040: import com.jgoodies.looks.Options;
041:
042: /**
043: * The JGoodies Looks implementation of <code>PopupFactory</code>.
044: * Adds a drop shadow border to all popups except ComboBox popups.
045: * It is installed by the JGoodies Plastic L&F, as well as by
046: * the JGoodies Windows L&F during the Look&Feel initialization,
047: * see {@link com.jgoodies.looks.plastic.PlasticLookAndFeel#initialize} and
048: * {@link com.jgoodies.looks.windows.WindowsLookAndFeel#initialize}.<p>
049: *
050: * This factory shall not be used on platforms that provide native drop shadows,
051: * such as the Mac OS X. Therefore the invocation of the {@link #install()}
052: * method will have no effect on such platforms.<p>
053: *
054: * <strong>Note:</strong> To be used in a sandbox environment, this PopupFactory
055: * requires two AWT permissions: <code>createRobot</code> and
056: * <code>readDisplayPixels</code>. The reason for it is, that in the case of
057: * the heavy weight popups this PopupFactory uses a Robot to snapshot
058: * the screen background to simulate the drop shadow effect.
059: *
060: * @author Andrej Golovnin
061: * @author Karsten Lentzsch
062: * @version $Revision: 1.2 $
063: *
064: * @see java.awt.AWTPermission
065: * @see java.awt.Robot
066: * @see javax.swing.Popup
067: * @see LookAndFeel#initialize
068: * @see LookAndFeel#uninitialize
069: */
070: public final class ShadowPopupFactory extends PopupFactory {
071:
072: /**
073: * In the case of heavy weight popups, snapshots of the screen background
074: * will be stored as client properties of the popup contents' parent.
075: * These snapshots will be used by the popup border to simulate the drop
076: * shadow effect. The two following constants define the names of
077: * these client properties.
078: *
079: * @see com.jgoodies.looks.common.ShadowPopupBorder
080: */
081: static final String PROP_HORIZONTAL_BACKGROUND = "jgoodies.hShadowBg";
082: static final String PROP_VERTICAL_BACKGROUND = "jgoodies.vShadowBg";
083:
084: /**
085: * The PopupFactory used before this PopupFactory has been installed
086: * in <code>#install</code>. Used to restored the original state
087: * in <code>#uninstall</code>.
088: */
089: private final PopupFactory storedFactory;
090:
091: // Instance Creation ******************************************************
092:
093: private ShadowPopupFactory(PopupFactory storedFactory) {
094: this .storedFactory = storedFactory;
095: }
096:
097: // API ********************************************************************
098:
099: /**
100: * Installs the ShadowPopupFactory as the shared popup factory
101: * on non-Mac platforms. Also stores the previously set factory,
102: * so that it can be restored in <code>#uninstall</code>.<p>
103: *
104: * In some Mac Java environments the popup factory throws
105: * a NullPointerException when we call <code>#getPopup</code>.<p>
106: *
107: * TODO: The Mac case shows that we may have problems replacing
108: * non PopupFactory instances. Therefore we should consider
109: * replacing only instances of PopupFactory.
110: *
111: * @see #uninstall()
112: */
113: public static void install() {
114: if (LookUtils.IS_OS_MAC) {
115: return;
116: }
117:
118: PopupFactory factory = PopupFactory.getSharedInstance();
119: if (factory instanceof ShadowPopupFactory)
120: return;
121:
122: PopupFactory.setSharedInstance(new ShadowPopupFactory(factory));
123: }
124:
125: /**
126: * Uninstalls the ShadowPopupFactory and restores the original
127: * popup factory as the new shared popup factory.
128: *
129: * @see #install()
130: */
131: public static void uninstall() {
132: PopupFactory factory = PopupFactory.getSharedInstance();
133: if (!(factory instanceof ShadowPopupFactory))
134: return;
135:
136: PopupFactory stored = ((ShadowPopupFactory) factory).storedFactory;
137: PopupFactory.setSharedInstance(stored);
138: }
139:
140: /**
141: * Creates a <code>Popup</code> for the Component <code>owner</code>
142: * containing the Component <code>contents</code>. In addition to
143: * the superclass behavior, we try to return a Popup that has a drop shadow,
144: * if popup drop shadows are active - as returned by
145: * <code>Options#isPopupDropShadowActive</code>.<p>
146: *
147: * <code>owner</code> is used to determine which <code>Window</code> the new
148: * <code>Popup</code> will parent the <code>Component</code> the
149: * <code>Popup</code> creates to. A null <code>owner</code> implies there
150: * is no valid parent. <code>x</code> and
151: * <code>y</code> specify the preferred initial location to place
152: * the <code>Popup</code> at. Based on screen size, or other paramaters,
153: * the <code>Popup</code> may not display at <code>x</code> and
154: * <code>y</code>.<p>
155: *
156: * We invoke the super <code>#getPopup</code>, not the one in the
157: * stored factory, because the popup type is set in this instance,
158: * not in the stored one.
159: *
160: * @param owner Component mouse coordinates are relative to, may be null
161: * @param contents Contents of the Popup
162: * @param x Initial x screen coordinate
163: * @param y Initial y screen coordinate
164: * @return Popup containing Contents
165: * @throws IllegalArgumentException if contents is null
166: *
167: * @see Options#isPopupDropShadowActive()
168: */
169: public Popup getPopup(Component owner, Component contents, int x,
170: int y) throws IllegalArgumentException {
171: Popup popup = super.getPopup(owner, contents, x, y);
172: return Options.isPopupDropShadowActive() ? ShadowPopup
173: .getInstance(owner, contents, x, y, popup) : popup;
174: }
175:
176: }
|