001: /*
002: * Copyright 1996-2006 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:
026: package sun.awt;
027:
028: import java.awt.*;
029: import java.awt.event.*;
030: import java.awt.image.*;
031: import java.awt.peer.*;
032: import java.security.AccessController;
033: import java.security.PrivilegedAction;
034: import java.lang.reflect.Constructor;
035: import java.lang.reflect.InvocationTargetException;
036: import java.lang.reflect.Modifier;
037: import java.lang.reflect.Field;
038: import java.beans.PropertyChangeListener;
039: import java.beans.PropertyChangeEvent;
040: import java.util.Set;
041: import java.awt.AWTKeyStroke;
042: import java.applet.Applet;
043: import sun.applet.AppletPanel;
044:
045: /**
046: * A generic container used for embedding Java components, usually applets.
047: * An EmbeddedFrame has two related uses:
048: *
049: * . Within a Java-based application, an EmbeddedFrame serves as a sort of
050: * firewall, preventing the contained components or applets from using
051: * getParent() to find parent components, such as menubars.
052: *
053: * . Within a C-based application, an EmbeddedFrame contains a window handle
054: * which was created by the application, which serves as the top-level
055: * Java window. EmbeddedFrames created for this purpose are passed-in a
056: * handle of an existing window created by the application. The window
057: * handle should be of the appropriate native type for a specific
058: * platform, as stored in the pData field of the ComponentPeer.
059: *
060: * @version 1.15, 04/07/00
061: * @author Thomas Ball
062: */
063: public abstract class EmbeddedFrame extends Frame implements
064: KeyEventDispatcher, PropertyChangeListener {
065:
066: private boolean isCursorAllowed = true;
067: private static Field fieldPeer;
068: private static Field currentCycleRoot;
069: private boolean supportsXEmbed = false;
070: private KeyboardFocusManager appletKFM;
071: // JDK 1.1 compatibility
072: private static final long serialVersionUID = 2967042741780317130L;
073:
074: // Use these in traverseOut method to determine directions
075: protected static final boolean FORWARD = true;
076: protected static final boolean BACKWARD = false;
077:
078: public boolean supportsXEmbed() {
079: return supportsXEmbed && SunToolkit.needsXEmbed();
080: }
081:
082: protected EmbeddedFrame(boolean supportsXEmbed) {
083: this ((long) 0, supportsXEmbed);
084: }
085:
086: protected EmbeddedFrame() {
087: this ((long) 0);
088: }
089:
090: /**
091: * @deprecated This constructor will be removed in 1.5
092: */
093: @Deprecated
094: protected EmbeddedFrame(int handle) {
095: this ((long) handle);
096: }
097:
098: protected EmbeddedFrame(long handle) {
099: this (handle, false);
100: }
101:
102: protected EmbeddedFrame(long handle, boolean supportsXEmbed) {
103: this .supportsXEmbed = supportsXEmbed;
104: registerListeners();
105: }
106:
107: /**
108: * Block introspection of a parent window by this child.
109: */
110: public Container getParent() {
111: return null;
112: }
113:
114: /**
115: * Needed to track which KeyboardFocusManager is current. We want to avoid memory
116: * leaks, so when KFM stops being current, we remove ourselves as listeners.
117: */
118: public void propertyChange(PropertyChangeEvent evt) {
119: // We don't handle any other properties. Skip it.
120: if (!evt.getPropertyName().equals("managingFocus")) {
121: return;
122: }
123:
124: // We only do it if it stops being current. Technically, we should
125: // never get an event about KFM starting being current.
126: if (evt.getNewValue() == Boolean.TRUE) {
127: return;
128: }
129:
130: // should be the same as appletKFM
131: removeTraversingOutListeners((KeyboardFocusManager) evt
132: .getSource());
133:
134: appletKFM = KeyboardFocusManager
135: .getCurrentKeyboardFocusManager();
136: if (isVisible()) {
137: addTraversingOutListeners(appletKFM);
138: }
139: }
140:
141: /**
142: * Register us as KeyEventDispatcher and property "managingFocus" listeners.
143: */
144: private void addTraversingOutListeners(KeyboardFocusManager kfm) {
145: kfm.addKeyEventDispatcher(this );
146: kfm.addPropertyChangeListener("managingFocus", this );
147: }
148:
149: /**
150: * Deregister us as KeyEventDispatcher and property "managingFocus" listeners.
151: */
152: private void removeTraversingOutListeners(KeyboardFocusManager kfm) {
153: kfm.removeKeyEventDispatcher(this );
154: kfm.removePropertyChangeListener("managingFocus", this );
155: }
156:
157: /**
158: * Because there may be many AppContexts, and we can't be sure where this
159: * EmbeddedFrame is first created or shown, we can't automatically determine
160: * the correct KeyboardFocusManager to attach to as KeyEventDispatcher.
161: * Those who want to use the functionality of traversing out of the EmbeddedFrame
162: * must call this method on the Applet's AppContext. After that, all the changes
163: * can be handled automatically, including possible replacement of
164: * KeyboardFocusManager.
165: */
166: public void registerListeners() {
167: if (appletKFM != null) {
168: removeTraversingOutListeners(appletKFM);
169: }
170: appletKFM = KeyboardFocusManager
171: .getCurrentKeyboardFocusManager();
172: if (isVisible()) {
173: addTraversingOutListeners(appletKFM);
174: }
175: }
176:
177: /**
178: * Needed to avoid memory leak: we register this EmbeddedFrame as a listener with
179: * KeyboardFocusManager of applet's AppContext. We don't want the KFM to keep
180: * reference to our EmbeddedFrame forever if the Frame is no longer in use, so we
181: * add listeners in show() and remove them in hide().
182: */
183: public void show() {
184: if (appletKFM != null) {
185: addTraversingOutListeners(appletKFM);
186: }
187: super .show();
188: }
189:
190: /**
191: * Needed to avoid memory leak: we register this EmbeddedFrame as a listener with
192: * KeyboardFocusManager of applet's AppContext. We don't want the KFM to keep
193: * reference to our EmbeddedFrame forever if the Frame is no longer in use, so we
194: * add listeners in show() and remove them in hide().
195: */
196: public void hide() {
197: if (appletKFM != null) {
198: removeTraversingOutListeners(appletKFM);
199: }
200: super .hide();
201: }
202:
203: /**
204: * Need this method to detect when the focus may have chance to leave the
205: * focus cycle root which is EmbeddedFrame. Mostly, the code here is copied
206: * from DefaultKeyboardFocusManager.processKeyEvent with some minor
207: * modifications.
208: */
209: public boolean dispatchKeyEvent(KeyEvent e) {
210:
211: // We can't guarantee that this is called on the same AppContext as EmbeddedFrame
212: // belongs to. That's why we can't use public methods to find current focus cycle
213: // root. Instead, we access KFM's private field directly.
214: if (currentCycleRoot == null) {
215: currentCycleRoot = (Field) AccessController
216: .doPrivileged(new PrivilegedAction() {
217: public Object run() {
218: try {
219: Field unaccessibleRoot = KeyboardFocusManager.class
220: .getDeclaredField("currentFocusCycleRoot");
221: if (unaccessibleRoot != null) {
222: unaccessibleRoot
223: .setAccessible(true);
224: }
225: return unaccessibleRoot;
226: } catch (NoSuchFieldException e1) {
227: assert false;
228: } catch (SecurityException e2) {
229: assert false;
230: }
231: return null;
232: }
233: });
234: }
235:
236: Container currentRoot = null;
237: if (currentCycleRoot != null) {
238: try {
239: // The field is static, so we can pass null to Field.get() as the argument.
240: currentRoot = (Container) currentCycleRoot.get(null);
241: } catch (IllegalAccessException e3) {
242: // This is impossible: currentCycleRoot would be null if setAccessible failed.
243: assert false;
244: }
245: }
246:
247: // if we are not in EmbeddedFrame's cycle, we should not try to leave.
248: if (this != currentRoot) {
249: return false;
250: }
251:
252: // KEY_TYPED events cannot be focus traversal keys
253: if (e.getID() == KeyEvent.KEY_TYPED) {
254: return false;
255: }
256:
257: if (!getFocusTraversalKeysEnabled() || e.isConsumed()) {
258: return false;
259: }
260:
261: AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e);
262: Set toTest;
263: Component currentFocused = e.getComponent();
264:
265: Component last = getFocusTraversalPolicy().getLastComponent(
266: this );
267: toTest = getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
268: if (toTest.contains(stroke)
269: && (currentFocused == last || last == null)) {
270: if (traverseOut(FORWARD)) {
271: e.consume();
272: return true;
273: }
274: }
275:
276: Component first = getFocusTraversalPolicy().getFirstComponent(
277: this );
278: toTest = getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
279: if (toTest.contains(stroke)
280: && (currentFocused == first || first == null)) {
281: if (traverseOut(BACKWARD)) {
282: e.consume();
283: return true;
284: }
285: }
286: return false;
287: }
288:
289: /**
290: * This method is called from dispatchKeyEvent in the following two cases:
291: * 1. The focus is on the first Component of this EmbeddedFrame and we are
292: * about to transfer the focus backward.
293: * 2. The focus in on the last Component of this EmbeddedFrame and we are
294: * about to transfer the focus forward.
295: * This is needed to give the opportuity for keyboard focus to leave the
296: * EmbeddedFrame. Override this method, initiate focus transfer in it and
297: * return true if you want the focus to leave EmbeddedFrame's cycle.
298: * The direction parameter specifies which of the two mentioned cases is
299: * happening. Use FORWARD and BACKWARD constants defined in EmbeddedFrame
300: * to avoid confusing boolean values.
301: *
302: * @param direction FORWARD or BACKWARD
303: * @return true, if EmbeddedFrame wants the focus to leave it,
304: * false otherwise.
305: */
306: protected boolean traverseOut(boolean direction) {
307: return false;
308: }
309:
310: /**
311: * Block modifying any frame attributes, since they aren't applicable
312: * for EmbeddedFrames.
313: */
314: public void setTitle(String title) {
315: }
316:
317: public void setIconImage(Image image) {
318: }
319:
320: public void setIconImages(java.util.List<? extends Image> icons) {
321: }
322:
323: public void setMenuBar(MenuBar mb) {
324: }
325:
326: public void setResizable(boolean resizable) {
327: }
328:
329: public void remove(MenuComponent m) {
330: }
331:
332: public boolean isResizable() {
333: return true;
334: }
335:
336: public void addNotify() {
337: synchronized (getTreeLock()) {
338: if (getPeer() == null) {
339: setPeer(new NullEmbeddedFramePeer());
340: }
341: super .addNotify();
342: }
343: }
344:
345: // These three functions consitute RFE 4100710. Do not remove.
346: public void setCursorAllowed(boolean isCursorAllowed) {
347: this .isCursorAllowed = isCursorAllowed;
348: getPeer().updateCursorImmediately();
349: }
350:
351: public boolean isCursorAllowed() {
352: return isCursorAllowed;
353: }
354:
355: public Cursor getCursor() {
356: return (isCursorAllowed) ? super .getCursor() : Cursor
357: .getPredefinedCursor(Cursor.DEFAULT_CURSOR);
358: }
359:
360: protected void setPeer(final ComponentPeer p) {
361: if (fieldPeer == null) {
362: fieldPeer = (Field) AccessController
363: .doPrivileged(new PrivilegedAction() {
364: public Object run() {
365: try {
366: Field lnkPeer = Component.class
367: .getDeclaredField("peer");
368: if (lnkPeer != null) {
369: lnkPeer.setAccessible(true);
370: }
371: return lnkPeer;
372: } catch (NoSuchFieldException e) {
373: assert false;
374: } catch (SecurityException e) {
375: assert false;
376: }
377: return null;
378: }//run
379: });
380: }
381: try {
382: if (fieldPeer != null) {
383: fieldPeer.set(EmbeddedFrame.this , p);
384: }
385: } catch (IllegalAccessException e) {
386: assert false;
387: }
388: }; //setPeer method ends
389:
390: /**
391: * Synthesize native message to activate or deactivate EmbeddedFrame window
392: * depending on the value of parameter <code>b</code>.
393: * Peers should override this method if they are to implement
394: * this functionality.
395: * @param doActivate if <code>true</code>, activates the window;
396: * otherwise, deactivates the window
397: */
398: public void synthesizeWindowActivation(boolean doActivate) {
399: }
400:
401: /**
402: * Moves this embedded frame to a new location. The top-left corner of
403: * the new location is specified by the <code>x</code> and <code>y</code>
404: * parameters relative to the native parent component.
405: * <p>
406: * setLocation() and setBounds() for EmbeddedFrame really don't move it
407: * within the native parent. These methods always put embedded frame to
408: * (0, 0) for backward compatibility. To allow moving embedded frame
409: * setLocationPrivate() and setBoundsPrivate() were introduced, and they
410: * work just the same way as setLocation() and setBounds() for usual,
411: * non-embedded components.
412: * </p>
413: * <p>
414: * Using usual get/setLocation() and get/setBounds() together with new
415: * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended.
416: * For example, calling getBoundsPrivate() after setLocation() works fine,
417: * but getBounds() after setBoundsPrivate() may return unpredictable value.
418: * </p>
419: * @param x the new <i>x</i>-coordinate relative to the parent component
420: * @param y the new <i>y</i>-coordinate relative to the parent component
421: * @see java.awt.Component#setLocation
422: * @see #getLocationPrivate
423: * @see #setBoundsPrivate
424: * @see #getBoundsPrivate
425: * @since 1.5
426: */
427: protected void setLocationPrivate(int x, int y) {
428: Dimension size = getSize();
429: setBoundsPrivate(x, y, size.width, size.height);
430: }
431:
432: /**
433: * Gets the location of this embedded frame as a point specifying the
434: * top-left corner relative to parent component.
435: * <p>
436: * setLocation() and setBounds() for EmbeddedFrame really don't move it
437: * within the native parent. These methods always put embedded frame to
438: * (0, 0) for backward compatibility. To allow getting location and size
439: * of embedded frame getLocationPrivate() and getBoundsPrivate() were
440: * introduced, and they work just the same way as getLocation() and getBounds()
441: * for ususal, non-embedded components.
442: * </p>
443: * <p>
444: * Using usual get/setLocation() and get/setBounds() together with new
445: * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended.
446: * For example, calling getBoundsPrivate() after setLocation() works fine,
447: * but getBounds() after setBoundsPrivate() may return unpredictable value.
448: * </p>
449: * @return a point indicating this embedded frame's top-left corner
450: * @see java.awt.Component#getLocation
451: * @see #setLocationPrivate
452: * @see #setBoundsPrivate
453: * @see #getBoundsPrivate
454: * @since 1.6
455: */
456: protected Point getLocationPrivate() {
457: Rectangle bounds = getBoundsPrivate();
458: return new Point(bounds.x, bounds.y);
459: }
460:
461: /**
462: * Moves and resizes this embedded frame. The new location of the top-left
463: * corner is specified by <code>x</code> and <code>y</code> parameters
464: * relative to the native parent component. The new size is specified by
465: * <code>width</code> and <code>height</code>.
466: * <p>
467: * setLocation() and setBounds() for EmbeddedFrame really don't move it
468: * within the native parent. These methods always put embedded frame to
469: * (0, 0) for backward compatibility. To allow moving embedded frames
470: * setLocationPrivate() and setBoundsPrivate() were introduced, and they
471: * work just the same way as setLocation() and setBounds() for usual,
472: * non-embedded components.
473: * </p>
474: * <p>
475: * Using usual get/setLocation() and get/setBounds() together with new
476: * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended.
477: * For example, calling getBoundsPrivate() after setLocation() works fine,
478: * but getBounds() after setBoundsPrivate() may return unpredictable value.
479: * </p>
480: * @param x the new <i>x</i>-coordinate relative to the parent component
481: * @param y the new <i>y</i>-coordinate relative to the parent component
482: * @param width the new <code>width</code> of this embedded frame
483: * @param height the new <code>height</code> of this embedded frame
484: * @see java.awt.Component#setBounds
485: * @see #setLocationPrivate
486: * @see #getLocationPrivate
487: * @see #getBoundsPrivate
488: * @since 1.5
489: */
490: protected void setBoundsPrivate(int x, int y, int width, int height) {
491: final FramePeer peer = (FramePeer) getPeer();
492: if (peer != null) {
493: peer.setBoundsPrivate(x, y, width, height);
494: }
495: }
496:
497: /**
498: * Gets the bounds of this embedded frame as a rectangle specifying the
499: * width, height and location relative to the native parent component.
500: * <p>
501: * setLocation() and setBounds() for EmbeddedFrame really don't move it
502: * within the native parent. These methods always put embedded frame to
503: * (0, 0) for backward compatibility. To allow getting location and size
504: * of embedded frames getLocationPrivate() and getBoundsPrivate() were
505: * introduced, and they work just the same way as getLocation() and getBounds()
506: * for ususal, non-embedded components.
507: * </p>
508: * <p>
509: * Using usual get/setLocation() and get/setBounds() together with new
510: * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended.
511: * For example, calling getBoundsPrivate() after setLocation() works fine,
512: * but getBounds() after setBoundsPrivate() may return unpredictable value.
513: * </p>
514: * @return a rectangle indicating this embedded frame's bounds
515: * @see java.awt.Component#getBounds
516: * @see #setLocationPrivate
517: * @see #getLocationPrivate
518: * @see #setBoundsPrivate
519: * @since 1.6
520: */
521: protected Rectangle getBoundsPrivate() {
522: final FramePeer peer = (FramePeer) getPeer();
523: if (peer != null) {
524: return peer.getBoundsPrivate();
525: } else {
526: return getBounds();
527: }
528: }
529:
530: public void toFront() {
531: }
532:
533: public void toBack() {
534: }
535:
536: public abstract void registerAccelerator(AWTKeyStroke stroke);
537:
538: public abstract void unregisterAccelerator(AWTKeyStroke stroke);
539:
540: /**
541: * Checks if the component is in an EmbeddedFrame. If so,
542: * returns the applet found in the hierarchy or null if
543: * not found.
544: * @return the parent applet or {@ null}
545: * @since 1.6
546: */
547: public static Applet getAppletIfAncestorOf(Component comp) {
548: Container parent = comp.getParent();
549: Applet applet = null;
550: while (parent != null && !(parent instanceof EmbeddedFrame)) {
551: if (parent instanceof Applet) {
552: applet = (Applet) parent;
553: }
554: parent = parent.getParent();
555: }
556: return parent == null ? null : applet;
557: }
558:
559: /**
560: * This method should be overriden in subclasses. It is
561: * called when window this frame is within should be blocked
562: * by some modal dialog.
563: */
564: public void notifyModalBlocked(Dialog blocker, boolean blocked) {
565: }
566:
567: private static class NullEmbeddedFramePeer extends
568: NullComponentPeer implements FramePeer {
569: public void setTitle(String title) {
570: }
571:
572: public void setIconImage(Image im) {
573: }
574:
575: public void updateIconImages() {
576: }
577:
578: public void setMenuBar(MenuBar mb) {
579: }
580:
581: public void setResizable(boolean resizeable) {
582: }
583:
584: public void setState(int state) {
585: }
586:
587: public int getState() {
588: return Frame.NORMAL;
589: }
590:
591: public void setMaximizedBounds(Rectangle b) {
592: }
593:
594: public void toFront() {
595: }
596:
597: public void toBack() {
598: }
599:
600: public void updateFocusableWindowState() {
601: }
602:
603: public void updateAlwaysOnTop() {
604: }
605:
606: public void setAlwaysOnTop(boolean alwaysOnTop) {
607: }
608:
609: public Component getGlobalHeavyweightFocusOwner() {
610: return null;
611: }
612:
613: public void setBoundsPrivate(int x, int y, int width, int height) {
614: setBounds(x, y, width, height, SET_BOUNDS);
615: }
616:
617: public Rectangle getBoundsPrivate() {
618: return getBounds();
619: }
620:
621: public void setModalBlocked(Dialog blocker, boolean blocked) {
622: }
623:
624: /**
625: * @see java.awt.peer.ContainerPeer#restack
626: */
627: public void restack() {
628: throw new UnsupportedOperationException();
629: }
630:
631: /**
632: * @see java.awt.peer.ContainerPeer#isRestackSupported
633: */
634: public boolean isRestackSupported() {
635: return false;
636: }
637:
638: public boolean requestWindowFocus() {
639: return false;
640: }
641:
642: public void updateMinimumSize() {
643: }
644: }
645: } // class EmbeddedFrame
|