001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.gsfret.editor.hyperlink;
043:
044: import java.awt.AWTEvent;
045: import java.awt.Component;
046: import java.awt.Container;
047: import java.awt.Frame;
048: import java.awt.Point;
049: import java.awt.Rectangle;
050: import java.awt.Toolkit;
051: import java.awt.event.AWTEventListener;
052: import java.awt.event.ComponentAdapter;
053: import java.awt.event.ComponentEvent;
054: import java.awt.event.FocusListener;
055: import java.awt.event.KeyEvent;
056: import java.awt.event.MouseEvent;
057: import java.awt.event.WindowEvent;
058: import java.awt.event.WindowStateListener;
059: import javax.swing.AbstractAction;
060: import javax.swing.Action;
061: import javax.swing.JComponent;
062: import javax.swing.JDialog;
063: import javax.swing.KeyStroke;
064: import javax.swing.SwingUtilities;
065: import org.openide.windows.WindowManager;
066:
067: /**
068: * This file is originally from Retouche, the Java Support
069: * infrastructure in NetBeans. I have modified the file as little
070: * as possible to make merging Retouche fixes back as simple as
071: * possible.
072: *
073: * (This used to be PopupUtil in org.netbeans.modules.java.editor.overridden)
074: *
075: * @author phrebejk
076: */
077: public final class PopupUtil {
078:
079: // private static MyFocusListener mfl = new MyFocusListener();
080:
081: private static final String CLOSE_KEY = "CloseKey"; //NOI18N
082: private static final Action CLOSE_ACTION = new CloseAction();
083: private static final KeyStroke ESC_KEY_STROKE = KeyStroke
084: .getKeyStroke(KeyEvent.VK_ESCAPE, 0);
085:
086: private static final String POPUP_NAME = "popupComponent"; //NOI18N
087: private static JDialog popupWindow;
088: private static HideAWTListener hideListener = new HideAWTListener();
089:
090: // Singleton
091: private PopupUtil() {
092: }
093:
094: public static boolean isPopupShowing() {
095: return popupWindow != null;
096: }
097:
098: public static void showPopup(JComponent content, String title) {
099: showPopup(content, title, -1, -1, false);
100: }
101:
102: public static void showPopup(JComponent content, String title,
103: int x, int y, boolean undecorated) {
104: showPopup(content, title, x, y, false, -1);
105: }
106:
107: public static void showPopup(JComponent content, String title,
108: int x, int y, boolean undecorated, int altHeight) {
109: if (popupWindow != null) {
110: return; // Content already showing
111: }
112:
113: Toolkit.getDefaultToolkit().addAWTEventListener(hideListener,
114: AWTEvent.MOUSE_EVENT_MASK);
115:
116: // NOT using PopupFactory
117: // 1. on linux, creates mediumweight popup taht doesn't refresh behind visible glasspane
118: // 2. on mac, needs an owner frame otherwise hiding tooltip also hides the popup. (linux requires no owner frame to force heavyweight)
119: // 3. the created window is not focusable window
120:
121: popupWindow = new JDialog(getMainWindow());
122: popupWindow.setName(POPUP_NAME);
123: popupWindow.setUndecorated(undecorated);
124: popupWindow.getRootPane().getInputMap(
125: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
126: ESC_KEY_STROKE, CLOSE_KEY);
127: popupWindow.getRootPane().getActionMap().put(CLOSE_KEY,
128: CLOSE_ACTION);
129:
130: //set a11y
131: String a11yName = content.getAccessibleContext()
132: .getAccessibleName();
133: if (a11yName != null && !a11yName.equals(""))
134: popupWindow.getAccessibleContext().setAccessibleName(
135: a11yName);
136: String a11yDesc = content.getAccessibleContext()
137: .getAccessibleDescription();
138: if (a11yDesc != null && !a11yDesc.equals(""))
139: popupWindow.getAccessibleContext()
140: .setAccessibleDescription(a11yDesc);
141:
142: if (title != null) {
143: // popupWindow.setTitle( title );
144: }
145: // popupWindow.setAlwaysOnTop( true );
146: popupWindow.getContentPane().add(content);
147: // popupWindow.addFocusListener( mfl );
148: // content.addFocusListener( mfl );
149:
150: WindowManager.getDefault().getMainWindow()
151: .addWindowStateListener(hideListener);
152: WindowManager.getDefault().getMainWindow()
153: .addComponentListener(hideListener);
154: resizePopup();
155:
156: if (x != (-1)) {
157: Point p = fitToScreen(x, y, altHeight);
158: popupWindow.setLocation(p.x, p.y);
159:
160: }
161:
162: popupWindow.setVisible(true);
163: // System.out.println(" RFIW ==" + popupWindow.requestFocusInWindow() );
164: content.requestFocus();
165: content.requestFocusInWindow();
166: // System.out.println(" has focus =" + content.hasFocus());
167: // System.out.println(" has focus =" + popupWindow.hasFocus());
168: // System.out.println(" window focusable=" + popupWindow.isFocusableWindow());
169: }
170:
171: public static void hidePopup() {
172: if (popupWindow != null) {
173: // popupWindow.getContentPane().removeAll();
174: Toolkit.getDefaultToolkit().removeAWTEventListener(
175: hideListener);
176:
177: popupWindow.setVisible(false);
178: popupWindow.dispose();
179: }
180: WindowManager.getDefault().getMainWindow()
181: .removeWindowStateListener(hideListener);
182: WindowManager.getDefault().getMainWindow()
183: .removeComponentListener(hideListener);
184: popupWindow = null;
185: }
186:
187: private static void resizePopup() {
188: popupWindow.pack();
189: Point point = new Point(0, 0);
190: SwingUtilities.convertPointToScreen(point, getMainWindow());
191: popupWindow.setLocation(point.x
192: + (getMainWindow().getWidth() - popupWindow.getWidth())
193: / 2, point.y
194: + (getMainWindow().getHeight() - popupWindow
195: .getHeight()) / 3);
196: }
197:
198: private static final int X_INSET = 10;
199: private static final int Y_INSET = X_INSET;
200:
201: private static Point fitToScreen(int x, int y, int altHeight) {
202:
203: Rectangle screen = org.openide.util.Utilities
204: .getUsableScreenBounds();
205:
206: Point p = new Point(x, y);
207:
208: // Adjust the x postition if necessary
209: if ((p.x + popupWindow.getWidth()) > (screen.x + screen.width - X_INSET)) {
210: p.x = screen.x + screen.width - X_INSET
211: - popupWindow.getWidth();
212: }
213:
214: // Adjust the y position if necessary
215: if ((p.y + popupWindow.getHeight()) > (screen.y + screen.height - X_INSET)) {
216: p.y = p.y - popupWindow.getHeight() - altHeight;
217: }
218:
219: return p;
220: }
221:
222: private static Frame getMainWindow() {
223: return WindowManager.getDefault().getMainWindow();
224: }
225:
226: // Innerclasses ------------------------------------------------------------
227:
228: private static class HideAWTListener extends ComponentAdapter
229: implements AWTEventListener, WindowStateListener {
230:
231: public void eventDispatched(java.awt.AWTEvent aWTEvent) {
232: if (aWTEvent instanceof MouseEvent) {
233: MouseEvent mv = (MouseEvent) aWTEvent;
234: if (mv.getID() == MouseEvent.MOUSE_CLICKED
235: && mv.getClickCount() > 0) {
236: //#118828
237: if (!(aWTEvent.getSource() instanceof Component)) {
238: hidePopup();
239: return;
240: }
241:
242: Component comp = (Component) aWTEvent.getSource();
243: Container par = SwingUtilities.getAncestorNamed(
244: POPUP_NAME, comp); //NOI18N
245: // Container barpar = SwingUtilities.getAncestorOfClass(PopupUtil.class, comp);
246: // if (par == null && barpar == null) {
247: if (par == null) {
248: hidePopup();
249: }
250: }
251: }
252: }
253:
254: public void windowStateChanged(WindowEvent windowEvent) {
255: if (popupWindow != null) {
256: int oldState = windowEvent.getOldState();
257: int newState = windowEvent.getNewState();
258:
259: if (((oldState & Frame.ICONIFIED) == 0)
260: && ((newState & Frame.ICONIFIED) == Frame.ICONIFIED)) {
261: hidePopup();
262: // } else if (((oldState & Frame.ICONIFIED) == Frame.ICONIFIED) &&
263: // ((newState & Frame.ICONIFIED) == 0 )) {
264: // //TODO remember we showed before and show again? I guess not worth the efford, not part of spec.
265: }
266: }
267:
268: }
269:
270: public void componentResized(ComponentEvent evt) {
271: if (popupWindow != null) {
272: resizePopup();
273: }
274: }
275:
276: public void componentMoved(ComponentEvent evt) {
277: if (popupWindow != null) {
278: resizePopup();
279: }
280: }
281:
282: }
283:
284: private static class MyFocusListener implements FocusListener {
285:
286: public void focusLost(java.awt.event.FocusEvent e) {
287: System.out.println(e);
288: }
289:
290: public void focusGained(java.awt.event.FocusEvent e) {
291: System.out.println(e);
292: }
293:
294: }
295:
296: private static class CloseAction extends AbstractAction {
297:
298: public void actionPerformed(java.awt.event.ActionEvent e) {
299: hidePopup();
300: }
301:
302: }
303:
304: }
|