001: /*
002: * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025: package sun.awt.X11;
026:
027: import java.awt.*;
028: import java.awt.peer.*;
029: import java.awt.event.*;
030:
031: import java.lang.reflect.Field;
032: import java.lang.reflect.Method;
033: import java.lang.reflect.InvocationTargetException;
034:
035: import java.util.Vector;
036: import java.util.logging.*;
037:
038: import sun.awt.SunToolkit;
039:
040: public class XPopupMenuPeer extends XMenuWindow implements
041: PopupMenuPeer {
042:
043: /************************************************
044: *
045: * Data members
046: *
047: ************************************************/
048: private static Logger log = Logger
049: .getLogger("sun.awt.X11.XBaseMenuWindow");
050:
051: /*
052: * Primary members
053: */
054: private XComponentPeer componentPeer;
055: private PopupMenu popupMenuTarget;
056:
057: /*
058: * If mouse button is clicked on item showing submenu
059: * we have to hide its submenu.
060: * This member saves the submenu under cursor
061: * Only if it's showing
062: */
063: private XMenuPeer showingMousePressedSubmenu = null;
064:
065: /*
066: * Painting constants
067: */
068: private final static int CAPTION_MARGIN_TOP = 4;
069: private final static int CAPTION_SEPARATOR_HEIGHT = 6;
070:
071: /*
072: * Menu's fields & methods
073: */
074: //Fix for 6184485: Popup menu is not disabled on XToolkit even when calling setEnabled (false)
075: private final static Field f_enabled;
076: //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit
077: private final static Field f_label;
078: private final static Method m_getFont;
079: private final static Field f_items;
080:
081: static {
082: f_enabled = SunToolkit.getField(MenuItem.class, "enabled");
083: f_label = SunToolkit.getField(MenuItem.class, "label");
084: f_items = SunToolkit.getField(Menu.class, "items");
085: m_getFont = SunToolkit.getMethod(MenuComponent.class,
086: "getFont_NoClientCode", null);
087: }
088:
089: /************************************************
090: *
091: * Construction
092: *
093: ************************************************/
094: XPopupMenuPeer(PopupMenu target) {
095: super (null);
096: this .popupMenuTarget = target;
097: }
098:
099: /************************************************
100: *
101: * Implementaion of interface methods
102: *
103: ************************************************/
104: /*
105: * From MenuComponentPeer
106: */
107: public void setFont(Font f) {
108: resetMapping();
109: setItemsFont(f);
110: postPaintEvent();
111: }
112:
113: /*
114: * From MenuItemPeer
115: */
116: public void setLabel(String label) {
117: resetMapping();
118: postPaintEvent();
119: }
120:
121: public void setEnabled(boolean enabled) {
122: postPaintEvent();
123: }
124:
125: /**
126: * DEPRECATED: Replaced by setEnabled(boolean).
127: * @see java.awt.peer.MenuItemPeer
128: */
129: public void enable() {
130: setEnabled(true);
131: }
132:
133: /**
134: * DEPRECATED: Replaced by setEnabled(boolean).
135: * @see java.awt.peer.MenuItemPeer
136: */
137: public void disable() {
138: setEnabled(false);
139: }
140:
141: /*
142: * From MenuPeer
143: */
144: /**
145: * addSeparator routines are not used
146: * in peers. Shared code invokes addItem("-")
147: * for adding separators
148: */
149: public void addSeparator() {
150: if (log.isLoggable(Level.FINER))
151: log.finer("addSeparator is not implemented");
152: }
153:
154: /*
155: * From PopupMenuPeer
156: */
157: public void show(Event e) {
158: target = (Component) e.target;
159: // Get menus from the target.
160: Vector targetItemVector = getMenuTargetItems();
161: if (targetItemVector != null) {
162: reloadItems(targetItemVector);
163: //Fix for 6287092: JCK15a: api/java_awt/interactive/event/EventTests.html#EventTest0015 fails, mustang
164: Point tl = target.getLocationOnScreen();
165: Point pt = new Point(tl.x + e.x, tl.y + e.y);
166: //Fixed 6266513: Incorrect key handling in XAWT popup menu
167: //No item should be selected when showing popup menu
168: if (!ensureCreated()) {
169: return;
170: }
171: Dimension dim = getDesiredSize();
172: //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened
173: //near the periphery of the screen, XToolkit
174: Rectangle bounds = getWindowBounds(pt, dim);
175: reshape(bounds);
176: xSetVisible(true);
177: toFront();
178: selectItem(null, false);
179: grabInput();
180: }
181: }
182:
183: /************************************************
184: *
185: * Access to target's fields
186: *
187: ************************************************/
188:
189: //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit
190: Font getTargetFont() {
191: if (popupMenuTarget == null) {
192: return XWindow.defaultFont;
193: }
194: try {
195: return (Font) m_getFont.invoke(popupMenuTarget,
196: new Object[0]);
197: } catch (IllegalAccessException e) {
198: e.printStackTrace();
199: } catch (InvocationTargetException e) {
200: e.printStackTrace();
201: }
202: return XWindow.defaultFont;
203: }
204:
205: String getTargetLabel() {
206: if (target == null) {
207: return "";
208: }
209: try {
210: String label = (String) f_label.get(popupMenuTarget);
211: return (label == null) ? "" : label;
212: } catch (IllegalAccessException e) {
213: e.printStackTrace();
214: }
215: return "";
216: }
217:
218: //Fix for 6184485: Popup menu is not disabled on XToolkit even when calling setEnabled (false)
219: boolean isTargetEnabled() {
220: if (popupMenuTarget == null) {
221: return false;
222: }
223: try {
224: return f_enabled.getBoolean(popupMenuTarget);
225: } catch (IllegalAccessException e) {
226: e.printStackTrace();
227: }
228: return false;
229: }
230:
231: Vector getMenuTargetItems() {
232: try {
233: return (Vector) f_items.get(popupMenuTarget);
234: } catch (IllegalAccessException iae) {
235: iae.printStackTrace();
236: return null;
237: }
238: }
239:
240: /************************************************
241: *
242: * Utility functions
243: *
244: ************************************************/
245:
246: //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened
247: //near the periphery of the screen, XToolkit
248: /**
249: * Calculates placement of popup menu window
250: * given origin in global coordinates and
251: * size of menu window. Returns suggested
252: * rectangle for menu window in global coordinates
253: * @param origin the origin point specified in show()
254: * function converted to global coordinates
255: * @param windowSize the desired size of menu's window
256: */
257: protected Rectangle getWindowBounds(Point origin,
258: Dimension windowSize) {
259: Rectangle globalBounds = new Rectangle(origin.x, origin.y, 0, 0);
260: Dimension screenSize = Toolkit.getDefaultToolkit()
261: .getScreenSize();
262: Rectangle res;
263: res = fitWindowRight(globalBounds, windowSize, screenSize);
264: if (res != null) {
265: return res;
266: }
267: res = fitWindowLeft(globalBounds, windowSize, screenSize);
268: if (res != null) {
269: return res;
270: }
271: res = fitWindowBelow(globalBounds, windowSize, screenSize);
272: if (res != null) {
273: return res;
274: }
275: res = fitWindowAbove(globalBounds, windowSize, screenSize);
276: if (res != null) {
277: return res;
278: }
279: return fitWindowToScreen(windowSize, screenSize);
280: }
281:
282: /************************************************
283: *
284: * Overriden XMenuWindow caption-painting functions
285: * Necessary to fix 6267144: PIT: Popup menu label is not shown, XToolkit
286: *
287: ************************************************/
288: /**
289: * Returns height of menu window's caption.
290: * Can be overriden for popup menus and tear-off menus
291: */
292: protected Dimension getCaptionSize() {
293: String s = getTargetLabel();
294: if (s.equals("")) {
295: return null;
296: }
297: Graphics g = getGraphics();
298: if (g == null) {
299: return null;
300: }
301: try {
302: g.setFont(getTargetFont());
303: FontMetrics fm = g.getFontMetrics();
304: String str = getTargetLabel();
305: int width = fm.stringWidth(str);
306: int height = CAPTION_MARGIN_TOP + fm.getHeight()
307: + CAPTION_SEPARATOR_HEIGHT;
308: Dimension textDimension = new Dimension(width, height);
309: return textDimension;
310: } finally {
311: g.dispose();
312: }
313: }
314:
315: /**
316: * Paints menu window's caption.
317: * Can be overriden for popup menus and tear-off menus.
318: * Default implementation does nothing
319: */
320: protected void paintCaption(Graphics g, Rectangle rect) {
321: String s = getTargetLabel();
322: if (s.equals("")) {
323: return;
324: }
325: g.setFont(getTargetFont());
326: FontMetrics fm = g.getFontMetrics();
327: String str = getTargetLabel();
328: int width = fm.stringWidth(str);
329: int textx = rect.x + (rect.width - width) / 2;
330: int texty = rect.y + CAPTION_MARGIN_TOP + fm.getAscent();
331: int sepy = rect.y + rect.height - CAPTION_SEPARATOR_HEIGHT / 2;
332: g.setColor(isTargetEnabled() ? getForegroundColor()
333: : getDisabledColor());
334: g.drawString(s, textx, texty);
335: draw3DRect(g, rect.x, sepy, rect.width, 2, false);
336: }
337:
338: /************************************************
339: *
340: * Overriden XBaseMenuWindow functions
341: *
342: ************************************************/
343: protected void doDispose() {
344: super .doDispose();
345: XToolkit.targetDisposedPeer(popupMenuTarget, this );
346: }
347:
348: protected void handleEvent(AWTEvent event) {
349: switch (event.getID()) {
350: case MouseEvent.MOUSE_PRESSED:
351: case MouseEvent.MOUSE_RELEASED:
352: case MouseEvent.MOUSE_CLICKED:
353: case MouseEvent.MOUSE_MOVED:
354: case MouseEvent.MOUSE_ENTERED:
355: case MouseEvent.MOUSE_EXITED:
356: case MouseEvent.MOUSE_DRAGGED:
357: doHandleJavaMouseEvent((MouseEvent) event);
358: break;
359: case KeyEvent.KEY_PRESSED:
360: case KeyEvent.KEY_RELEASED:
361: doHandleJavaKeyEvent((KeyEvent) event);
362: break;
363: default:
364: super .handleEvent(event);
365: break;
366: }
367: }
368:
369: /************************************************
370: *
371: * Overriden XWindow general-purpose functions
372: *
373: ************************************************/
374: void ungrabInputImpl() {
375: hide();
376: }
377:
378: /************************************************
379: *
380: * Overriden XWindow keyboard processing
381: *
382: ************************************************/
383:
384: /*
385: * In previous version keys were handled in handleKeyPress.
386: * Now we override this function do disable F10 explicit
387: * processing. All processing is done using KeyEvent.
388: */
389: public void handleKeyPress(XEvent xev) {
390: XKeyEvent xkey = xev.get_xkey();
391: if (log.isLoggable(Level.FINE)) {
392: log.fine(xkey.toString());
393: }
394: if (isEventDisabled(xev)) {
395: return;
396: }
397: final Component currentSource = (Component) getEventSource();
398: handleKeyPress(xkey);
399: }
400:
401: }
|