Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/awt/Container.java
38829 views
1
/*
2
* Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
package java.awt;
26
27
import java.awt.dnd.DropTarget;
28
29
import java.awt.event.*;
30
31
import java.awt.peer.ContainerPeer;
32
import java.awt.peer.ComponentPeer;
33
import java.awt.peer.LightweightPeer;
34
35
import java.beans.PropertyChangeListener;
36
37
import java.io.IOException;
38
import java.io.InvalidObjectException;
39
import java.io.ObjectInputStream;
40
import java.io.ObjectOutputStream;
41
import java.io.ObjectStreamField;
42
import java.io.PrintStream;
43
import java.io.PrintWriter;
44
45
import java.lang.ref.WeakReference;
46
import java.security.AccessController;
47
48
import java.util.ArrayList;
49
import java.util.EventListener;
50
import java.util.HashSet;
51
import java.util.Set;
52
53
import javax.accessibility.*;
54
55
import sun.util.logging.PlatformLogger;
56
57
import sun.awt.AppContext;
58
import sun.awt.AWTAccessor;
59
import sun.awt.AWTAccessor.MouseEventAccessor;
60
import sun.awt.CausedFocusEvent;
61
import sun.awt.PeerEvent;
62
import sun.awt.SunToolkit;
63
64
import sun.awt.dnd.SunDropTargetEvent;
65
66
import sun.java2d.pipe.Region;
67
68
import sun.security.action.GetBooleanAction;
69
70
/**
71
* A generic Abstract Window Toolkit(AWT) container object is a component
72
* that can contain other AWT components.
73
* <p>
74
* Components added to a container are tracked in a list. The order
75
* of the list will define the components' front-to-back stacking order
76
* within the container. If no index is specified when adding a
77
* component to a container, it will be added to the end of the list
78
* (and hence to the bottom of the stacking order).
79
* <p>
80
* <b>Note</b>: For details on the focus subsystem, see
81
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
82
* How to Use the Focus Subsystem</a>,
83
* a section in <em>The Java Tutorial</em>, and the
84
* <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
85
* for more information.
86
*
87
* @author Arthur van Hoff
88
* @author Sami Shaio
89
* @see #add(java.awt.Component, int)
90
* @see #getComponent(int)
91
* @see LayoutManager
92
* @since JDK1.0
93
*/
94
public class Container extends Component {
95
96
private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.Container");
97
private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.Container");
98
99
private static final Component[] EMPTY_ARRAY = new Component[0];
100
101
/**
102
* The components in this container.
103
* @see #add
104
* @see #getComponents
105
*/
106
private java.util.List<Component> component = new ArrayList<>();
107
108
/**
109
* Layout manager for this container.
110
* @see #doLayout
111
* @see #setLayout
112
* @see #getLayout
113
*/
114
LayoutManager layoutMgr;
115
116
/**
117
* Event router for lightweight components. If this container
118
* is native, this dispatcher takes care of forwarding and
119
* retargeting the events to lightweight components contained
120
* (if any).
121
*/
122
private LightweightDispatcher dispatcher;
123
124
/**
125
* The focus traversal policy that will manage keyboard traversal of this
126
* Container's children, if this Container is a focus cycle root. If the
127
* value is null, this Container inherits its policy from its focus-cycle-
128
* root ancestor. If all such ancestors of this Container have null
129
* policies, then the current KeyboardFocusManager's default policy is
130
* used. If the value is non-null, this policy will be inherited by all
131
* focus-cycle-root children that have no keyboard-traversal policy of
132
* their own (as will, recursively, their focus-cycle-root children).
133
* <p>
134
* If this Container is not a focus cycle root, the value will be
135
* remembered, but will not be used or inherited by this or any other
136
* Containers until this Container is made a focus cycle root.
137
*
138
* @see #setFocusTraversalPolicy
139
* @see #getFocusTraversalPolicy
140
* @since 1.4
141
*/
142
private transient FocusTraversalPolicy focusTraversalPolicy;
143
144
/**
145
* Indicates whether this Component is the root of a focus traversal cycle.
146
* Once focus enters a traversal cycle, typically it cannot leave it via
147
* focus traversal unless one of the up- or down-cycle keys is pressed.
148
* Normal traversal is limited to this Container, and all of this
149
* Container's descendants that are not descendants of inferior focus cycle
150
* roots.
151
*
152
* @see #setFocusCycleRoot
153
* @see #isFocusCycleRoot
154
* @since 1.4
155
*/
156
private boolean focusCycleRoot = false;
157
158
159
/**
160
* Stores the value of focusTraversalPolicyProvider property.
161
* @since 1.5
162
* @see #setFocusTraversalPolicyProvider
163
*/
164
private boolean focusTraversalPolicyProvider;
165
166
// keeps track of the threads that are printing this component
167
private transient Set<Thread> printingThreads;
168
// True if there is at least one thread that's printing this component
169
private transient boolean printing = false;
170
171
transient ContainerListener containerListener;
172
173
/* HierarchyListener and HierarchyBoundsListener support */
174
transient int listeningChildren;
175
transient int listeningBoundsChildren;
176
transient int descendantsCount;
177
178
/* Non-opaque window support -- see Window.setLayersOpaque */
179
transient Color preserveBackgroundColor = null;
180
181
/**
182
* JDK 1.1 serialVersionUID
183
*/
184
private static final long serialVersionUID = 4613797578919906343L;
185
186
/**
187
* A constant which toggles one of the controllable behaviors
188
* of <code>getMouseEventTarget</code>. It is used to specify whether
189
* the method can return the Container on which it is originally called
190
* in case if none of its children are the current mouse event targets.
191
*
192
* @see #getMouseEventTarget(int, int, boolean)
193
*/
194
static final boolean INCLUDE_SELF = true;
195
196
/**
197
* A constant which toggles one of the controllable behaviors
198
* of <code>getMouseEventTarget</code>. It is used to specify whether
199
* the method should search only lightweight components.
200
*
201
* @see #getMouseEventTarget(int, int, boolean)
202
*/
203
static final boolean SEARCH_HEAVYWEIGHTS = true;
204
205
/*
206
* Number of HW or LW components in this container (including
207
* all descendant containers).
208
*/
209
private transient int numOfHWComponents = 0;
210
private transient int numOfLWComponents = 0;
211
212
private static final PlatformLogger mixingLog = PlatformLogger.getLogger("java.awt.mixing.Container");
213
214
/**
215
* @serialField ncomponents int
216
* The number of components in this container.
217
* This value can be null.
218
* @serialField component Component[]
219
* The components in this container.
220
* @serialField layoutMgr LayoutManager
221
* Layout manager for this container.
222
* @serialField dispatcher LightweightDispatcher
223
* Event router for lightweight components. If this container
224
* is native, this dispatcher takes care of forwarding and
225
* retargeting the events to lightweight components contained
226
* (if any).
227
* @serialField maxSize Dimension
228
* Maximum size of this Container.
229
* @serialField focusCycleRoot boolean
230
* Indicates whether this Component is the root of a focus traversal cycle.
231
* Once focus enters a traversal cycle, typically it cannot leave it via
232
* focus traversal unless one of the up- or down-cycle keys is pressed.
233
* Normal traversal is limited to this Container, and all of this
234
* Container's descendants that are not descendants of inferior focus cycle
235
* roots.
236
* @serialField containerSerializedDataVersion int
237
* Container Serial Data Version.
238
* @serialField focusTraversalPolicyProvider boolean
239
* Stores the value of focusTraversalPolicyProvider property.
240
*/
241
private static final ObjectStreamField[] serialPersistentFields = {
242
new ObjectStreamField("ncomponents", Integer.TYPE),
243
new ObjectStreamField("component", Component[].class),
244
new ObjectStreamField("layoutMgr", LayoutManager.class),
245
new ObjectStreamField("dispatcher", LightweightDispatcher.class),
246
new ObjectStreamField("maxSize", Dimension.class),
247
new ObjectStreamField("focusCycleRoot", Boolean.TYPE),
248
new ObjectStreamField("containerSerializedDataVersion", Integer.TYPE),
249
new ObjectStreamField("focusTraversalPolicyProvider", Boolean.TYPE),
250
};
251
252
static {
253
/* ensure that the necessary native libraries are loaded */
254
Toolkit.loadLibraries();
255
if (!GraphicsEnvironment.isHeadless()) {
256
initIDs();
257
}
258
259
AWTAccessor.setContainerAccessor(new AWTAccessor.ContainerAccessor() {
260
@Override
261
public void validateUnconditionally(Container cont) {
262
cont.validateUnconditionally();
263
}
264
265
@Override
266
public Component findComponentAt(Container cont, int x, int y,
267
boolean ignoreEnabled) {
268
return cont.findComponentAt(x, y, ignoreEnabled);
269
}
270
});
271
}
272
273
/**
274
* Initialize JNI field and method IDs for fields that may be
275
called from C.
276
*/
277
private static native void initIDs();
278
279
/**
280
* Constructs a new Container. Containers can be extended directly,
281
* but are lightweight in this case and must be contained by a parent
282
* somewhere higher up in the component tree that is native.
283
* (such as Frame for example).
284
*/
285
public Container() {
286
}
287
@SuppressWarnings({"unchecked","rawtypes"})
288
void initializeFocusTraversalKeys() {
289
focusTraversalKeys = new Set[4];
290
}
291
292
/**
293
* Gets the number of components in this panel.
294
* <p>
295
* Note: This method should be called under AWT tree lock.
296
*
297
* @return the number of components in this panel.
298
* @see #getComponent
299
* @since JDK1.1
300
* @see Component#getTreeLock()
301
*/
302
public int getComponentCount() {
303
return countComponents();
304
}
305
306
/**
307
* @deprecated As of JDK version 1.1,
308
* replaced by getComponentCount().
309
*/
310
@Deprecated
311
public int countComponents() {
312
// This method is not synchronized under AWT tree lock.
313
// Instead, the calling code is responsible for the
314
// synchronization. See 6784816 for details.
315
return component.size();
316
}
317
318
/**
319
* Gets the nth component in this container.
320
* <p>
321
* Note: This method should be called under AWT tree lock.
322
*
323
* @param n the index of the component to get.
324
* @return the n<sup>th</sup> component in this container.
325
* @exception ArrayIndexOutOfBoundsException
326
* if the n<sup>th</sup> value does not exist.
327
* @see Component#getTreeLock()
328
*/
329
public Component getComponent(int n) {
330
// This method is not synchronized under AWT tree lock.
331
// Instead, the calling code is responsible for the
332
// synchronization. See 6784816 for details.
333
try {
334
return component.get(n);
335
} catch (IndexOutOfBoundsException z) {
336
throw new ArrayIndexOutOfBoundsException("No such child: " + n);
337
}
338
}
339
340
/**
341
* Gets all the components in this container.
342
* <p>
343
* Note: This method should be called under AWT tree lock.
344
*
345
* @return an array of all the components in this container.
346
* @see Component#getTreeLock()
347
*/
348
public Component[] getComponents() {
349
// This method is not synchronized under AWT tree lock.
350
// Instead, the calling code is responsible for the
351
// synchronization. See 6784816 for details.
352
return getComponents_NoClientCode();
353
}
354
355
// NOTE: This method may be called by privileged threads.
356
// This functionality is implemented in a package-private method
357
// to insure that it cannot be overridden by client subclasses.
358
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
359
final Component[] getComponents_NoClientCode() {
360
return component.toArray(EMPTY_ARRAY);
361
}
362
363
/*
364
* Wrapper for getComponents() method with a proper synchronization.
365
*/
366
Component[] getComponentsSync() {
367
synchronized (getTreeLock()) {
368
return getComponents();
369
}
370
}
371
372
/**
373
* Determines the insets of this container, which indicate the size
374
* of the container's border.
375
* <p>
376
* A <code>Frame</code> object, for example, has a top inset that
377
* corresponds to the height of the frame's title bar.
378
* @return the insets of this container.
379
* @see Insets
380
* @see LayoutManager
381
* @since JDK1.1
382
*/
383
public Insets getInsets() {
384
return insets();
385
}
386
387
/**
388
* @deprecated As of JDK version 1.1,
389
* replaced by <code>getInsets()</code>.
390
*/
391
@Deprecated
392
public Insets insets() {
393
ComponentPeer peer = this.peer;
394
if (peer instanceof ContainerPeer) {
395
ContainerPeer cpeer = (ContainerPeer)peer;
396
return (Insets)cpeer.getInsets().clone();
397
}
398
return new Insets(0, 0, 0, 0);
399
}
400
401
/**
402
* Appends the specified component to the end of this container.
403
* This is a convenience method for {@link #addImpl}.
404
* <p>
405
* This method changes layout-related information, and therefore,
406
* invalidates the component hierarchy. If the container has already been
407
* displayed, the hierarchy must be validated thereafter in order to
408
* display the added component.
409
*
410
* @param comp the component to be added
411
* @exception NullPointerException if {@code comp} is {@code null}
412
* @see #addImpl
413
* @see #invalidate
414
* @see #validate
415
* @see javax.swing.JComponent#revalidate()
416
* @return the component argument
417
*/
418
public Component add(Component comp) {
419
addImpl(comp, null, -1);
420
return comp;
421
}
422
423
/**
424
* Adds the specified component to this container.
425
* This is a convenience method for {@link #addImpl}.
426
* <p>
427
* This method is obsolete as of 1.1. Please use the
428
* method <code>add(Component, Object)</code> instead.
429
* <p>
430
* This method changes layout-related information, and therefore,
431
* invalidates the component hierarchy. If the container has already been
432
* displayed, the hierarchy must be validated thereafter in order to
433
* display the added component.
434
*
435
* @exception NullPointerException if {@code comp} is {@code null}
436
* @see #add(Component, Object)
437
* @see #invalidate
438
*/
439
public Component add(String name, Component comp) {
440
addImpl(comp, name, -1);
441
return comp;
442
}
443
444
/**
445
* Adds the specified component to this container at the given
446
* position.
447
* This is a convenience method for {@link #addImpl}.
448
* <p>
449
* This method changes layout-related information, and therefore,
450
* invalidates the component hierarchy. If the container has already been
451
* displayed, the hierarchy must be validated thereafter in order to
452
* display the added component.
453
*
454
*
455
* @param comp the component to be added
456
* @param index the position at which to insert the component,
457
* or <code>-1</code> to append the component to the end
458
* @exception NullPointerException if {@code comp} is {@code null}
459
* @exception IllegalArgumentException if {@code index} is invalid (see
460
* {@link #addImpl} for details)
461
* @return the component <code>comp</code>
462
* @see #addImpl
463
* @see #remove
464
* @see #invalidate
465
* @see #validate
466
* @see javax.swing.JComponent#revalidate()
467
*/
468
public Component add(Component comp, int index) {
469
addImpl(comp, null, index);
470
return comp;
471
}
472
473
/**
474
* Checks that the component
475
* isn't supposed to be added into itself.
476
*/
477
private void checkAddToSelf(Component comp){
478
if (comp instanceof Container) {
479
for (Container cn = this; cn != null; cn=cn.parent) {
480
if (cn == comp) {
481
throw new IllegalArgumentException("adding container's parent to itself");
482
}
483
}
484
}
485
}
486
487
/**
488
* Checks that the component is not a Window instance.
489
*/
490
private void checkNotAWindow(Component comp){
491
if (comp instanceof Window) {
492
throw new IllegalArgumentException("adding a window to a container");
493
}
494
}
495
496
/**
497
* Checks that the component comp can be added to this container
498
* Checks : index in bounds of container's size,
499
* comp is not one of this container's parents,
500
* and comp is not a window.
501
* Comp and container must be on the same GraphicsDevice.
502
* if comp is container, all sub-components must be on
503
* same GraphicsDevice.
504
*
505
* @since 1.5
506
*/
507
private void checkAdding(Component comp, int index) {
508
checkTreeLock();
509
510
GraphicsConfiguration thisGC = getGraphicsConfiguration();
511
512
if (index > component.size() || index < 0) {
513
throw new IllegalArgumentException("illegal component position");
514
}
515
if (comp.parent == this) {
516
if (index == component.size()) {
517
throw new IllegalArgumentException("illegal component position " +
518
index + " should be less then " + component.size());
519
}
520
}
521
checkAddToSelf(comp);
522
checkNotAWindow(comp);
523
524
Window thisTopLevel = getContainingWindow();
525
Window compTopLevel = comp.getContainingWindow();
526
if (thisTopLevel != compTopLevel) {
527
throw new IllegalArgumentException("component and container should be in the same top-level window");
528
}
529
if (thisGC != null) {
530
comp.checkGD(thisGC.getDevice().getIDstring());
531
}
532
}
533
534
/**
535
* Removes component comp from this container without making unneccessary changes
536
* and generating unneccessary events. This function intended to perform optimized
537
* remove, for example, if newParent and current parent are the same it just changes
538
* index without calling removeNotify.
539
* Note: Should be called while holding treeLock
540
* Returns whether removeNotify was invoked
541
* @since: 1.5
542
*/
543
private boolean removeDelicately(Component comp, Container newParent, int newIndex) {
544
checkTreeLock();
545
546
int index = getComponentZOrder(comp);
547
boolean needRemoveNotify = isRemoveNotifyNeeded(comp, this, newParent);
548
if (needRemoveNotify) {
549
comp.removeNotify();
550
}
551
if (newParent != this) {
552
if (layoutMgr != null) {
553
layoutMgr.removeLayoutComponent(comp);
554
}
555
adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
556
-comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
557
adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
558
-comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
559
adjustDescendants(-(comp.countHierarchyMembers()));
560
561
comp.parent = null;
562
if (needRemoveNotify) {
563
comp.setGraphicsConfiguration(null);
564
}
565
component.remove(index);
566
567
invalidateIfValid();
568
} else {
569
// We should remove component and then
570
// add it by the newIndex without newIndex decrement if even we shift components to the left
571
// after remove. Consult the rules below:
572
// 2->4: 012345 -> 013425, 2->5: 012345 -> 013452
573
// 4->2: 012345 -> 014235
574
component.remove(index);
575
component.add(newIndex, comp);
576
}
577
if (comp.parent == null) { // was actually removed
578
if (containerListener != null ||
579
(eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
580
Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
581
ContainerEvent e = new ContainerEvent(this,
582
ContainerEvent.COMPONENT_REMOVED,
583
comp);
584
dispatchEvent(e);
585
586
}
587
comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
588
this, HierarchyEvent.PARENT_CHANGED,
589
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
590
if (peer != null && layoutMgr == null && isVisible()) {
591
updateCursorImmediately();
592
}
593
}
594
return needRemoveNotify;
595
}
596
597
/**
598
* Checks whether this container can contain component which is focus owner.
599
* Verifies that container is enable and showing, and if it is focus cycle root
600
* its FTP allows component to be focus owner
601
* @since 1.5
602
*/
603
boolean canContainFocusOwner(Component focusOwnerCandidate) {
604
if (!(isEnabled() && isDisplayable()
605
&& isVisible() && isFocusable()))
606
{
607
return false;
608
}
609
if (isFocusCycleRoot()) {
610
FocusTraversalPolicy policy = getFocusTraversalPolicy();
611
if (policy instanceof DefaultFocusTraversalPolicy) {
612
if (!((DefaultFocusTraversalPolicy)policy).accept(focusOwnerCandidate)) {
613
return false;
614
}
615
}
616
}
617
synchronized(getTreeLock()) {
618
if (parent != null) {
619
return parent.canContainFocusOwner(focusOwnerCandidate);
620
}
621
}
622
return true;
623
}
624
625
/**
626
* Checks whether or not this container has heavyweight children.
627
* Note: Should be called while holding tree lock
628
* @return true if there is at least one heavyweight children in a container, false otherwise
629
* @since 1.5
630
*/
631
final boolean hasHeavyweightDescendants() {
632
checkTreeLock();
633
return numOfHWComponents > 0;
634
}
635
636
/**
637
* Checks whether or not this container has lightweight children.
638
* Note: Should be called while holding tree lock
639
* @return true if there is at least one lightweight children in a container, false otherwise
640
* @since 1.7
641
*/
642
final boolean hasLightweightDescendants() {
643
checkTreeLock();
644
return numOfLWComponents > 0;
645
}
646
647
/**
648
* Returns closest heavyweight component to this container. If this container is heavyweight
649
* returns this.
650
* @since 1.5
651
*/
652
Container getHeavyweightContainer() {
653
checkTreeLock();
654
if (peer != null && !(peer instanceof LightweightPeer)) {
655
return this;
656
} else {
657
return getNativeContainer();
658
}
659
}
660
661
/**
662
* Detects whether or not remove from current parent and adding to new parent requires call of
663
* removeNotify on the component. Since removeNotify destroys native window this might (not)
664
* be required. For example, if new container and old containers are the same we don't need to
665
* destroy native window.
666
* @since: 1.5
667
*/
668
private static boolean isRemoveNotifyNeeded(Component comp, Container oldContainer, Container newContainer) {
669
if (oldContainer == null) { // Component didn't have parent - no removeNotify
670
return false;
671
}
672
if (comp.peer == null) { // Component didn't have peer - no removeNotify
673
return false;
674
}
675
if (newContainer.peer == null) {
676
// Component has peer but new Container doesn't - call removeNotify
677
return true;
678
}
679
680
// If component is lightweight non-Container or lightweight Container with all but heavyweight
681
// children there is no need to call remove notify
682
if (comp.isLightweight()) {
683
boolean isContainer = comp instanceof Container;
684
685
if (!isContainer || (isContainer && !((Container)comp).hasHeavyweightDescendants())) {
686
return false;
687
}
688
}
689
690
// If this point is reached, then the comp is either a HW or a LW container with HW descendants.
691
692
// All three components have peers, check for peer change
693
Container newNativeContainer = oldContainer.getHeavyweightContainer();
694
Container oldNativeContainer = newContainer.getHeavyweightContainer();
695
if (newNativeContainer != oldNativeContainer) {
696
// Native containers change - check whether or not current platform supports
697
// changing of widget hierarchy on native level without recreation.
698
// The current implementation forbids reparenting of LW containers with HW descendants
699
// into another native container w/o destroying the peers. Actually such an operation
700
// is quite rare. If we ever need to save the peers, we'll have to slightly change the
701
// addDelicately() method in order to handle such LW containers recursively, reparenting
702
// each HW descendant independently.
703
return !comp.peer.isReparentSupported();
704
} else {
705
return false;
706
}
707
}
708
709
/**
710
* Moves the specified component to the specified z-order index in
711
* the container. The z-order determines the order that components
712
* are painted; the component with the highest z-order paints first
713
* and the component with the lowest z-order paints last.
714
* Where components overlap, the component with the lower
715
* z-order paints over the component with the higher z-order.
716
* <p>
717
* If the component is a child of some other container, it is
718
* removed from that container before being added to this container.
719
* The important difference between this method and
720
* <code>java.awt.Container.add(Component, int)</code> is that this method
721
* doesn't call <code>removeNotify</code> on the component while
722
* removing it from its previous container unless necessary and when
723
* allowed by the underlying native windowing system. This way, if the
724
* component has the keyboard focus, it maintains the focus when
725
* moved to the new position.
726
* <p>
727
* This property is guaranteed to apply only to lightweight
728
* non-<code>Container</code> components.
729
* <p>
730
* This method changes layout-related information, and therefore,
731
* invalidates the component hierarchy.
732
* <p>
733
* <b>Note</b>: Not all platforms support changing the z-order of
734
* heavyweight components from one container into another without
735
* the call to <code>removeNotify</code>. There is no way to detect
736
* whether a platform supports this, so developers shouldn't make
737
* any assumptions.
738
*
739
* @param comp the component to be moved
740
* @param index the position in the container's list to
741
* insert the component, where <code>getComponentCount()</code>
742
* appends to the end
743
* @exception NullPointerException if <code>comp</code> is
744
* <code>null</code>
745
* @exception IllegalArgumentException if <code>comp</code> is one of the
746
* container's parents
747
* @exception IllegalArgumentException if <code>index</code> is not in
748
* the range <code>[0, getComponentCount()]</code> for moving
749
* between containers, or not in the range
750
* <code>[0, getComponentCount()-1]</code> for moving inside
751
* a container
752
* @exception IllegalArgumentException if adding a container to itself
753
* @exception IllegalArgumentException if adding a <code>Window</code>
754
* to a container
755
* @see #getComponentZOrder(java.awt.Component)
756
* @see #invalidate
757
* @since 1.5
758
*/
759
public void setComponentZOrder(Component comp, int index) {
760
synchronized (getTreeLock()) {
761
// Store parent because remove will clear it
762
Container curParent = comp.parent;
763
int oldZindex = getComponentZOrder(comp);
764
765
if (curParent == this && index == oldZindex) {
766
return;
767
}
768
checkAdding(comp, index);
769
770
boolean peerRecreated = (curParent != null) ?
771
curParent.removeDelicately(comp, this, index) : false;
772
773
addDelicately(comp, curParent, index);
774
775
// If the oldZindex == -1, the component gets inserted,
776
// rather than it changes its z-order.
777
if (!peerRecreated && oldZindex != -1) {
778
// The new 'index' cannot be == -1.
779
// It gets checked at the checkAdding() method.
780
// Therefore both oldZIndex and index denote
781
// some existing positions at this point and
782
// this is actually a Z-order changing.
783
comp.mixOnZOrderChanging(oldZindex, index);
784
}
785
}
786
}
787
788
/**
789
* Traverses the tree of components and reparents children heavyweight component
790
* to new heavyweight parent.
791
* @since 1.5
792
*/
793
private void reparentTraverse(ContainerPeer parentPeer, Container child) {
794
checkTreeLock();
795
796
for (int i = 0; i < child.getComponentCount(); i++) {
797
Component comp = child.getComponent(i);
798
if (comp.isLightweight()) {
799
// If components is lightweight check if it is container
800
// If it is container it might contain heavyweight children we need to reparent
801
if (comp instanceof Container) {
802
reparentTraverse(parentPeer, (Container)comp);
803
}
804
} else {
805
// Q: Need to update NativeInLightFixer?
806
comp.getPeer().reparent(parentPeer);
807
}
808
}
809
}
810
811
/**
812
* Reparents child component peer to this container peer.
813
* Container must be heavyweight.
814
* @since 1.5
815
*/
816
private void reparentChild(Component comp) {
817
checkTreeLock();
818
if (comp == null) {
819
return;
820
}
821
if (comp.isLightweight()) {
822
// If component is lightweight container we need to reparent all its explicit heavyweight children
823
if (comp instanceof Container) {
824
// Traverse component's tree till depth-first until encountering heavyweight component
825
reparentTraverse((ContainerPeer)getPeer(), (Container)comp);
826
}
827
} else {
828
comp.getPeer().reparent((ContainerPeer)getPeer());
829
}
830
}
831
832
/**
833
* Adds component to this container. Tries to minimize side effects of this adding -
834
* doesn't call remove notify if it is not required.
835
* @since 1.5
836
*/
837
private void addDelicately(Component comp, Container curParent, int index) {
838
checkTreeLock();
839
840
// Check if moving between containers
841
if (curParent != this) {
842
//index == -1 means add to the end.
843
if (index == -1) {
844
component.add(comp);
845
} else {
846
component.add(index, comp);
847
}
848
comp.parent = this;
849
comp.setGraphicsConfiguration(getGraphicsConfiguration());
850
851
adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
852
comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
853
adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
854
comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
855
adjustDescendants(comp.countHierarchyMembers());
856
} else {
857
if (index < component.size()) {
858
component.set(index, comp);
859
}
860
}
861
862
invalidateIfValid();
863
if (peer != null) {
864
if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one
865
comp.addNotify();
866
} else { // Both container and child have peers, it means child peer should be reparented.
867
// In both cases we need to reparent native widgets.
868
Container newNativeContainer = getHeavyweightContainer();
869
Container oldNativeContainer = curParent.getHeavyweightContainer();
870
if (oldNativeContainer != newNativeContainer) {
871
// Native container changed - need to reparent native widgets
872
newNativeContainer.reparentChild(comp);
873
}
874
comp.updateZOrder();
875
876
if (!comp.isLightweight() && isLightweight()) {
877
// If component is heavyweight and one of the containers is lightweight
878
// the location of the component should be fixed.
879
comp.relocateComponent();
880
}
881
}
882
}
883
if (curParent != this) {
884
/* Notify the layout manager of the added component. */
885
if (layoutMgr != null) {
886
if (layoutMgr instanceof LayoutManager2) {
887
((LayoutManager2)layoutMgr).addLayoutComponent(comp, null);
888
} else {
889
layoutMgr.addLayoutComponent(null, comp);
890
}
891
}
892
if (containerListener != null ||
893
(eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
894
Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
895
ContainerEvent e = new ContainerEvent(this,
896
ContainerEvent.COMPONENT_ADDED,
897
comp);
898
dispatchEvent(e);
899
}
900
comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
901
this, HierarchyEvent.PARENT_CHANGED,
902
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
903
904
// If component is focus owner or parent container of focus owner check that after reparenting
905
// focus owner moved out if new container prohibit this kind of focus owner.
906
if (comp.isFocusOwner() && !comp.canBeFocusOwnerRecursively()) {
907
comp.transferFocus();
908
} else if (comp instanceof Container) {
909
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
910
if (focusOwner != null && isParentOf(focusOwner) && !focusOwner.canBeFocusOwnerRecursively()) {
911
focusOwner.transferFocus();
912
}
913
}
914
} else {
915
comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
916
this, HierarchyEvent.HIERARCHY_CHANGED,
917
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
918
}
919
920
if (peer != null && layoutMgr == null && isVisible()) {
921
updateCursorImmediately();
922
}
923
}
924
925
/**
926
* Returns the z-order index of the component inside the container.
927
* The higher a component is in the z-order hierarchy, the lower
928
* its index. The component with the lowest z-order index is
929
* painted last, above all other child components.
930
*
931
* @param comp the component being queried
932
* @return the z-order index of the component; otherwise
933
* returns -1 if the component is <code>null</code>
934
* or doesn't belong to the container
935
* @see #setComponentZOrder(java.awt.Component, int)
936
* @since 1.5
937
*/
938
public int getComponentZOrder(Component comp) {
939
if (comp == null) {
940
return -1;
941
}
942
synchronized(getTreeLock()) {
943
// Quick check - container should be immediate parent of the component
944
if (comp.parent != this) {
945
return -1;
946
}
947
return component.indexOf(comp);
948
}
949
}
950
951
/**
952
* Adds the specified component to the end of this container.
953
* Also notifies the layout manager to add the component to
954
* this container's layout using the specified constraints object.
955
* This is a convenience method for {@link #addImpl}.
956
* <p>
957
* This method changes layout-related information, and therefore,
958
* invalidates the component hierarchy. If the container has already been
959
* displayed, the hierarchy must be validated thereafter in order to
960
* display the added component.
961
*
962
*
963
* @param comp the component to be added
964
* @param constraints an object expressing
965
* layout constraints for this component
966
* @exception NullPointerException if {@code comp} is {@code null}
967
* @see #addImpl
968
* @see #invalidate
969
* @see #validate
970
* @see javax.swing.JComponent#revalidate()
971
* @see LayoutManager
972
* @since JDK1.1
973
*/
974
public void add(Component comp, Object constraints) {
975
addImpl(comp, constraints, -1);
976
}
977
978
/**
979
* Adds the specified component to this container with the specified
980
* constraints at the specified index. Also notifies the layout
981
* manager to add the component to the this container's layout using
982
* the specified constraints object.
983
* This is a convenience method for {@link #addImpl}.
984
* <p>
985
* This method changes layout-related information, and therefore,
986
* invalidates the component hierarchy. If the container has already been
987
* displayed, the hierarchy must be validated thereafter in order to
988
* display the added component.
989
*
990
*
991
* @param comp the component to be added
992
* @param constraints an object expressing layout constraints for this
993
* @param index the position in the container's list at which to insert
994
* the component; <code>-1</code> means insert at the end
995
* component
996
* @exception NullPointerException if {@code comp} is {@code null}
997
* @exception IllegalArgumentException if {@code index} is invalid (see
998
* {@link #addImpl} for details)
999
* @see #addImpl
1000
* @see #invalidate
1001
* @see #validate
1002
* @see javax.swing.JComponent#revalidate()
1003
* @see #remove
1004
* @see LayoutManager
1005
*/
1006
public void add(Component comp, Object constraints, int index) {
1007
addImpl(comp, constraints, index);
1008
}
1009
1010
/**
1011
* Adds the specified component to this container at the specified
1012
* index. This method also notifies the layout manager to add
1013
* the component to this container's layout using the specified
1014
* constraints object via the <code>addLayoutComponent</code>
1015
* method.
1016
* <p>
1017
* The constraints are
1018
* defined by the particular layout manager being used. For
1019
* example, the <code>BorderLayout</code> class defines five
1020
* constraints: <code>BorderLayout.NORTH</code>,
1021
* <code>BorderLayout.SOUTH</code>, <code>BorderLayout.EAST</code>,
1022
* <code>BorderLayout.WEST</code>, and <code>BorderLayout.CENTER</code>.
1023
* <p>
1024
* The <code>GridBagLayout</code> class requires a
1025
* <code>GridBagConstraints</code> object. Failure to pass
1026
* the correct type of constraints object results in an
1027
* <code>IllegalArgumentException</code>.
1028
* <p>
1029
* If the current layout manager implements {@code LayoutManager2}, then
1030
* {@link LayoutManager2#addLayoutComponent(Component,Object)} is invoked on
1031
* it. If the current layout manager does not implement
1032
* {@code LayoutManager2}, and constraints is a {@code String}, then
1033
* {@link LayoutManager#addLayoutComponent(String,Component)} is invoked on it.
1034
* <p>
1035
* If the component is not an ancestor of this container and has a non-null
1036
* parent, it is removed from its current parent before it is added to this
1037
* container.
1038
* <p>
1039
* This is the method to override if a program needs to track
1040
* every add request to a container as all other add methods defer
1041
* to this one. An overriding method should
1042
* usually include a call to the superclass's version of the method:
1043
*
1044
* <blockquote>
1045
* <code>super.addImpl(comp, constraints, index)</code>
1046
* </blockquote>
1047
* <p>
1048
* This method changes layout-related information, and therefore,
1049
* invalidates the component hierarchy. If the container has already been
1050
* displayed, the hierarchy must be validated thereafter in order to
1051
* display the added component.
1052
*
1053
* @param comp the component to be added
1054
* @param constraints an object expressing layout constraints
1055
* for this component
1056
* @param index the position in the container's list at which to
1057
* insert the component, where <code>-1</code>
1058
* means append to the end
1059
* @exception IllegalArgumentException if {@code index} is invalid;
1060
* if {@code comp} is a child of this container, the valid
1061
* range is {@code [-1, getComponentCount()-1]}; if component is
1062
* not a child of this container, the valid range is
1063
* {@code [-1, getComponentCount()]}
1064
*
1065
* @exception IllegalArgumentException if {@code comp} is an ancestor of
1066
* this container
1067
* @exception IllegalArgumentException if adding a window to a container
1068
* @exception NullPointerException if {@code comp} is {@code null}
1069
* @see #add(Component)
1070
* @see #add(Component, int)
1071
* @see #add(Component, java.lang.Object)
1072
* @see #invalidate
1073
* @see LayoutManager
1074
* @see LayoutManager2
1075
* @since JDK1.1
1076
*/
1077
protected void addImpl(Component comp, Object constraints, int index) {
1078
synchronized (getTreeLock()) {
1079
/* Check for correct arguments: index in bounds,
1080
* comp cannot be one of this container's parents,
1081
* and comp cannot be a window.
1082
* comp and container must be on the same GraphicsDevice.
1083
* if comp is container, all sub-components must be on
1084
* same GraphicsDevice.
1085
*/
1086
GraphicsConfiguration thisGC = this.getGraphicsConfiguration();
1087
1088
if (index > component.size() || (index < 0 && index != -1)) {
1089
throw new IllegalArgumentException(
1090
"illegal component position");
1091
}
1092
checkAddToSelf(comp);
1093
checkNotAWindow(comp);
1094
/* Reparent the component and tidy up the tree's state. */
1095
if (comp.parent != null) {
1096
comp.parent.remove(comp);
1097
if (index > component.size()) {
1098
throw new IllegalArgumentException("illegal component position");
1099
}
1100
}
1101
if (thisGC != null) {
1102
comp.checkGD(thisGC.getDevice().getIDstring());
1103
}
1104
1105
1106
1107
//index == -1 means add to the end.
1108
if (index == -1) {
1109
component.add(comp);
1110
} else {
1111
component.add(index, comp);
1112
}
1113
comp.parent = this;
1114
comp.setGraphicsConfiguration(thisGC);
1115
1116
adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1117
comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
1118
adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1119
comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1120
adjustDescendants(comp.countHierarchyMembers());
1121
1122
invalidateIfValid();
1123
if (peer != null) {
1124
comp.addNotify();
1125
}
1126
1127
/* Notify the layout manager of the added component. */
1128
if (layoutMgr != null) {
1129
if (layoutMgr instanceof LayoutManager2) {
1130
((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints);
1131
} else if (constraints instanceof String) {
1132
layoutMgr.addLayoutComponent((String)constraints, comp);
1133
}
1134
}
1135
if (containerListener != null ||
1136
(eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
1137
Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1138
ContainerEvent e = new ContainerEvent(this,
1139
ContainerEvent.COMPONENT_ADDED,
1140
comp);
1141
dispatchEvent(e);
1142
}
1143
1144
comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
1145
this, HierarchyEvent.PARENT_CHANGED,
1146
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1147
if (peer != null && layoutMgr == null && isVisible()) {
1148
updateCursorImmediately();
1149
}
1150
}
1151
}
1152
1153
@Override
1154
boolean updateGraphicsData(GraphicsConfiguration gc) {
1155
checkTreeLock();
1156
1157
boolean ret = super.updateGraphicsData(gc);
1158
1159
for (Component comp : component) {
1160
if (comp != null) {
1161
ret |= comp.updateGraphicsData(gc);
1162
}
1163
}
1164
return ret;
1165
}
1166
1167
/**
1168
* Checks that all Components that this Container contains are on
1169
* the same GraphicsDevice as this Container. If not, throws an
1170
* IllegalArgumentException.
1171
*/
1172
void checkGD(String stringID) {
1173
for (Component comp : component) {
1174
if (comp != null) {
1175
comp.checkGD(stringID);
1176
}
1177
}
1178
}
1179
1180
/**
1181
* Removes the component, specified by <code>index</code>,
1182
* from this container.
1183
* This method also notifies the layout manager to remove the
1184
* component from this container's layout via the
1185
* <code>removeLayoutComponent</code> method.
1186
* <p>
1187
* This method changes layout-related information, and therefore,
1188
* invalidates the component hierarchy. If the container has already been
1189
* displayed, the hierarchy must be validated thereafter in order to
1190
* reflect the changes.
1191
*
1192
*
1193
* @param index the index of the component to be removed
1194
* @throws ArrayIndexOutOfBoundsException if {@code index} is not in
1195
* range {@code [0, getComponentCount()-1]}
1196
* @see #add
1197
* @see #invalidate
1198
* @see #validate
1199
* @see #getComponentCount
1200
* @since JDK1.1
1201
*/
1202
public void remove(int index) {
1203
synchronized (getTreeLock()) {
1204
if (index < 0 || index >= component.size()) {
1205
throw new ArrayIndexOutOfBoundsException(index);
1206
}
1207
Component comp = component.get(index);
1208
if (peer != null) {
1209
comp.removeNotify();
1210
}
1211
if (layoutMgr != null) {
1212
layoutMgr.removeLayoutComponent(comp);
1213
}
1214
1215
adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1216
-comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
1217
adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1218
-comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1219
adjustDescendants(-(comp.countHierarchyMembers()));
1220
1221
comp.parent = null;
1222
component.remove(index);
1223
comp.setGraphicsConfiguration(null);
1224
1225
invalidateIfValid();
1226
if (containerListener != null ||
1227
(eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
1228
Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1229
ContainerEvent e = new ContainerEvent(this,
1230
ContainerEvent.COMPONENT_REMOVED,
1231
comp);
1232
dispatchEvent(e);
1233
}
1234
1235
comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
1236
this, HierarchyEvent.PARENT_CHANGED,
1237
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1238
if (peer != null && layoutMgr == null && isVisible()) {
1239
updateCursorImmediately();
1240
}
1241
}
1242
}
1243
1244
/**
1245
* Removes the specified component from this container.
1246
* This method also notifies the layout manager to remove the
1247
* component from this container's layout via the
1248
* <code>removeLayoutComponent</code> method.
1249
* <p>
1250
* This method changes layout-related information, and therefore,
1251
* invalidates the component hierarchy. If the container has already been
1252
* displayed, the hierarchy must be validated thereafter in order to
1253
* reflect the changes.
1254
*
1255
* @param comp the component to be removed
1256
* @throws NullPointerException if {@code comp} is {@code null}
1257
* @see #add
1258
* @see #invalidate
1259
* @see #validate
1260
* @see #remove(int)
1261
*/
1262
public void remove(Component comp) {
1263
synchronized (getTreeLock()) {
1264
if (comp.parent == this) {
1265
int index = component.indexOf(comp);
1266
if (index >= 0) {
1267
remove(index);
1268
}
1269
}
1270
}
1271
}
1272
1273
/**
1274
* Removes all the components from this container.
1275
* This method also notifies the layout manager to remove the
1276
* components from this container's layout via the
1277
* <code>removeLayoutComponent</code> method.
1278
* <p>
1279
* This method changes layout-related information, and therefore,
1280
* invalidates the component hierarchy. If the container has already been
1281
* displayed, the hierarchy must be validated thereafter in order to
1282
* reflect the changes.
1283
*
1284
* @see #add
1285
* @see #remove
1286
* @see #invalidate
1287
*/
1288
public void removeAll() {
1289
synchronized (getTreeLock()) {
1290
adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1291
-listeningChildren);
1292
adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1293
-listeningBoundsChildren);
1294
adjustDescendants(-descendantsCount);
1295
1296
while (!component.isEmpty()) {
1297
Component comp = component.remove(component.size()-1);
1298
1299
if (peer != null) {
1300
comp.removeNotify();
1301
}
1302
if (layoutMgr != null) {
1303
layoutMgr.removeLayoutComponent(comp);
1304
}
1305
comp.parent = null;
1306
comp.setGraphicsConfiguration(null);
1307
if (containerListener != null ||
1308
(eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
1309
Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1310
ContainerEvent e = new ContainerEvent(this,
1311
ContainerEvent.COMPONENT_REMOVED,
1312
comp);
1313
dispatchEvent(e);
1314
}
1315
1316
comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,
1317
comp, this,
1318
HierarchyEvent.PARENT_CHANGED,
1319
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1320
}
1321
if (peer != null && layoutMgr == null && isVisible()) {
1322
updateCursorImmediately();
1323
}
1324
invalidateIfValid();
1325
}
1326
}
1327
1328
// Should only be called while holding tree lock
1329
int numListening(long mask) {
1330
int superListening = super.numListening(mask);
1331
1332
if (mask == AWTEvent.HIERARCHY_EVENT_MASK) {
1333
if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
1334
// Verify listeningChildren is correct
1335
int sum = 0;
1336
for (Component comp : component) {
1337
sum += comp.numListening(mask);
1338
}
1339
if (listeningChildren != sum) {
1340
eventLog.fine("Assertion (listeningChildren == sum) failed");
1341
}
1342
}
1343
return listeningChildren + superListening;
1344
} else if (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
1345
if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
1346
// Verify listeningBoundsChildren is correct
1347
int sum = 0;
1348
for (Component comp : component) {
1349
sum += comp.numListening(mask);
1350
}
1351
if (listeningBoundsChildren != sum) {
1352
eventLog.fine("Assertion (listeningBoundsChildren == sum) failed");
1353
}
1354
}
1355
return listeningBoundsChildren + superListening;
1356
} else {
1357
// assert false;
1358
if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
1359
eventLog.fine("This code must never be reached");
1360
}
1361
return superListening;
1362
}
1363
}
1364
1365
// Should only be called while holding tree lock
1366
void adjustListeningChildren(long mask, int num) {
1367
if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
1368
boolean toAssert = (mask == AWTEvent.HIERARCHY_EVENT_MASK ||
1369
mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK ||
1370
mask == (AWTEvent.HIERARCHY_EVENT_MASK |
1371
AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1372
if (!toAssert) {
1373
eventLog.fine("Assertion failed");
1374
}
1375
}
1376
1377
if (num == 0)
1378
return;
1379
1380
if ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) {
1381
listeningChildren += num;
1382
}
1383
if ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) {
1384
listeningBoundsChildren += num;
1385
}
1386
1387
adjustListeningChildrenOnParent(mask, num);
1388
}
1389
1390
// Should only be called while holding tree lock
1391
void adjustDescendants(int num) {
1392
if (num == 0)
1393
return;
1394
1395
descendantsCount += num;
1396
adjustDecendantsOnParent(num);
1397
}
1398
1399
// Should only be called while holding tree lock
1400
void adjustDecendantsOnParent(int num) {
1401
if (parent != null) {
1402
parent.adjustDescendants(num);
1403
}
1404
}
1405
1406
// Should only be called while holding tree lock
1407
int countHierarchyMembers() {
1408
if (log.isLoggable(PlatformLogger.Level.FINE)) {
1409
// Verify descendantsCount is correct
1410
int sum = 0;
1411
for (Component comp : component) {
1412
sum += comp.countHierarchyMembers();
1413
}
1414
if (descendantsCount != sum) {
1415
log.fine("Assertion (descendantsCount == sum) failed");
1416
}
1417
}
1418
return descendantsCount + 1;
1419
}
1420
1421
private int getListenersCount(int id, boolean enabledOnToolkit) {
1422
checkTreeLock();
1423
if (enabledOnToolkit) {
1424
return descendantsCount;
1425
}
1426
switch (id) {
1427
case HierarchyEvent.HIERARCHY_CHANGED:
1428
return listeningChildren;
1429
case HierarchyEvent.ANCESTOR_MOVED:
1430
case HierarchyEvent.ANCESTOR_RESIZED:
1431
return listeningBoundsChildren;
1432
default:
1433
return 0;
1434
}
1435
}
1436
1437
final int createHierarchyEvents(int id, Component changed,
1438
Container changedParent, long changeFlags, boolean enabledOnToolkit)
1439
{
1440
checkTreeLock();
1441
int listeners = getListenersCount(id, enabledOnToolkit);
1442
1443
for (int count = listeners, i = 0; count > 0; i++) {
1444
count -= component.get(i).createHierarchyEvents(id, changed,
1445
changedParent, changeFlags, enabledOnToolkit);
1446
}
1447
return listeners +
1448
super.createHierarchyEvents(id, changed, changedParent,
1449
changeFlags, enabledOnToolkit);
1450
}
1451
1452
final void createChildHierarchyEvents(int id, long changeFlags,
1453
boolean enabledOnToolkit)
1454
{
1455
checkTreeLock();
1456
if (component.isEmpty()) {
1457
return;
1458
}
1459
int listeners = getListenersCount(id, enabledOnToolkit);
1460
1461
for (int count = listeners, i = 0; count > 0; i++) {
1462
count -= component.get(i).createHierarchyEvents(id, this, parent,
1463
changeFlags, enabledOnToolkit);
1464
}
1465
}
1466
1467
/**
1468
* Gets the layout manager for this container.
1469
* @see #doLayout
1470
* @see #setLayout
1471
*/
1472
public LayoutManager getLayout() {
1473
return layoutMgr;
1474
}
1475
1476
/**
1477
* Sets the layout manager for this container.
1478
* <p>
1479
* This method changes layout-related information, and therefore,
1480
* invalidates the component hierarchy.
1481
*
1482
* @param mgr the specified layout manager
1483
* @see #doLayout
1484
* @see #getLayout
1485
* @see #invalidate
1486
*/
1487
public void setLayout(LayoutManager mgr) {
1488
layoutMgr = mgr;
1489
invalidateIfValid();
1490
}
1491
1492
/**
1493
* Causes this container to lay out its components. Most programs
1494
* should not call this method directly, but should invoke
1495
* the <code>validate</code> method instead.
1496
* @see LayoutManager#layoutContainer
1497
* @see #setLayout
1498
* @see #validate
1499
* @since JDK1.1
1500
*/
1501
public void doLayout() {
1502
layout();
1503
}
1504
1505
/**
1506
* @deprecated As of JDK version 1.1,
1507
* replaced by <code>doLayout()</code>.
1508
*/
1509
@Deprecated
1510
public void layout() {
1511
LayoutManager layoutMgr = this.layoutMgr;
1512
if (layoutMgr != null) {
1513
layoutMgr.layoutContainer(this);
1514
}
1515
}
1516
1517
/**
1518
* Indicates if this container is a <i>validate root</i>.
1519
* <p>
1520
* Layout-related changes, such as bounds of the validate root descendants,
1521
* do not affect the layout of the validate root parent. This peculiarity
1522
* enables the {@code invalidate()} method to stop invalidating the
1523
* component hierarchy when the method encounters a validate root. However,
1524
* to preserve backward compatibility this new optimized behavior is
1525
* enabled only when the {@code java.awt.smartInvalidate} system property
1526
* value is set to {@code true}.
1527
* <p>
1528
* If a component hierarchy contains validate roots and the new optimized
1529
* {@code invalidate()} behavior is enabled, the {@code validate()} method
1530
* must be invoked on the validate root of a previously invalidated
1531
* component to restore the validity of the hierarchy later. Otherwise,
1532
* calling the {@code validate()} method on the top-level container (such
1533
* as a {@code Frame} object) should be used to restore the validity of the
1534
* component hierarchy.
1535
* <p>
1536
* The {@code Window} class and the {@code Applet} class are the validate
1537
* roots in AWT. Swing introduces more validate roots.
1538
*
1539
* @return whether this container is a validate root
1540
* @see #invalidate
1541
* @see java.awt.Component#invalidate
1542
* @see javax.swing.JComponent#isValidateRoot
1543
* @see javax.swing.JComponent#revalidate
1544
* @since 1.7
1545
*/
1546
public boolean isValidateRoot() {
1547
return false;
1548
}
1549
1550
private static final boolean isJavaAwtSmartInvalidate;
1551
static {
1552
// Don't lazy-read because every app uses invalidate()
1553
isJavaAwtSmartInvalidate = AccessController.doPrivileged(
1554
new GetBooleanAction("java.awt.smartInvalidate"));
1555
}
1556
1557
/**
1558
* Invalidates the parent of the container unless the container
1559
* is a validate root.
1560
*/
1561
@Override
1562
void invalidateParent() {
1563
if (!isJavaAwtSmartInvalidate || !isValidateRoot()) {
1564
super.invalidateParent();
1565
}
1566
}
1567
1568
/**
1569
* Invalidates the container.
1570
* <p>
1571
* If the {@code LayoutManager} installed on this container is an instance
1572
* of the {@code LayoutManager2} interface, then
1573
* the {@link LayoutManager2#invalidateLayout(Container)} method is invoked
1574
* on it supplying this {@code Container} as the argument.
1575
* <p>
1576
* Afterwards this method marks this container invalid, and invalidates its
1577
* ancestors. See the {@link Component#invalidate} method for more details.
1578
*
1579
* @see #validate
1580
* @see #layout
1581
* @see LayoutManager2
1582
*/
1583
@Override
1584
public void invalidate() {
1585
LayoutManager layoutMgr = this.layoutMgr;
1586
if (layoutMgr instanceof LayoutManager2) {
1587
LayoutManager2 lm = (LayoutManager2) layoutMgr;
1588
lm.invalidateLayout(this);
1589
}
1590
super.invalidate();
1591
}
1592
1593
/**
1594
* Validates this container and all of its subcomponents.
1595
* <p>
1596
* Validating a container means laying out its subcomponents.
1597
* Layout-related changes, such as setting the bounds of a component, or
1598
* adding a component to the container, invalidate the container
1599
* automatically. Note that the ancestors of the container may be
1600
* invalidated also (see {@link Component#invalidate} for details.)
1601
* Therefore, to restore the validity of the hierarchy, the {@code
1602
* validate()} method should be invoked on the top-most invalid
1603
* container of the hierarchy.
1604
* <p>
1605
* Validating the container may be a quite time-consuming operation. For
1606
* performance reasons a developer may postpone the validation of the
1607
* hierarchy till a set of layout-related operations completes, e.g. after
1608
* adding all the children to the container.
1609
* <p>
1610
* If this {@code Container} is not valid, this method invokes
1611
* the {@code validateTree} method and marks this {@code Container}
1612
* as valid. Otherwise, no action is performed.
1613
*
1614
* @see #add(java.awt.Component)
1615
* @see #invalidate
1616
* @see Container#isValidateRoot
1617
* @see javax.swing.JComponent#revalidate()
1618
* @see #validateTree
1619
*/
1620
public void validate() {
1621
boolean updateCur = false;
1622
synchronized (getTreeLock()) {
1623
if ((!isValid() || descendUnconditionallyWhenValidating)
1624
&& peer != null)
1625
{
1626
ContainerPeer p = null;
1627
if (peer instanceof ContainerPeer) {
1628
p = (ContainerPeer) peer;
1629
}
1630
if (p != null) {
1631
p.beginValidate();
1632
}
1633
validateTree();
1634
if (p != null) {
1635
p.endValidate();
1636
// Avoid updating cursor if this is an internal call.
1637
// See validateUnconditionally() for details.
1638
if (!descendUnconditionallyWhenValidating) {
1639
updateCur = isVisible();
1640
}
1641
}
1642
}
1643
}
1644
if (updateCur) {
1645
updateCursorImmediately();
1646
}
1647
}
1648
1649
/**
1650
* Indicates whether valid containers should also traverse their
1651
* children and call the validateTree() method on them.
1652
*
1653
* Synchronization: TreeLock.
1654
*
1655
* The field is allowed to be static as long as the TreeLock itself is
1656
* static.
1657
*
1658
* @see #validateUnconditionally()
1659
*/
1660
private static boolean descendUnconditionallyWhenValidating = false;
1661
1662
/**
1663
* Unconditionally validate the component hierarchy.
1664
*/
1665
final void validateUnconditionally() {
1666
boolean updateCur = false;
1667
synchronized (getTreeLock()) {
1668
descendUnconditionallyWhenValidating = true;
1669
1670
validate();
1671
if (peer instanceof ContainerPeer) {
1672
updateCur = isVisible();
1673
}
1674
1675
descendUnconditionallyWhenValidating = false;
1676
}
1677
if (updateCur) {
1678
updateCursorImmediately();
1679
}
1680
}
1681
1682
/**
1683
* Recursively descends the container tree and recomputes the
1684
* layout for any subtrees marked as needing it (those marked as
1685
* invalid). Synchronization should be provided by the method
1686
* that calls this one: <code>validate</code>.
1687
*
1688
* @see #doLayout
1689
* @see #validate
1690
*/
1691
protected void validateTree() {
1692
checkTreeLock();
1693
if (!isValid() || descendUnconditionallyWhenValidating) {
1694
if (peer instanceof ContainerPeer) {
1695
((ContainerPeer)peer).beginLayout();
1696
}
1697
if (!isValid()) {
1698
doLayout();
1699
}
1700
for (int i = 0; i < component.size(); i++) {
1701
Component comp = component.get(i);
1702
if ( (comp instanceof Container)
1703
&& !(comp instanceof Window)
1704
&& (!comp.isValid() ||
1705
descendUnconditionallyWhenValidating))
1706
{
1707
((Container)comp).validateTree();
1708
} else {
1709
comp.validate();
1710
}
1711
}
1712
if (peer instanceof ContainerPeer) {
1713
((ContainerPeer)peer).endLayout();
1714
}
1715
}
1716
super.validate();
1717
}
1718
1719
/**
1720
* Recursively descends the container tree and invalidates all
1721
* contained components.
1722
*/
1723
void invalidateTree() {
1724
synchronized (getTreeLock()) {
1725
for (int i = 0; i < component.size(); i++) {
1726
Component comp = component.get(i);
1727
if (comp instanceof Container) {
1728
((Container)comp).invalidateTree();
1729
}
1730
else {
1731
comp.invalidateIfValid();
1732
}
1733
}
1734
invalidateIfValid();
1735
}
1736
}
1737
1738
/**
1739
* Sets the font of this container.
1740
* <p>
1741
* This method changes layout-related information, and therefore,
1742
* invalidates the component hierarchy.
1743
*
1744
* @param f The font to become this container's font.
1745
* @see Component#getFont
1746
* @see #invalidate
1747
* @since JDK1.0
1748
*/
1749
public void setFont(Font f) {
1750
boolean shouldinvalidate = false;
1751
1752
Font oldfont = getFont();
1753
super.setFont(f);
1754
Font newfont = getFont();
1755
if (newfont != oldfont && (oldfont == null ||
1756
!oldfont.equals(newfont))) {
1757
invalidateTree();
1758
}
1759
}
1760
1761
/**
1762
* Returns the preferred size of this container. If the preferred size has
1763
* not been set explicitly by {@link Component#setPreferredSize(Dimension)}
1764
* and this {@code Container} has a {@code non-null} {@link LayoutManager},
1765
* then {@link LayoutManager#preferredLayoutSize(Container)}
1766
* is used to calculate the preferred size.
1767
*
1768
* <p>Note: some implementations may cache the value returned from the
1769
* {@code LayoutManager}. Implementations that cache need not invoke
1770
* {@code preferredLayoutSize} on the {@code LayoutManager} every time
1771
* this method is invoked, rather the {@code LayoutManager} will only
1772
* be queried after the {@code Container} becomes invalid.
1773
*
1774
* @return an instance of <code>Dimension</code> that represents
1775
* the preferred size of this container.
1776
* @see #getMinimumSize
1777
* @see #getMaximumSize
1778
* @see #getLayout
1779
* @see LayoutManager#preferredLayoutSize(Container)
1780
* @see Component#getPreferredSize
1781
*/
1782
public Dimension getPreferredSize() {
1783
return preferredSize();
1784
}
1785
1786
/**
1787
* @deprecated As of JDK version 1.1,
1788
* replaced by <code>getPreferredSize()</code>.
1789
*/
1790
@Deprecated
1791
public Dimension preferredSize() {
1792
/* Avoid grabbing the lock if a reasonable cached size value
1793
* is available.
1794
*/
1795
Dimension dim = prefSize;
1796
if (dim == null || !(isPreferredSizeSet() || isValid())) {
1797
synchronized (getTreeLock()) {
1798
prefSize = (layoutMgr != null) ?
1799
layoutMgr.preferredLayoutSize(this) :
1800
super.preferredSize();
1801
dim = prefSize;
1802
}
1803
}
1804
if (dim != null){
1805
return new Dimension(dim);
1806
}
1807
else{
1808
return dim;
1809
}
1810
}
1811
1812
/**
1813
* Returns the minimum size of this container. If the minimum size has
1814
* not been set explicitly by {@link Component#setMinimumSize(Dimension)}
1815
* and this {@code Container} has a {@code non-null} {@link LayoutManager},
1816
* then {@link LayoutManager#minimumLayoutSize(Container)}
1817
* is used to calculate the minimum size.
1818
*
1819
* <p>Note: some implementations may cache the value returned from the
1820
* {@code LayoutManager}. Implementations that cache need not invoke
1821
* {@code minimumLayoutSize} on the {@code LayoutManager} every time
1822
* this method is invoked, rather the {@code LayoutManager} will only
1823
* be queried after the {@code Container} becomes invalid.
1824
*
1825
* @return an instance of <code>Dimension</code> that represents
1826
* the minimum size of this container.
1827
* @see #getPreferredSize
1828
* @see #getMaximumSize
1829
* @see #getLayout
1830
* @see LayoutManager#minimumLayoutSize(Container)
1831
* @see Component#getMinimumSize
1832
* @since JDK1.1
1833
*/
1834
public Dimension getMinimumSize() {
1835
return minimumSize();
1836
}
1837
1838
/**
1839
* @deprecated As of JDK version 1.1,
1840
* replaced by <code>getMinimumSize()</code>.
1841
*/
1842
@Deprecated
1843
public Dimension minimumSize() {
1844
/* Avoid grabbing the lock if a reasonable cached size value
1845
* is available.
1846
*/
1847
Dimension dim = minSize;
1848
if (dim == null || !(isMinimumSizeSet() || isValid())) {
1849
synchronized (getTreeLock()) {
1850
minSize = (layoutMgr != null) ?
1851
layoutMgr.minimumLayoutSize(this) :
1852
super.minimumSize();
1853
dim = minSize;
1854
}
1855
}
1856
if (dim != null){
1857
return new Dimension(dim);
1858
}
1859
else{
1860
return dim;
1861
}
1862
}
1863
1864
/**
1865
* Returns the maximum size of this container. If the maximum size has
1866
* not been set explicitly by {@link Component#setMaximumSize(Dimension)}
1867
* and the {@link LayoutManager} installed on this {@code Container}
1868
* is an instance of {@link LayoutManager2}, then
1869
* {@link LayoutManager2#maximumLayoutSize(Container)}
1870
* is used to calculate the maximum size.
1871
*
1872
* <p>Note: some implementations may cache the value returned from the
1873
* {@code LayoutManager2}. Implementations that cache need not invoke
1874
* {@code maximumLayoutSize} on the {@code LayoutManager2} every time
1875
* this method is invoked, rather the {@code LayoutManager2} will only
1876
* be queried after the {@code Container} becomes invalid.
1877
*
1878
* @return an instance of <code>Dimension</code> that represents
1879
* the maximum size of this container.
1880
* @see #getPreferredSize
1881
* @see #getMinimumSize
1882
* @see #getLayout
1883
* @see LayoutManager2#maximumLayoutSize(Container)
1884
* @see Component#getMaximumSize
1885
*/
1886
public Dimension getMaximumSize() {
1887
/* Avoid grabbing the lock if a reasonable cached size value
1888
* is available.
1889
*/
1890
Dimension dim = maxSize;
1891
if (dim == null || !(isMaximumSizeSet() || isValid())) {
1892
synchronized (getTreeLock()) {
1893
if (layoutMgr instanceof LayoutManager2) {
1894
LayoutManager2 lm = (LayoutManager2) layoutMgr;
1895
maxSize = lm.maximumLayoutSize(this);
1896
} else {
1897
maxSize = super.getMaximumSize();
1898
}
1899
dim = maxSize;
1900
}
1901
}
1902
if (dim != null){
1903
return new Dimension(dim);
1904
}
1905
else{
1906
return dim;
1907
}
1908
}
1909
1910
/**
1911
* Returns the alignment along the x axis. This specifies how
1912
* the component would like to be aligned relative to other
1913
* components. The value should be a number between 0 and 1
1914
* where 0 represents alignment along the origin, 1 is aligned
1915
* the furthest away from the origin, 0.5 is centered, etc.
1916
*/
1917
public float getAlignmentX() {
1918
float xAlign;
1919
if (layoutMgr instanceof LayoutManager2) {
1920
synchronized (getTreeLock()) {
1921
LayoutManager2 lm = (LayoutManager2) layoutMgr;
1922
xAlign = lm.getLayoutAlignmentX(this);
1923
}
1924
} else {
1925
xAlign = super.getAlignmentX();
1926
}
1927
return xAlign;
1928
}
1929
1930
/**
1931
* Returns the alignment along the y axis. This specifies how
1932
* the component would like to be aligned relative to other
1933
* components. The value should be a number between 0 and 1
1934
* where 0 represents alignment along the origin, 1 is aligned
1935
* the furthest away from the origin, 0.5 is centered, etc.
1936
*/
1937
public float getAlignmentY() {
1938
float yAlign;
1939
if (layoutMgr instanceof LayoutManager2) {
1940
synchronized (getTreeLock()) {
1941
LayoutManager2 lm = (LayoutManager2) layoutMgr;
1942
yAlign = lm.getLayoutAlignmentY(this);
1943
}
1944
} else {
1945
yAlign = super.getAlignmentY();
1946
}
1947
return yAlign;
1948
}
1949
1950
/**
1951
* Paints the container. This forwards the paint to any lightweight
1952
* components that are children of this container. If this method is
1953
* reimplemented, super.paint(g) should be called so that lightweight
1954
* components are properly rendered. If a child component is entirely
1955
* clipped by the current clipping setting in g, paint() will not be
1956
* forwarded to that child.
1957
*
1958
* @param g the specified Graphics window
1959
* @see Component#update(Graphics)
1960
*/
1961
public void paint(Graphics g) {
1962
if (isShowing()) {
1963
synchronized (getObjectLock()) {
1964
if (printing) {
1965
if (printingThreads.contains(Thread.currentThread())) {
1966
return;
1967
}
1968
}
1969
}
1970
1971
// The container is showing on screen and
1972
// this paint() is not called from print().
1973
// Paint self and forward the paint to lightweight subcomponents.
1974
1975
// super.paint(); -- Don't bother, since it's a NOP.
1976
1977
GraphicsCallback.PaintCallback.getInstance().
1978
runComponents(getComponentsSync(), g, GraphicsCallback.LIGHTWEIGHTS);
1979
}
1980
}
1981
1982
/**
1983
* Updates the container. This forwards the update to any lightweight
1984
* components that are children of this container. If this method is
1985
* reimplemented, super.update(g) should be called so that lightweight
1986
* components are properly rendered. If a child component is entirely
1987
* clipped by the current clipping setting in g, update() will not be
1988
* forwarded to that child.
1989
*
1990
* @param g the specified Graphics window
1991
* @see Component#update(Graphics)
1992
*/
1993
public void update(Graphics g) {
1994
if (isShowing()) {
1995
if (! (peer instanceof LightweightPeer)) {
1996
g.clearRect(0, 0, width, height);
1997
}
1998
paint(g);
1999
}
2000
}
2001
2002
/**
2003
* Prints the container. This forwards the print to any lightweight
2004
* components that are children of this container. If this method is
2005
* reimplemented, super.print(g) should be called so that lightweight
2006
* components are properly rendered. If a child component is entirely
2007
* clipped by the current clipping setting in g, print() will not be
2008
* forwarded to that child.
2009
*
2010
* @param g the specified Graphics window
2011
* @see Component#update(Graphics)
2012
*/
2013
public void print(Graphics g) {
2014
if (isShowing()) {
2015
Thread t = Thread.currentThread();
2016
try {
2017
synchronized (getObjectLock()) {
2018
if (printingThreads == null) {
2019
printingThreads = new HashSet<>();
2020
}
2021
printingThreads.add(t);
2022
printing = true;
2023
}
2024
super.print(g); // By default, Component.print() calls paint()
2025
} finally {
2026
synchronized (getObjectLock()) {
2027
printingThreads.remove(t);
2028
printing = !printingThreads.isEmpty();
2029
}
2030
}
2031
2032
GraphicsCallback.PrintCallback.getInstance().
2033
runComponents(getComponentsSync(), g, GraphicsCallback.LIGHTWEIGHTS);
2034
}
2035
}
2036
2037
/**
2038
* Paints each of the components in this container.
2039
* @param g the graphics context.
2040
* @see Component#paint
2041
* @see Component#paintAll
2042
*/
2043
public void paintComponents(Graphics g) {
2044
if (isShowing()) {
2045
GraphicsCallback.PaintAllCallback.getInstance().
2046
runComponents(getComponentsSync(), g, GraphicsCallback.TWO_PASSES);
2047
}
2048
}
2049
2050
/**
2051
* Simulates the peer callbacks into java.awt for printing of
2052
* lightweight Containers.
2053
* @param g the graphics context to use for printing.
2054
* @see Component#printAll
2055
* @see #printComponents
2056
*/
2057
void lightweightPaint(Graphics g) {
2058
super.lightweightPaint(g);
2059
paintHeavyweightComponents(g);
2060
}
2061
2062
/**
2063
* Prints all the heavyweight subcomponents.
2064
*/
2065
void paintHeavyweightComponents(Graphics g) {
2066
if (isShowing()) {
2067
GraphicsCallback.PaintHeavyweightComponentsCallback.getInstance().
2068
runComponents(getComponentsSync(), g,
2069
GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS);
2070
}
2071
}
2072
2073
/**
2074
* Prints each of the components in this container.
2075
* @param g the graphics context.
2076
* @see Component#print
2077
* @see Component#printAll
2078
*/
2079
public void printComponents(Graphics g) {
2080
if (isShowing()) {
2081
GraphicsCallback.PrintAllCallback.getInstance().
2082
runComponents(getComponentsSync(), g, GraphicsCallback.TWO_PASSES);
2083
}
2084
}
2085
2086
/**
2087
* Simulates the peer callbacks into java.awt for printing of
2088
* lightweight Containers.
2089
* @param g the graphics context to use for printing.
2090
* @see Component#printAll
2091
* @see #printComponents
2092
*/
2093
void lightweightPrint(Graphics g) {
2094
super.lightweightPrint(g);
2095
printHeavyweightComponents(g);
2096
}
2097
2098
/**
2099
* Prints all the heavyweight subcomponents.
2100
*/
2101
void printHeavyweightComponents(Graphics g) {
2102
if (isShowing()) {
2103
GraphicsCallback.PrintHeavyweightComponentsCallback.getInstance().
2104
runComponents(getComponentsSync(), g,
2105
GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS);
2106
}
2107
}
2108
2109
/**
2110
* Adds the specified container listener to receive container events
2111
* from this container.
2112
* If l is null, no exception is thrown and no action is performed.
2113
* <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
2114
* >AWT Threading Issues</a> for details on AWT's threading model.
2115
*
2116
* @param l the container listener
2117
*
2118
* @see #removeContainerListener
2119
* @see #getContainerListeners
2120
*/
2121
public synchronized void addContainerListener(ContainerListener l) {
2122
if (l == null) {
2123
return;
2124
}
2125
containerListener = AWTEventMulticaster.add(containerListener, l);
2126
newEventsOnly = true;
2127
}
2128
2129
/**
2130
* Removes the specified container listener so it no longer receives
2131
* container events from this container.
2132
* If l is null, no exception is thrown and no action is performed.
2133
* <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
2134
* >AWT Threading Issues</a> for details on AWT's threading model.
2135
*
2136
* @param l the container listener
2137
*
2138
* @see #addContainerListener
2139
* @see #getContainerListeners
2140
*/
2141
public synchronized void removeContainerListener(ContainerListener l) {
2142
if (l == null) {
2143
return;
2144
}
2145
containerListener = AWTEventMulticaster.remove(containerListener, l);
2146
}
2147
2148
/**
2149
* Returns an array of all the container listeners
2150
* registered on this container.
2151
*
2152
* @return all of this container's <code>ContainerListener</code>s
2153
* or an empty array if no container
2154
* listeners are currently registered
2155
*
2156
* @see #addContainerListener
2157
* @see #removeContainerListener
2158
* @since 1.4
2159
*/
2160
public synchronized ContainerListener[] getContainerListeners() {
2161
return getListeners(ContainerListener.class);
2162
}
2163
2164
/**
2165
* Returns an array of all the objects currently registered
2166
* as <code><em>Foo</em>Listener</code>s
2167
* upon this <code>Container</code>.
2168
* <code><em>Foo</em>Listener</code>s are registered using the
2169
* <code>add<em>Foo</em>Listener</code> method.
2170
*
2171
* <p>
2172
* You can specify the <code>listenerType</code> argument
2173
* with a class literal, such as
2174
* <code><em>Foo</em>Listener.class</code>.
2175
* For example, you can query a
2176
* <code>Container</code> <code>c</code>
2177
* for its container listeners with the following code:
2178
*
2179
* <pre>ContainerListener[] cls = (ContainerListener[])(c.getListeners(ContainerListener.class));</pre>
2180
*
2181
* If no such listeners exist, this method returns an empty array.
2182
*
2183
* @param listenerType the type of listeners requested; this parameter
2184
* should specify an interface that descends from
2185
* <code>java.util.EventListener</code>
2186
* @return an array of all objects registered as
2187
* <code><em>Foo</em>Listener</code>s on this container,
2188
* or an empty array if no such listeners have been added
2189
* @exception ClassCastException if <code>listenerType</code>
2190
* doesn't specify a class or interface that implements
2191
* <code>java.util.EventListener</code>
2192
* @exception NullPointerException if {@code listenerType} is {@code null}
2193
*
2194
* @see #getContainerListeners
2195
*
2196
* @since 1.3
2197
*/
2198
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
2199
EventListener l = null;
2200
if (listenerType == ContainerListener.class) {
2201
l = containerListener;
2202
} else {
2203
return super.getListeners(listenerType);
2204
}
2205
return AWTEventMulticaster.getListeners(l, listenerType);
2206
}
2207
2208
// REMIND: remove when filtering is done at lower level
2209
boolean eventEnabled(AWTEvent e) {
2210
int id = e.getID();
2211
2212
if (id == ContainerEvent.COMPONENT_ADDED ||
2213
id == ContainerEvent.COMPONENT_REMOVED) {
2214
if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
2215
containerListener != null) {
2216
return true;
2217
}
2218
return false;
2219
}
2220
return super.eventEnabled(e);
2221
}
2222
2223
/**
2224
* Processes events on this container. If the event is a
2225
* <code>ContainerEvent</code>, it invokes the
2226
* <code>processContainerEvent</code> method, else it invokes
2227
* its superclass's <code>processEvent</code>.
2228
* <p>Note that if the event parameter is <code>null</code>
2229
* the behavior is unspecified and may result in an
2230
* exception.
2231
*
2232
* @param e the event
2233
*/
2234
protected void processEvent(AWTEvent e) {
2235
if (e instanceof ContainerEvent) {
2236
processContainerEvent((ContainerEvent)e);
2237
return;
2238
}
2239
super.processEvent(e);
2240
}
2241
2242
/**
2243
* Processes container events occurring on this container by
2244
* dispatching them to any registered ContainerListener objects.
2245
* NOTE: This method will not be called unless container events
2246
* are enabled for this component; this happens when one of the
2247
* following occurs:
2248
* <ul>
2249
* <li>A ContainerListener object is registered via
2250
* <code>addContainerListener</code>
2251
* <li>Container events are enabled via <code>enableEvents</code>
2252
* </ul>
2253
* <p>Note that if the event parameter is <code>null</code>
2254
* the behavior is unspecified and may result in an
2255
* exception.
2256
*
2257
* @param e the container event
2258
* @see Component#enableEvents
2259
*/
2260
protected void processContainerEvent(ContainerEvent e) {
2261
ContainerListener listener = containerListener;
2262
if (listener != null) {
2263
switch(e.getID()) {
2264
case ContainerEvent.COMPONENT_ADDED:
2265
listener.componentAdded(e);
2266
break;
2267
case ContainerEvent.COMPONENT_REMOVED:
2268
listener.componentRemoved(e);
2269
break;
2270
}
2271
}
2272
}
2273
2274
/*
2275
* Dispatches an event to this component or one of its sub components.
2276
* Create ANCESTOR_RESIZED and ANCESTOR_MOVED events in response to
2277
* COMPONENT_RESIZED and COMPONENT_MOVED events. We have to do this
2278
* here instead of in processComponentEvent because ComponentEvents
2279
* may not be enabled for this Container.
2280
* @param e the event
2281
*/
2282
void dispatchEventImpl(AWTEvent e) {
2283
if ((dispatcher != null) && dispatcher.dispatchEvent(e)) {
2284
// event was sent to a lightweight component. The
2285
// native-produced event sent to the native container
2286
// must be properly disposed of by the peer, so it
2287
// gets forwarded. If the native host has been removed
2288
// as a result of the sending the lightweight event,
2289
// the peer reference will be null.
2290
e.consume();
2291
if (peer != null) {
2292
peer.handleEvent(e);
2293
}
2294
return;
2295
}
2296
2297
super.dispatchEventImpl(e);
2298
2299
synchronized (getTreeLock()) {
2300
switch (e.getID()) {
2301
case ComponentEvent.COMPONENT_RESIZED:
2302
createChildHierarchyEvents(HierarchyEvent.ANCESTOR_RESIZED, 0,
2303
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
2304
break;
2305
case ComponentEvent.COMPONENT_MOVED:
2306
createChildHierarchyEvents(HierarchyEvent.ANCESTOR_MOVED, 0,
2307
Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
2308
break;
2309
default:
2310
break;
2311
}
2312
}
2313
}
2314
2315
/*
2316
* Dispatches an event to this component, without trying to forward
2317
* it to any subcomponents
2318
* @param e the event
2319
*/
2320
void dispatchEventToSelf(AWTEvent e) {
2321
super.dispatchEventImpl(e);
2322
}
2323
2324
/**
2325
* Fetchs the top-most (deepest) lightweight component that is interested
2326
* in receiving mouse events.
2327
*/
2328
Component getMouseEventTarget(int x, int y, boolean includeSelf) {
2329
return getMouseEventTarget(x, y, includeSelf,
2330
MouseEventTargetFilter.FILTER,
2331
!SEARCH_HEAVYWEIGHTS);
2332
}
2333
2334
/**
2335
* Fetches the top-most (deepest) component to receive SunDropTargetEvents.
2336
*/
2337
Component getDropTargetEventTarget(int x, int y, boolean includeSelf) {
2338
return getMouseEventTarget(x, y, includeSelf,
2339
DropTargetEventTargetFilter.FILTER,
2340
SEARCH_HEAVYWEIGHTS);
2341
}
2342
2343
/**
2344
* A private version of getMouseEventTarget which has two additional
2345
* controllable behaviors. This method searches for the top-most
2346
* descendant of this container that contains the given coordinates
2347
* and is accepted by the given filter. The search will be constrained to
2348
* lightweight descendants if the last argument is <code>false</code>.
2349
*
2350
* @param filter EventTargetFilter instance to determine whether the
2351
* given component is a valid target for this event.
2352
* @param searchHeavyweights if <code>false</code>, the method
2353
* will bypass heavyweight components during the search.
2354
*/
2355
private Component getMouseEventTarget(int x, int y, boolean includeSelf,
2356
EventTargetFilter filter,
2357
boolean searchHeavyweights) {
2358
Component comp = null;
2359
if (searchHeavyweights) {
2360
comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
2361
SEARCH_HEAVYWEIGHTS,
2362
searchHeavyweights);
2363
}
2364
2365
if (comp == null || comp == this) {
2366
comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
2367
!SEARCH_HEAVYWEIGHTS,
2368
searchHeavyweights);
2369
}
2370
2371
return comp;
2372
}
2373
2374
/**
2375
* A private version of getMouseEventTarget which has three additional
2376
* controllable behaviors. This method searches for the top-most
2377
* descendant of this container that contains the given coordinates
2378
* and is accepted by the given filter. The search will be constrained to
2379
* descendants of only lightweight children or only heavyweight children
2380
* of this container depending on searchHeavyweightChildren. The search will
2381
* be constrained to only lightweight descendants of the searched children
2382
* of this container if searchHeavyweightDescendants is <code>false</code>.
2383
*
2384
* @param filter EventTargetFilter instance to determine whether the
2385
* selected component is a valid target for this event.
2386
* @param searchHeavyweightChildren if <code>true</code>, the method
2387
* will bypass immediate lightweight children during the search.
2388
* If <code>false</code>, the methods will bypass immediate
2389
* heavyweight children during the search.
2390
* @param searchHeavyweightDescendants if <code>false</code>, the method
2391
* will bypass heavyweight descendants which are not immediate
2392
* children during the search. If <code>true</code>, the method
2393
* will traverse both lightweight and heavyweight descendants during
2394
* the search.
2395
*/
2396
private Component getMouseEventTargetImpl(int x, int y, boolean includeSelf,
2397
EventTargetFilter filter,
2398
boolean searchHeavyweightChildren,
2399
boolean searchHeavyweightDescendants) {
2400
synchronized (getTreeLock()) {
2401
2402
for (int i = 0; i < component.size(); i++) {
2403
Component comp = component.get(i);
2404
if (comp != null && comp.visible &&
2405
((!searchHeavyweightChildren &&
2406
comp.peer instanceof LightweightPeer) ||
2407
(searchHeavyweightChildren &&
2408
!(comp.peer instanceof LightweightPeer))) &&
2409
comp.contains(x - comp.x, y - comp.y)) {
2410
2411
// found a component that intersects the point, see if there
2412
// is a deeper possibility.
2413
if (comp instanceof Container) {
2414
Container child = (Container) comp;
2415
Component deeper = child.getMouseEventTarget(
2416
x - child.x,
2417
y - child.y,
2418
includeSelf,
2419
filter,
2420
searchHeavyweightDescendants);
2421
if (deeper != null) {
2422
return deeper;
2423
}
2424
} else {
2425
if (filter.accept(comp)) {
2426
// there isn't a deeper target, but this component
2427
// is a target
2428
return comp;
2429
}
2430
}
2431
}
2432
}
2433
2434
boolean isPeerOK;
2435
boolean isMouseOverMe;
2436
2437
isPeerOK = (peer instanceof LightweightPeer) || includeSelf;
2438
isMouseOverMe = contains(x,y);
2439
2440
// didn't find a child target, return this component if it's
2441
// a possible target
2442
if (isMouseOverMe && isPeerOK && filter.accept(this)) {
2443
return this;
2444
}
2445
// no possible target
2446
return null;
2447
}
2448
}
2449
2450
static interface EventTargetFilter {
2451
boolean accept(final Component comp);
2452
}
2453
2454
static class MouseEventTargetFilter implements EventTargetFilter {
2455
static final EventTargetFilter FILTER = new MouseEventTargetFilter();
2456
2457
private MouseEventTargetFilter() {}
2458
2459
public boolean accept(final Component comp) {
2460
return (comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
2461
|| (comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
2462
|| (comp.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0
2463
|| comp.mouseListener != null
2464
|| comp.mouseMotionListener != null
2465
|| comp.mouseWheelListener != null;
2466
}
2467
}
2468
2469
static class DropTargetEventTargetFilter implements EventTargetFilter {
2470
static final EventTargetFilter FILTER = new DropTargetEventTargetFilter();
2471
2472
private DropTargetEventTargetFilter() {}
2473
2474
public boolean accept(final Component comp) {
2475
DropTarget dt = comp.getDropTarget();
2476
return dt != null && dt.isActive();
2477
}
2478
}
2479
2480
/**
2481
* This is called by lightweight components that want the containing
2482
* windowed parent to enable some kind of events on their behalf.
2483
* This is needed for events that are normally only dispatched to
2484
* windows to be accepted so that they can be forwarded downward to
2485
* the lightweight component that has enabled them.
2486
*/
2487
void proxyEnableEvents(long events) {
2488
if (peer instanceof LightweightPeer) {
2489
// this container is lightweight.... continue sending it
2490
// upward.
2491
if (parent != null) {
2492
parent.proxyEnableEvents(events);
2493
}
2494
} else {
2495
// This is a native container, so it needs to host
2496
// one of it's children. If this function is called before
2497
// a peer has been created we don't yet have a dispatcher
2498
// because it has not yet been determined if this instance
2499
// is lightweight.
2500
if (dispatcher != null) {
2501
dispatcher.enableEvents(events);
2502
}
2503
}
2504
}
2505
2506
/**
2507
* @deprecated As of JDK version 1.1,
2508
* replaced by <code>dispatchEvent(AWTEvent e)</code>
2509
*/
2510
@Deprecated
2511
public void deliverEvent(Event e) {
2512
Component comp = getComponentAt(e.x, e.y);
2513
if ((comp != null) && (comp != this)) {
2514
e.translate(-comp.x, -comp.y);
2515
comp.deliverEvent(e);
2516
} else {
2517
postEvent(e);
2518
}
2519
}
2520
2521
/**
2522
* Locates the component that contains the x,y position. The
2523
* top-most child component is returned in the case where there
2524
* is overlap in the components. This is determined by finding
2525
* the component closest to the index 0 that claims to contain
2526
* the given point via Component.contains(), except that Components
2527
* which have native peers take precedence over those which do not
2528
* (i.e., lightweight Components).
2529
*
2530
* @param x the <i>x</i> coordinate
2531
* @param y the <i>y</i> coordinate
2532
* @return null if the component does not contain the position.
2533
* If there is no child component at the requested point and the
2534
* point is within the bounds of the container the container itself
2535
* is returned; otherwise the top-most child is returned.
2536
* @see Component#contains
2537
* @since JDK1.1
2538
*/
2539
public Component getComponentAt(int x, int y) {
2540
return locate(x, y);
2541
}
2542
2543
/**
2544
* @deprecated As of JDK version 1.1,
2545
* replaced by <code>getComponentAt(int, int)</code>.
2546
*/
2547
@Deprecated
2548
public Component locate(int x, int y) {
2549
if (!contains(x, y)) {
2550
return null;
2551
}
2552
Component lightweight = null;
2553
synchronized (getTreeLock()) {
2554
// Optimized version of two passes:
2555
// see comment in sun.awt.SunGraphicsCallback
2556
for (final Component comp : component) {
2557
if (comp.contains(x - comp.x, y - comp.y)) {
2558
if (!comp.isLightweight()) {
2559
// return heavyweight component as soon as possible
2560
return comp;
2561
}
2562
if (lightweight == null) {
2563
// save and return later the first lightweight component
2564
lightweight = comp;
2565
}
2566
}
2567
}
2568
}
2569
return lightweight != null ? lightweight : this;
2570
}
2571
2572
/**
2573
* Gets the component that contains the specified point.
2574
* @param p the point.
2575
* @return returns the component that contains the point,
2576
* or <code>null</code> if the component does
2577
* not contain the point.
2578
* @see Component#contains
2579
* @since JDK1.1
2580
*/
2581
public Component getComponentAt(Point p) {
2582
return getComponentAt(p.x, p.y);
2583
}
2584
2585
/**
2586
* Returns the position of the mouse pointer in this <code>Container</code>'s
2587
* coordinate space if the <code>Container</code> is under the mouse pointer,
2588
* otherwise returns <code>null</code>.
2589
* This method is similar to {@link Component#getMousePosition()} with the exception
2590
* that it can take the <code>Container</code>'s children into account.
2591
* If <code>allowChildren</code> is <code>false</code>, this method will return
2592
* a non-null value only if the mouse pointer is above the <code>Container</code>
2593
* directly, not above the part obscured by children.
2594
* If <code>allowChildren</code> is <code>true</code>, this method returns
2595
* a non-null value if the mouse pointer is above <code>Container</code> or any
2596
* of its descendants.
2597
*
2598
* @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true
2599
* @param allowChildren true if children should be taken into account
2600
* @see Component#getMousePosition
2601
* @return mouse coordinates relative to this <code>Component</code>, or null
2602
* @since 1.5
2603
*/
2604
public Point getMousePosition(boolean allowChildren) throws HeadlessException {
2605
if (GraphicsEnvironment.isHeadless()) {
2606
throw new HeadlessException();
2607
}
2608
PointerInfo pi = java.security.AccessController.doPrivileged(
2609
new java.security.PrivilegedAction<PointerInfo>() {
2610
public PointerInfo run() {
2611
return MouseInfo.getPointerInfo();
2612
}
2613
}
2614
);
2615
synchronized (getTreeLock()) {
2616
Component inTheSameWindow = findUnderMouseInWindow(pi);
2617
if (isSameOrAncestorOf(inTheSameWindow, allowChildren)) {
2618
return pointRelativeToComponent(pi.getLocation());
2619
}
2620
return null;
2621
}
2622
}
2623
2624
boolean isSameOrAncestorOf(Component comp, boolean allowChildren) {
2625
return this == comp || (allowChildren && isParentOf(comp));
2626
}
2627
2628
/**
2629
* Locates the visible child component that contains the specified
2630
* position. The top-most child component is returned in the case
2631
* where there is overlap in the components. If the containing child
2632
* component is a Container, this method will continue searching for
2633
* the deepest nested child component. Components which are not
2634
* visible are ignored during the search.<p>
2635
*
2636
* The findComponentAt method is different from getComponentAt in
2637
* that getComponentAt only searches the Container's immediate
2638
* children; if the containing component is a Container,
2639
* findComponentAt will search that child to find a nested component.
2640
*
2641
* @param x the <i>x</i> coordinate
2642
* @param y the <i>y</i> coordinate
2643
* @return null if the component does not contain the position.
2644
* If there is no child component at the requested point and the
2645
* point is within the bounds of the container the container itself
2646
* is returned.
2647
* @see Component#contains
2648
* @see #getComponentAt
2649
* @since 1.2
2650
*/
2651
public Component findComponentAt(int x, int y) {
2652
return findComponentAt(x, y, true);
2653
}
2654
2655
/**
2656
* Private version of findComponentAt which has a controllable
2657
* behavior. Setting 'ignoreEnabled' to 'false' bypasses disabled
2658
* Components during the search. This behavior is used by the
2659
* lightweight cursor support in sun.awt.GlobalCursorManager.
2660
*
2661
* The addition of this feature is temporary, pending the
2662
* adoption of new, public API which exports this feature.
2663
*/
2664
final Component findComponentAt(int x, int y, boolean ignoreEnabled) {
2665
synchronized (getTreeLock()) {
2666
if (isRecursivelyVisible()){
2667
return findComponentAtImpl(x, y, ignoreEnabled);
2668
}
2669
}
2670
return null;
2671
}
2672
2673
final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled) {
2674
// checkTreeLock(); commented for a performance reason
2675
2676
if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) {
2677
return null;
2678
}
2679
Component lightweight = null;
2680
// Optimized version of two passes:
2681
// see comment in sun.awt.SunGraphicsCallback
2682
for (final Component comp : component) {
2683
final int x1 = x - comp.x;
2684
final int y1 = y - comp.y;
2685
if (!comp.contains(x1, y1)) {
2686
continue; // fast path
2687
}
2688
if (!comp.isLightweight()) {
2689
final Component child = getChildAt(comp, x1, y1, ignoreEnabled);
2690
if (child != null) {
2691
// return heavyweight component as soon as possible
2692
return child;
2693
}
2694
} else {
2695
if (lightweight == null) {
2696
// save and return later the first lightweight component
2697
lightweight = getChildAt(comp, x1, y1, ignoreEnabled);
2698
}
2699
}
2700
}
2701
return lightweight != null ? lightweight : this;
2702
}
2703
2704
/**
2705
* Helper method for findComponentAtImpl. Finds a child component using
2706
* findComponentAtImpl for Container and getComponentAt for Component.
2707
*/
2708
private static Component getChildAt(Component comp, int x, int y,
2709
boolean ignoreEnabled) {
2710
if (comp instanceof Container) {
2711
comp = ((Container) comp).findComponentAtImpl(x, y,
2712
ignoreEnabled);
2713
} else {
2714
comp = comp.getComponentAt(x, y);
2715
}
2716
if (comp != null && comp.visible &&
2717
(ignoreEnabled || comp.enabled)) {
2718
return comp;
2719
}
2720
return null;
2721
}
2722
2723
/**
2724
* Locates the visible child component that contains the specified
2725
* point. The top-most child component is returned in the case
2726
* where there is overlap in the components. If the containing child
2727
* component is a Container, this method will continue searching for
2728
* the deepest nested child component. Components which are not
2729
* visible are ignored during the search.<p>
2730
*
2731
* The findComponentAt method is different from getComponentAt in
2732
* that getComponentAt only searches the Container's immediate
2733
* children; if the containing component is a Container,
2734
* findComponentAt will search that child to find a nested component.
2735
*
2736
* @param p the point.
2737
* @return null if the component does not contain the position.
2738
* If there is no child component at the requested point and the
2739
* point is within the bounds of the container the container itself
2740
* is returned.
2741
* @throws NullPointerException if {@code p} is {@code null}
2742
* @see Component#contains
2743
* @see #getComponentAt
2744
* @since 1.2
2745
*/
2746
public Component findComponentAt(Point p) {
2747
return findComponentAt(p.x, p.y);
2748
}
2749
2750
/**
2751
* Makes this Container displayable by connecting it to
2752
* a native screen resource. Making a container displayable will
2753
* cause all of its children to be made displayable.
2754
* This method is called internally by the toolkit and should
2755
* not be called directly by programs.
2756
* @see Component#isDisplayable
2757
* @see #removeNotify
2758
*/
2759
public void addNotify() {
2760
synchronized (getTreeLock()) {
2761
// addNotify() on the children may cause proxy event enabling
2762
// on this instance, so we first call super.addNotify() and
2763
// possibly create an lightweight event dispatcher before calling
2764
// addNotify() on the children which may be lightweight.
2765
super.addNotify();
2766
if (! (peer instanceof LightweightPeer)) {
2767
dispatcher = new LightweightDispatcher(this);
2768
}
2769
2770
// We shouldn't use iterator because of the Swing menu
2771
// implementation specifics:
2772
// the menu is being assigned as a child to JLayeredPane
2773
// instead of particular component so always affect
2774
// collection of component if menu is becoming shown or hidden.
2775
for (int i = 0; i < component.size(); i++) {
2776
component.get(i).addNotify();
2777
}
2778
}
2779
}
2780
2781
/**
2782
* Makes this Container undisplayable by removing its connection
2783
* to its native screen resource. Making a container undisplayable
2784
* will cause all of its children to be made undisplayable.
2785
* This method is called by the toolkit internally and should
2786
* not be called directly by programs.
2787
* @see Component#isDisplayable
2788
* @see #addNotify
2789
*/
2790
public void removeNotify() {
2791
synchronized (getTreeLock()) {
2792
// We shouldn't use iterator because of the Swing menu
2793
// implementation specifics:
2794
// the menu is being assigned as a child to JLayeredPane
2795
// instead of particular component so always affect
2796
// collection of component if menu is becoming shown or hidden.
2797
for (int i = component.size()-1 ; i >= 0 ; i--) {
2798
Component comp = component.get(i);
2799
if (comp != null) {
2800
// Fix for 6607170.
2801
// We want to suppress focus change on disposal
2802
// of the focused component. But because of focus
2803
// is asynchronous, we should suppress focus change
2804
// on every component in case it receives native focus
2805
// in the process of disposal.
2806
comp.setAutoFocusTransferOnDisposal(false);
2807
comp.removeNotify();
2808
comp.setAutoFocusTransferOnDisposal(true);
2809
}
2810
}
2811
// If some of the children had focus before disposal then it still has.
2812
// Auto-transfer focus to the next (or previous) component if auto-transfer
2813
// is enabled.
2814
if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) {
2815
if (!transferFocus(false)) {
2816
transferFocusBackward(true);
2817
}
2818
}
2819
if ( dispatcher != null ) {
2820
dispatcher.dispose();
2821
dispatcher = null;
2822
}
2823
super.removeNotify();
2824
}
2825
}
2826
2827
/**
2828
* Checks if the component is contained in the component hierarchy of
2829
* this container.
2830
* @param c the component
2831
* @return <code>true</code> if it is an ancestor;
2832
* <code>false</code> otherwise.
2833
* @since JDK1.1
2834
*/
2835
public boolean isAncestorOf(Component c) {
2836
Container p;
2837
if (c == null || ((p = c.getParent()) == null)) {
2838
return false;
2839
}
2840
while (p != null) {
2841
if (p == this) {
2842
return true;
2843
}
2844
p = p.getParent();
2845
}
2846
return false;
2847
}
2848
2849
/*
2850
* The following code was added to support modal JInternalFrames
2851
* Unfortunately this code has to be added here so that we can get access to
2852
* some private AWT classes like SequencedEvent.
2853
*
2854
* The native container of the LW component has this field set
2855
* to tell it that it should block Mouse events for all LW
2856
* children except for the modal component.
2857
*
2858
* In the case of nested Modal components, we store the previous
2859
* modal component in the new modal components value of modalComp;
2860
*/
2861
2862
transient Component modalComp;
2863
transient AppContext modalAppContext;
2864
2865
private void startLWModal() {
2866
// Store the app context on which this component is being shown.
2867
// Event dispatch thread of this app context will be sleeping until
2868
// we wake it by any event from hideAndDisposeHandler().
2869
modalAppContext = AppContext.getAppContext();
2870
2871
// keep the KeyEvents from being dispatched
2872
// until the focus has been transfered
2873
long time = Toolkit.getEventQueue().getMostRecentKeyEventTime();
2874
Component predictedFocusOwner = (Component.isInstanceOf(this, "javax.swing.JInternalFrame")) ? ((javax.swing.JInternalFrame)(this)).getMostRecentFocusOwner() : null;
2875
if (predictedFocusOwner != null) {
2876
KeyboardFocusManager.getCurrentKeyboardFocusManager().
2877
enqueueKeyEvents(time, predictedFocusOwner);
2878
}
2879
// We have two mechanisms for blocking: 1. If we're on the
2880
// EventDispatchThread, start a new event pump. 2. If we're
2881
// on any other thread, call wait() on the treelock.
2882
final Container nativeContainer;
2883
synchronized (getTreeLock()) {
2884
nativeContainer = getHeavyweightContainer();
2885
if (nativeContainer.modalComp != null) {
2886
this.modalComp = nativeContainer.modalComp;
2887
nativeContainer.modalComp = this;
2888
return;
2889
}
2890
else {
2891
nativeContainer.modalComp = this;
2892
}
2893
}
2894
2895
Runnable pumpEventsForHierarchy = new Runnable() {
2896
public void run() {
2897
EventDispatchThread dispatchThread =
2898
(EventDispatchThread)Thread.currentThread();
2899
dispatchThread.pumpEventsForHierarchy(
2900
new Conditional() {
2901
public boolean evaluate() {
2902
return ((windowClosingException == null) && (nativeContainer.modalComp != null)) ;
2903
}
2904
}, Container.this);
2905
}
2906
};
2907
2908
if (EventQueue.isDispatchThread()) {
2909
SequencedEvent currentSequencedEvent =
2910
KeyboardFocusManager.getCurrentKeyboardFocusManager().
2911
getCurrentSequencedEvent();
2912
if (currentSequencedEvent != null) {
2913
currentSequencedEvent.dispose();
2914
}
2915
2916
pumpEventsForHierarchy.run();
2917
} else {
2918
synchronized (getTreeLock()) {
2919
Toolkit.getEventQueue().
2920
postEvent(new PeerEvent(this,
2921
pumpEventsForHierarchy,
2922
PeerEvent.PRIORITY_EVENT));
2923
while ((windowClosingException == null) &&
2924
(nativeContainer.modalComp != null))
2925
{
2926
try {
2927
getTreeLock().wait();
2928
} catch (InterruptedException e) {
2929
break;
2930
}
2931
}
2932
}
2933
}
2934
if (windowClosingException != null) {
2935
windowClosingException.fillInStackTrace();
2936
throw windowClosingException;
2937
}
2938
if (predictedFocusOwner != null) {
2939
KeyboardFocusManager.getCurrentKeyboardFocusManager().
2940
dequeueKeyEvents(time, predictedFocusOwner);
2941
}
2942
}
2943
2944
private void stopLWModal() {
2945
synchronized (getTreeLock()) {
2946
if (modalAppContext != null) {
2947
Container nativeContainer = getHeavyweightContainer();
2948
if(nativeContainer != null) {
2949
if (this.modalComp != null) {
2950
nativeContainer.modalComp = this.modalComp;
2951
this.modalComp = null;
2952
return;
2953
}
2954
else {
2955
nativeContainer.modalComp = null;
2956
}
2957
}
2958
// Wake up event dispatch thread on which the dialog was
2959
// initially shown
2960
SunToolkit.postEvent(modalAppContext,
2961
new PeerEvent(this,
2962
new WakingRunnable(),
2963
PeerEvent.PRIORITY_EVENT));
2964
}
2965
EventQueue.invokeLater(new WakingRunnable());
2966
getTreeLock().notifyAll();
2967
}
2968
}
2969
2970
final static class WakingRunnable implements Runnable {
2971
public void run() {
2972
}
2973
}
2974
2975
/* End of JOptionPane support code */
2976
2977
/**
2978
* Returns a string representing the state of this <code>Container</code>.
2979
* This method is intended to be used only for debugging purposes, and the
2980
* content and format of the returned string may vary between
2981
* implementations. The returned string may be empty but may not be
2982
* <code>null</code>.
2983
*
2984
* @return the parameter string of this container
2985
*/
2986
protected String paramString() {
2987
String str = super.paramString();
2988
LayoutManager layoutMgr = this.layoutMgr;
2989
if (layoutMgr != null) {
2990
str += ",layout=" + layoutMgr.getClass().getName();
2991
}
2992
return str;
2993
}
2994
2995
/**
2996
* Prints a listing of this container to the specified output
2997
* stream. The listing starts at the specified indentation.
2998
* <p>
2999
* The immediate children of the container are printed with
3000
* an indentation of <code>indent+1</code>. The children
3001
* of those children are printed at <code>indent+2</code>
3002
* and so on.
3003
*
3004
* @param out a print stream
3005
* @param indent the number of spaces to indent
3006
* @throws NullPointerException if {@code out} is {@code null}
3007
* @see Component#list(java.io.PrintStream, int)
3008
* @since JDK1.0
3009
*/
3010
public void list(PrintStream out, int indent) {
3011
super.list(out, indent);
3012
synchronized(getTreeLock()) {
3013
for (int i = 0; i < component.size(); i++) {
3014
Component comp = component.get(i);
3015
if (comp != null) {
3016
comp.list(out, indent+1);
3017
}
3018
}
3019
}
3020
}
3021
3022
/**
3023
* Prints out a list, starting at the specified indentation,
3024
* to the specified print writer.
3025
* <p>
3026
* The immediate children of the container are printed with
3027
* an indentation of <code>indent+1</code>. The children
3028
* of those children are printed at <code>indent+2</code>
3029
* and so on.
3030
*
3031
* @param out a print writer
3032
* @param indent the number of spaces to indent
3033
* @throws NullPointerException if {@code out} is {@code null}
3034
* @see Component#list(java.io.PrintWriter, int)
3035
* @since JDK1.1
3036
*/
3037
public void list(PrintWriter out, int indent) {
3038
super.list(out, indent);
3039
synchronized(getTreeLock()) {
3040
for (int i = 0; i < component.size(); i++) {
3041
Component comp = component.get(i);
3042
if (comp != null) {
3043
comp.list(out, indent+1);
3044
}
3045
}
3046
}
3047
}
3048
3049
/**
3050
* Sets the focus traversal keys for a given traversal operation for this
3051
* Container.
3052
* <p>
3053
* The default values for a Container's focus traversal keys are
3054
* implementation-dependent. Sun recommends that all implementations for a
3055
* particular native platform use the same default values. The
3056
* recommendations for Windows and Unix are listed below. These
3057
* recommendations are used in the Sun AWT implementations.
3058
*
3059
* <table border=1 summary="Recommended default values for a Container's focus traversal keys">
3060
* <tr>
3061
* <th>Identifier</th>
3062
* <th>Meaning</th>
3063
* <th>Default</th>
3064
* </tr>
3065
* <tr>
3066
* <td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td>
3067
* <td>Normal forward keyboard traversal</td>
3068
* <td>TAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED</td>
3069
* </tr>
3070
* <tr>
3071
* <td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td>
3072
* <td>Normal reverse keyboard traversal</td>
3073
* <td>SHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED</td>
3074
* </tr>
3075
* <tr>
3076
* <td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td>
3077
* <td>Go up one focus traversal cycle</td>
3078
* <td>none</td>
3079
* </tr>
3080
* <tr>
3081
* <td>KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS<td>
3082
* <td>Go down one focus traversal cycle</td>
3083
* <td>none</td>
3084
* </tr>
3085
* </table>
3086
*
3087
* To disable a traversal key, use an empty Set; Collections.EMPTY_SET is
3088
* recommended.
3089
* <p>
3090
* Using the AWTKeyStroke API, client code can specify on which of two
3091
* specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal
3092
* operation will occur. Regardless of which KeyEvent is specified,
3093
* however, all KeyEvents related to the focus traversal key, including the
3094
* associated KEY_TYPED event, will be consumed, and will not be dispatched
3095
* to any Container. It is a runtime error to specify a KEY_TYPED event as
3096
* mapping to a focus traversal operation, or to map the same event to
3097
* multiple default focus traversal operations.
3098
* <p>
3099
* If a value of null is specified for the Set, this Container inherits the
3100
* Set from its parent. If all ancestors of this Container have null
3101
* specified for the Set, then the current KeyboardFocusManager's default
3102
* Set is used.
3103
* <p>
3104
* This method may throw a {@code ClassCastException} if any {@code Object}
3105
* in {@code keystrokes} is not an {@code AWTKeyStroke}.
3106
*
3107
* @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3108
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3109
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3110
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3111
* @param keystrokes the Set of AWTKeyStroke for the specified operation
3112
* @see #getFocusTraversalKeys
3113
* @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
3114
* @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
3115
* @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
3116
* @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
3117
* @throws IllegalArgumentException if id is not one of
3118
* KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3119
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3120
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3121
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, or if keystrokes
3122
* contains null, or if any keystroke represents a KEY_TYPED event,
3123
* or if any keystroke already maps to another focus traversal
3124
* operation for this Container
3125
* @since 1.4
3126
* @beaninfo
3127
* bound: true
3128
*/
3129
public void setFocusTraversalKeys(int id,
3130
Set<? extends AWTKeyStroke> keystrokes)
3131
{
3132
if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3133
throw new IllegalArgumentException("invalid focus traversal key identifier");
3134
}
3135
3136
// Don't call super.setFocusTraversalKey. The Component parameter check
3137
// does not allow DOWN_CYCLE_TRAVERSAL_KEYS, but we do.
3138
setFocusTraversalKeys_NoIDCheck(id, keystrokes);
3139
}
3140
3141
/**
3142
* Returns the Set of focus traversal keys for a given traversal operation
3143
* for this Container. (See
3144
* <code>setFocusTraversalKeys</code> for a full description of each key.)
3145
* <p>
3146
* If a Set of traversal keys has not been explicitly defined for this
3147
* Container, then this Container's parent's Set is returned. If no Set
3148
* has been explicitly defined for any of this Container's ancestors, then
3149
* the current KeyboardFocusManager's default Set is returned.
3150
*
3151
* @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3152
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3153
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3154
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3155
* @return the Set of AWTKeyStrokes for the specified operation. The Set
3156
* will be unmodifiable, and may be empty. null will never be
3157
* returned.
3158
* @see #setFocusTraversalKeys
3159
* @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
3160
* @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
3161
* @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
3162
* @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
3163
* @throws IllegalArgumentException if id is not one of
3164
* KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3165
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3166
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3167
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3168
* @since 1.4
3169
*/
3170
public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
3171
if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3172
throw new IllegalArgumentException("invalid focus traversal key identifier");
3173
}
3174
3175
// Don't call super.getFocusTraversalKey. The Component parameter check
3176
// does not allow DOWN_CYCLE_TRAVERSAL_KEY, but we do.
3177
return getFocusTraversalKeys_NoIDCheck(id);
3178
}
3179
3180
/**
3181
* Returns whether the Set of focus traversal keys for the given focus
3182
* traversal operation has been explicitly defined for this Container. If
3183
* this method returns <code>false</code>, this Container is inheriting the
3184
* Set from an ancestor, or from the current KeyboardFocusManager.
3185
*
3186
* @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3187
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3188
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3189
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3190
* @return <code>true</code> if the the Set of focus traversal keys for the
3191
* given focus traversal operation has been explicitly defined for
3192
* this Component; <code>false</code> otherwise.
3193
* @throws IllegalArgumentException if id is not one of
3194
* KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3195
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3196
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3197
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3198
* @since 1.4
3199
*/
3200
public boolean areFocusTraversalKeysSet(int id) {
3201
if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3202
throw new IllegalArgumentException("invalid focus traversal key identifier");
3203
}
3204
3205
return (focusTraversalKeys != null && focusTraversalKeys[id] != null);
3206
}
3207
3208
/**
3209
* Returns whether the specified Container is the focus cycle root of this
3210
* Container's focus traversal cycle. Each focus traversal cycle has only
3211
* a single focus cycle root and each Container which is not a focus cycle
3212
* root belongs to only a single focus traversal cycle. Containers which
3213
* are focus cycle roots belong to two cycles: one rooted at the Container
3214
* itself, and one rooted at the Container's nearest focus-cycle-root
3215
* ancestor. This method will return <code>true</code> for both such
3216
* Containers in this case.
3217
*
3218
* @param container the Container to be tested
3219
* @return <code>true</code> if the specified Container is a focus-cycle-
3220
* root of this Container; <code>false</code> otherwise
3221
* @see #isFocusCycleRoot()
3222
* @since 1.4
3223
*/
3224
public boolean isFocusCycleRoot(Container container) {
3225
if (isFocusCycleRoot() && container == this) {
3226
return true;
3227
} else {
3228
return super.isFocusCycleRoot(container);
3229
}
3230
}
3231
3232
private Container findTraversalRoot() {
3233
// I potentially have two roots, myself and my root parent
3234
// If I am the current root, then use me
3235
// If none of my parents are roots, then use me
3236
// If my root parent is the current root, then use my root parent
3237
// If neither I nor my root parent is the current root, then
3238
// use my root parent (a guess)
3239
3240
Container currentFocusCycleRoot = KeyboardFocusManager.
3241
getCurrentKeyboardFocusManager().getCurrentFocusCycleRoot();
3242
Container root;
3243
3244
if (currentFocusCycleRoot == this) {
3245
root = this;
3246
} else {
3247
root = getFocusCycleRootAncestor();
3248
if (root == null) {
3249
root = this;
3250
}
3251
}
3252
3253
if (root != currentFocusCycleRoot) {
3254
KeyboardFocusManager.getCurrentKeyboardFocusManager().
3255
setGlobalCurrentFocusCycleRootPriv(root);
3256
}
3257
return root;
3258
}
3259
3260
final boolean containsFocus() {
3261
final Component focusOwner = KeyboardFocusManager.
3262
getCurrentKeyboardFocusManager().getFocusOwner();
3263
return isParentOf(focusOwner);
3264
}
3265
3266
/**
3267
* Check if this component is the child of this container or its children.
3268
* Note: this function acquires treeLock
3269
* Note: this function traverses children tree only in one Window.
3270
* @param comp a component in test, must not be null
3271
*/
3272
private boolean isParentOf(Component comp) {
3273
synchronized(getTreeLock()) {
3274
while (comp != null && comp != this && !(comp instanceof Window)) {
3275
comp = comp.getParent();
3276
}
3277
return (comp == this);
3278
}
3279
}
3280
3281
void clearMostRecentFocusOwnerOnHide() {
3282
boolean reset = false;
3283
Window window = null;
3284
3285
synchronized (getTreeLock()) {
3286
window = getContainingWindow();
3287
if (window != null) {
3288
Component comp = KeyboardFocusManager.getMostRecentFocusOwner(window);
3289
reset = ((comp == this) || isParentOf(comp));
3290
// This synchronized should always be the second in a pair
3291
// (tree lock, KeyboardFocusManager.class)
3292
synchronized(KeyboardFocusManager.class) {
3293
Component storedComp = window.getTemporaryLostComponent();
3294
if (isParentOf(storedComp) || storedComp == this) {
3295
window.setTemporaryLostComponent(null);
3296
}
3297
}
3298
}
3299
}
3300
3301
if (reset) {
3302
KeyboardFocusManager.setMostRecentFocusOwner(window, null);
3303
}
3304
}
3305
3306
void clearCurrentFocusCycleRootOnHide() {
3307
KeyboardFocusManager kfm =
3308
KeyboardFocusManager.getCurrentKeyboardFocusManager();
3309
Container cont = kfm.getCurrentFocusCycleRoot();
3310
3311
if (cont == this || isParentOf(cont)) {
3312
kfm.setGlobalCurrentFocusCycleRootPriv(null);
3313
}
3314
}
3315
3316
final Container getTraversalRoot() {
3317
if (isFocusCycleRoot()) {
3318
return findTraversalRoot();
3319
}
3320
3321
return super.getTraversalRoot();
3322
}
3323
3324
/**
3325
* Sets the focus traversal policy that will manage keyboard traversal of
3326
* this Container's children, if this Container is a focus cycle root. If
3327
* the argument is null, this Container inherits its policy from its focus-
3328
* cycle-root ancestor. If the argument is non-null, this policy will be
3329
* inherited by all focus-cycle-root children that have no keyboard-
3330
* traversal policy of their own (as will, recursively, their focus-cycle-
3331
* root children).
3332
* <p>
3333
* If this Container is not a focus cycle root, the policy will be
3334
* remembered, but will not be used or inherited by this or any other
3335
* Containers until this Container is made a focus cycle root.
3336
*
3337
* @param policy the new focus traversal policy for this Container
3338
* @see #getFocusTraversalPolicy
3339
* @see #setFocusCycleRoot
3340
* @see #isFocusCycleRoot
3341
* @since 1.4
3342
* @beaninfo
3343
* bound: true
3344
*/
3345
public void setFocusTraversalPolicy(FocusTraversalPolicy policy) {
3346
FocusTraversalPolicy oldPolicy;
3347
synchronized (this) {
3348
oldPolicy = this.focusTraversalPolicy;
3349
this.focusTraversalPolicy = policy;
3350
}
3351
firePropertyChange("focusTraversalPolicy", oldPolicy, policy);
3352
}
3353
3354
/**
3355
* Returns the focus traversal policy that will manage keyboard traversal
3356
* of this Container's children, or null if this Container is not a focus
3357
* cycle root. If no traversal policy has been explicitly set for this
3358
* Container, then this Container's focus-cycle-root ancestor's policy is
3359
* returned.
3360
*
3361
* @return this Container's focus traversal policy, or null if this
3362
* Container is not a focus cycle root.
3363
* @see #setFocusTraversalPolicy
3364
* @see #setFocusCycleRoot
3365
* @see #isFocusCycleRoot
3366
* @since 1.4
3367
*/
3368
public FocusTraversalPolicy getFocusTraversalPolicy() {
3369
if (!isFocusTraversalPolicyProvider() && !isFocusCycleRoot()) {
3370
return null;
3371
}
3372
3373
FocusTraversalPolicy policy = this.focusTraversalPolicy;
3374
if (policy != null) {
3375
return policy;
3376
}
3377
3378
Container rootAncestor = getFocusCycleRootAncestor();
3379
if (rootAncestor != null) {
3380
return rootAncestor.getFocusTraversalPolicy();
3381
} else {
3382
return KeyboardFocusManager.getCurrentKeyboardFocusManager().
3383
getDefaultFocusTraversalPolicy();
3384
}
3385
}
3386
3387
/**
3388
* Returns whether the focus traversal policy has been explicitly set for
3389
* this Container. If this method returns <code>false</code>, this
3390
* Container will inherit its focus traversal policy from an ancestor.
3391
*
3392
* @return <code>true</code> if the focus traversal policy has been
3393
* explicitly set for this Container; <code>false</code> otherwise.
3394
* @since 1.4
3395
*/
3396
public boolean isFocusTraversalPolicySet() {
3397
return (focusTraversalPolicy != null);
3398
}
3399
3400
/**
3401
* Sets whether this Container is the root of a focus traversal cycle. Once
3402
* focus enters a traversal cycle, typically it cannot leave it via focus
3403
* traversal unless one of the up- or down-cycle keys is pressed. Normal
3404
* traversal is limited to this Container, and all of this Container's
3405
* descendants that are not descendants of inferior focus cycle roots. Note
3406
* that a FocusTraversalPolicy may bend these restrictions, however. For
3407
* example, ContainerOrderFocusTraversalPolicy supports implicit down-cycle
3408
* traversal.
3409
* <p>
3410
* The alternative way to specify the traversal order of this Container's
3411
* children is to make this Container a
3412
* <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy provider</a>.
3413
*
3414
* @param focusCycleRoot indicates whether this Container is the root of a
3415
* focus traversal cycle
3416
* @see #isFocusCycleRoot()
3417
* @see #setFocusTraversalPolicy
3418
* @see #getFocusTraversalPolicy
3419
* @see ContainerOrderFocusTraversalPolicy
3420
* @see #setFocusTraversalPolicyProvider
3421
* @since 1.4
3422
* @beaninfo
3423
* bound: true
3424
*/
3425
public void setFocusCycleRoot(boolean focusCycleRoot) {
3426
boolean oldFocusCycleRoot;
3427
synchronized (this) {
3428
oldFocusCycleRoot = this.focusCycleRoot;
3429
this.focusCycleRoot = focusCycleRoot;
3430
}
3431
firePropertyChange("focusCycleRoot", oldFocusCycleRoot,
3432
focusCycleRoot);
3433
}
3434
3435
/**
3436
* Returns whether this Container is the root of a focus traversal cycle.
3437
* Once focus enters a traversal cycle, typically it cannot leave it via
3438
* focus traversal unless one of the up- or down-cycle keys is pressed.
3439
* Normal traversal is limited to this Container, and all of this
3440
* Container's descendants that are not descendants of inferior focus
3441
* cycle roots. Note that a FocusTraversalPolicy may bend these
3442
* restrictions, however. For example, ContainerOrderFocusTraversalPolicy
3443
* supports implicit down-cycle traversal.
3444
*
3445
* @return whether this Container is the root of a focus traversal cycle
3446
* @see #setFocusCycleRoot
3447
* @see #setFocusTraversalPolicy
3448
* @see #getFocusTraversalPolicy
3449
* @see ContainerOrderFocusTraversalPolicy
3450
* @since 1.4
3451
*/
3452
public boolean isFocusCycleRoot() {
3453
return focusCycleRoot;
3454
}
3455
3456
/**
3457
* Sets whether this container will be used to provide focus
3458
* traversal policy. Container with this property as
3459
* <code>true</code> will be used to acquire focus traversal policy
3460
* instead of closest focus cycle root ancestor.
3461
* @param provider indicates whether this container will be used to
3462
* provide focus traversal policy
3463
* @see #setFocusTraversalPolicy
3464
* @see #getFocusTraversalPolicy
3465
* @see #isFocusTraversalPolicyProvider
3466
* @since 1.5
3467
* @beaninfo
3468
* bound: true
3469
*/
3470
public final void setFocusTraversalPolicyProvider(boolean provider) {
3471
boolean oldProvider;
3472
synchronized(this) {
3473
oldProvider = focusTraversalPolicyProvider;
3474
focusTraversalPolicyProvider = provider;
3475
}
3476
firePropertyChange("focusTraversalPolicyProvider", oldProvider, provider);
3477
}
3478
3479
/**
3480
* Returns whether this container provides focus traversal
3481
* policy. If this property is set to <code>true</code> then when
3482
* keyboard focus manager searches container hierarchy for focus
3483
* traversal policy and encounters this container before any other
3484
* container with this property as true or focus cycle roots then
3485
* its focus traversal policy will be used instead of focus cycle
3486
* root's policy.
3487
* @see #setFocusTraversalPolicy
3488
* @see #getFocusTraversalPolicy
3489
* @see #setFocusCycleRoot
3490
* @see #setFocusTraversalPolicyProvider
3491
* @return <code>true</code> if this container provides focus traversal
3492
* policy, <code>false</code> otherwise
3493
* @since 1.5
3494
* @beaninfo
3495
* bound: true
3496
*/
3497
public final boolean isFocusTraversalPolicyProvider() {
3498
return focusTraversalPolicyProvider;
3499
}
3500
3501
/**
3502
* Transfers the focus down one focus traversal cycle. If this Container is
3503
* a focus cycle root, then the focus owner is set to this Container's
3504
* default Component to focus, and the current focus cycle root is set to
3505
* this Container. If this Container is not a focus cycle root, then no
3506
* focus traversal operation occurs.
3507
*
3508
* @see Component#requestFocus()
3509
* @see #isFocusCycleRoot
3510
* @see #setFocusCycleRoot
3511
* @since 1.4
3512
*/
3513
public void transferFocusDownCycle() {
3514
if (isFocusCycleRoot()) {
3515
KeyboardFocusManager.getCurrentKeyboardFocusManager().
3516
setGlobalCurrentFocusCycleRootPriv(this);
3517
Component toFocus = getFocusTraversalPolicy().
3518
getDefaultComponent(this);
3519
if (toFocus != null) {
3520
toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN);
3521
}
3522
}
3523
}
3524
3525
void preProcessKeyEvent(KeyEvent e) {
3526
Container parent = this.parent;
3527
if (parent != null) {
3528
parent.preProcessKeyEvent(e);
3529
}
3530
}
3531
3532
void postProcessKeyEvent(KeyEvent e) {
3533
Container parent = this.parent;
3534
if (parent != null) {
3535
parent.postProcessKeyEvent(e);
3536
}
3537
}
3538
3539
boolean postsOldMouseEvents() {
3540
return true;
3541
}
3542
3543
/**
3544
* Sets the <code>ComponentOrientation</code> property of this container
3545
* and all components contained within it.
3546
* <p>
3547
* This method changes layout-related information, and therefore,
3548
* invalidates the component hierarchy.
3549
*
3550
* @param o the new component orientation of this container and
3551
* the components contained within it.
3552
* @exception NullPointerException if <code>orientation</code> is null.
3553
* @see Component#setComponentOrientation
3554
* @see Component#getComponentOrientation
3555
* @see #invalidate
3556
* @since 1.4
3557
*/
3558
public void applyComponentOrientation(ComponentOrientation o) {
3559
super.applyComponentOrientation(o);
3560
synchronized (getTreeLock()) {
3561
for (int i = 0; i < component.size(); i++) {
3562
Component comp = component.get(i);
3563
comp.applyComponentOrientation(o);
3564
}
3565
}
3566
}
3567
3568
/**
3569
* Adds a PropertyChangeListener to the listener list. The listener is
3570
* registered for all bound properties of this class, including the
3571
* following:
3572
* <ul>
3573
* <li>this Container's font ("font")</li>
3574
* <li>this Container's background color ("background")</li>
3575
* <li>this Container's foreground color ("foreground")</li>
3576
* <li>this Container's focusability ("focusable")</li>
3577
* <li>this Container's focus traversal keys enabled state
3578
* ("focusTraversalKeysEnabled")</li>
3579
* <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
3580
* ("forwardFocusTraversalKeys")</li>
3581
* <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
3582
* ("backwardFocusTraversalKeys")</li>
3583
* <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
3584
* ("upCycleFocusTraversalKeys")</li>
3585
* <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
3586
* ("downCycleFocusTraversalKeys")</li>
3587
* <li>this Container's focus traversal policy ("focusTraversalPolicy")
3588
* </li>
3589
* <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
3590
* </ul>
3591
* Note that if this Container is inheriting a bound property, then no
3592
* event will be fired in response to a change in the inherited property.
3593
* <p>
3594
* If listener is null, no exception is thrown and no action is performed.
3595
*
3596
* @param listener the PropertyChangeListener to be added
3597
*
3598
* @see Component#removePropertyChangeListener
3599
* @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
3600
*/
3601
public void addPropertyChangeListener(PropertyChangeListener listener) {
3602
super.addPropertyChangeListener(listener);
3603
}
3604
3605
/**
3606
* Adds a PropertyChangeListener to the listener list for a specific
3607
* property. The specified property may be user-defined, or one of the
3608
* following defaults:
3609
* <ul>
3610
* <li>this Container's font ("font")</li>
3611
* <li>this Container's background color ("background")</li>
3612
* <li>this Container's foreground color ("foreground")</li>
3613
* <li>this Container's focusability ("focusable")</li>
3614
* <li>this Container's focus traversal keys enabled state
3615
* ("focusTraversalKeysEnabled")</li>
3616
* <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
3617
* ("forwardFocusTraversalKeys")</li>
3618
* <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
3619
* ("backwardFocusTraversalKeys")</li>
3620
* <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
3621
* ("upCycleFocusTraversalKeys")</li>
3622
* <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
3623
* ("downCycleFocusTraversalKeys")</li>
3624
* <li>this Container's focus traversal policy ("focusTraversalPolicy")
3625
* </li>
3626
* <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
3627
* <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
3628
* <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
3629
* </ul>
3630
* Note that if this Container is inheriting a bound property, then no
3631
* event will be fired in response to a change in the inherited property.
3632
* <p>
3633
* If listener is null, no exception is thrown and no action is performed.
3634
*
3635
* @param propertyName one of the property names listed above
3636
* @param listener the PropertyChangeListener to be added
3637
*
3638
* @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
3639
* @see Component#removePropertyChangeListener
3640
*/
3641
public void addPropertyChangeListener(String propertyName,
3642
PropertyChangeListener listener) {
3643
super.addPropertyChangeListener(propertyName, listener);
3644
}
3645
3646
// Serialization support. A Container is responsible for restoring the
3647
// parent fields of its component children.
3648
3649
/**
3650
* Container Serial Data Version.
3651
*/
3652
private int containerSerializedDataVersion = 1;
3653
3654
/**
3655
* Serializes this <code>Container</code> to the specified
3656
* <code>ObjectOutputStream</code>.
3657
* <ul>
3658
* <li>Writes default serializable fields to the stream.</li>
3659
* <li>Writes a list of serializable ContainerListener(s) as optional
3660
* data. The non-serializable ContainerListner(s) are detected and
3661
* no attempt is made to serialize them.</li>
3662
* <li>Write this Container's FocusTraversalPolicy if and only if it
3663
* is Serializable; otherwise, <code>null</code> is written.</li>
3664
* </ul>
3665
*
3666
* @param s the <code>ObjectOutputStream</code> to write
3667
* @serialData <code>null</code> terminated sequence of 0 or more pairs;
3668
* the pair consists of a <code>String</code> and <code>Object</code>;
3669
* the <code>String</code> indicates the type of object and
3670
* is one of the following:
3671
* <code>containerListenerK</code> indicating an
3672
* <code>ContainerListener</code> object;
3673
* the <code>Container</code>'s <code>FocusTraversalPolicy</code>,
3674
* or <code>null</code>
3675
*
3676
* @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String, java.util.EventListener)
3677
* @see Container#containerListenerK
3678
* @see #readObject(ObjectInputStream)
3679
*/
3680
private void writeObject(ObjectOutputStream s) throws IOException {
3681
ObjectOutputStream.PutField f = s.putFields();
3682
f.put("ncomponents", component.size());
3683
f.put("component", component.toArray(EMPTY_ARRAY));
3684
f.put("layoutMgr", layoutMgr);
3685
f.put("dispatcher", dispatcher);
3686
f.put("maxSize", maxSize);
3687
f.put("focusCycleRoot", focusCycleRoot);
3688
f.put("containerSerializedDataVersion", containerSerializedDataVersion);
3689
f.put("focusTraversalPolicyProvider", focusTraversalPolicyProvider);
3690
s.writeFields();
3691
3692
AWTEventMulticaster.save(s, containerListenerK, containerListener);
3693
s.writeObject(null);
3694
3695
if (focusTraversalPolicy instanceof java.io.Serializable) {
3696
s.writeObject(focusTraversalPolicy);
3697
} else {
3698
s.writeObject(null);
3699
}
3700
}
3701
3702
/**
3703
* Deserializes this <code>Container</code> from the specified
3704
* <code>ObjectInputStream</code>.
3705
* <ul>
3706
* <li>Reads default serializable fields from the stream.</li>
3707
* <li>Reads a list of serializable ContainerListener(s) as optional
3708
* data. If the list is null, no Listeners are installed.</li>
3709
* <li>Reads this Container's FocusTraversalPolicy, which may be null,
3710
* as optional data.</li>
3711
* </ul>
3712
*
3713
* @param s the <code>ObjectInputStream</code> to read
3714
* @serial
3715
* @see #addContainerListener
3716
* @see #writeObject(ObjectOutputStream)
3717
*/
3718
private void readObject(ObjectInputStream s)
3719
throws ClassNotFoundException, IOException
3720
{
3721
ObjectInputStream.GetField f = s.readFields();
3722
// array of components may not be present in the stream or may be null
3723
Component [] tmpComponent = (Component[])f.get("component", null);
3724
if (tmpComponent == null) {
3725
tmpComponent = EMPTY_ARRAY;
3726
}
3727
int ncomponents = (Integer) f.get("ncomponents", 0);
3728
if (ncomponents < 0 || ncomponents > tmpComponent.length) {
3729
throw new InvalidObjectException("Incorrect number of components");
3730
}
3731
component = new java.util.ArrayList<Component>(ncomponents);
3732
for (int i = 0; i < ncomponents; ++i) {
3733
component.add(tmpComponent[i]);
3734
}
3735
layoutMgr = (LayoutManager)f.get("layoutMgr", null);
3736
dispatcher = (LightweightDispatcher)f.get("dispatcher", null);
3737
// Old stream. Doesn't contain maxSize among Component's fields.
3738
if (maxSize == null) {
3739
maxSize = (Dimension)f.get("maxSize", null);
3740
}
3741
focusCycleRoot = f.get("focusCycleRoot", false);
3742
containerSerializedDataVersion = f.get("containerSerializedDataVersion", 1);
3743
focusTraversalPolicyProvider = f.get("focusTraversalPolicyProvider", false);
3744
java.util.List<Component> component = this.component;
3745
for(Component comp : component) {
3746
comp.parent = this;
3747
adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
3748
comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
3749
adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
3750
comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
3751
adjustDescendants(comp.countHierarchyMembers());
3752
}
3753
3754
Object keyOrNull;
3755
while(null != (keyOrNull = s.readObject())) {
3756
String key = ((String)keyOrNull).intern();
3757
3758
if (containerListenerK == key) {
3759
addContainerListener((ContainerListener)(s.readObject()));
3760
} else {
3761
// skip value for unrecognized key
3762
s.readObject();
3763
}
3764
}
3765
3766
try {
3767
Object policy = s.readObject();
3768
if (policy instanceof FocusTraversalPolicy) {
3769
focusTraversalPolicy = (FocusTraversalPolicy)policy;
3770
}
3771
} catch (java.io.OptionalDataException e) {
3772
// JDK 1.1/1.2/1.3 instances will not have this optional data.
3773
// e.eof will be true to indicate that there is no more data
3774
// available for this object. If e.eof is not true, throw the
3775
// exception as it might have been caused by reasons unrelated to
3776
// focusTraversalPolicy.
3777
3778
if (!e.eof) {
3779
throw e;
3780
}
3781
}
3782
}
3783
3784
/*
3785
* --- Accessibility Support ---
3786
*/
3787
3788
/**
3789
* Inner class of Container used to provide default support for
3790
* accessibility. This class is not meant to be used directly by
3791
* application developers, but is instead meant only to be
3792
* subclassed by container developers.
3793
* <p>
3794
* The class used to obtain the accessible role for this object,
3795
* as well as implementing many of the methods in the
3796
* AccessibleContainer interface.
3797
* @since 1.3
3798
*/
3799
protected class AccessibleAWTContainer extends AccessibleAWTComponent {
3800
3801
/**
3802
* JDK1.3 serialVersionUID
3803
*/
3804
private static final long serialVersionUID = 5081320404842566097L;
3805
3806
/**
3807
* Returns the number of accessible children in the object. If all
3808
* of the children of this object implement <code>Accessible</code>,
3809
* then this method should return the number of children of this object.
3810
*
3811
* @return the number of accessible children in the object
3812
*/
3813
public int getAccessibleChildrenCount() {
3814
return Container.this.getAccessibleChildrenCount();
3815
}
3816
3817
/**
3818
* Returns the nth <code>Accessible</code> child of the object.
3819
*
3820
* @param i zero-based index of child
3821
* @return the nth <code>Accessible</code> child of the object
3822
*/
3823
public Accessible getAccessibleChild(int i) {
3824
return Container.this.getAccessibleChild(i);
3825
}
3826
3827
/**
3828
* Returns the <code>Accessible</code> child, if one exists,
3829
* contained at the local coordinate <code>Point</code>.
3830
*
3831
* @param p the point defining the top-left corner of the
3832
* <code>Accessible</code>, given in the coordinate space
3833
* of the object's parent
3834
* @return the <code>Accessible</code>, if it exists,
3835
* at the specified location; else <code>null</code>
3836
*/
3837
public Accessible getAccessibleAt(Point p) {
3838
return Container.this.getAccessibleAt(p);
3839
}
3840
3841
/**
3842
* Number of PropertyChangeListener objects registered. It's used
3843
* to add/remove ContainerListener to track target Container's state.
3844
*/
3845
private volatile transient int propertyListenersCount = 0;
3846
3847
protected ContainerListener accessibleContainerHandler = null;
3848
3849
/**
3850
* Fire <code>PropertyChange</code> listener, if one is registered,
3851
* when children are added or removed.
3852
* @since 1.3
3853
*/
3854
protected class AccessibleContainerHandler
3855
implements ContainerListener {
3856
public void componentAdded(ContainerEvent e) {
3857
Component c = e.getChild();
3858
if (c != null && c instanceof Accessible) {
3859
AccessibleAWTContainer.this.firePropertyChange(
3860
AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3861
null, ((Accessible) c).getAccessibleContext());
3862
}
3863
}
3864
public void componentRemoved(ContainerEvent e) {
3865
Component c = e.getChild();
3866
if (c != null && c instanceof Accessible) {
3867
AccessibleAWTContainer.this.firePropertyChange(
3868
AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3869
((Accessible) c).getAccessibleContext(), null);
3870
}
3871
}
3872
}
3873
3874
/**
3875
* Adds a PropertyChangeListener to the listener list.
3876
*
3877
* @param listener the PropertyChangeListener to be added
3878
*/
3879
public void addPropertyChangeListener(PropertyChangeListener listener) {
3880
if (accessibleContainerHandler == null) {
3881
accessibleContainerHandler = new AccessibleContainerHandler();
3882
}
3883
if (propertyListenersCount++ == 0) {
3884
Container.this.addContainerListener(accessibleContainerHandler);
3885
}
3886
super.addPropertyChangeListener(listener);
3887
}
3888
3889
/**
3890
* Remove a PropertyChangeListener from the listener list.
3891
* This removes a PropertyChangeListener that was registered
3892
* for all properties.
3893
*
3894
* @param listener the PropertyChangeListener to be removed
3895
*/
3896
public void removePropertyChangeListener(PropertyChangeListener listener) {
3897
if (--propertyListenersCount == 0) {
3898
Container.this.removeContainerListener(accessibleContainerHandler);
3899
}
3900
super.removePropertyChangeListener(listener);
3901
}
3902
3903
} // inner class AccessibleAWTContainer
3904
3905
/**
3906
* Returns the <code>Accessible</code> child contained at the local
3907
* coordinate <code>Point</code>, if one exists. Otherwise
3908
* returns <code>null</code>.
3909
*
3910
* @param p the point defining the top-left corner of the
3911
* <code>Accessible</code>, given in the coordinate space
3912
* of the object's parent
3913
* @return the <code>Accessible</code> at the specified location,
3914
* if it exists; otherwise <code>null</code>
3915
*/
3916
Accessible getAccessibleAt(Point p) {
3917
synchronized (getTreeLock()) {
3918
if (this instanceof Accessible) {
3919
Accessible a = (Accessible)this;
3920
AccessibleContext ac = a.getAccessibleContext();
3921
if (ac != null) {
3922
AccessibleComponent acmp;
3923
Point location;
3924
int nchildren = ac.getAccessibleChildrenCount();
3925
for (int i=0; i < nchildren; i++) {
3926
a = ac.getAccessibleChild(i);
3927
if ((a != null)) {
3928
ac = a.getAccessibleContext();
3929
if (ac != null) {
3930
acmp = ac.getAccessibleComponent();
3931
if ((acmp != null) && (acmp.isShowing())) {
3932
location = acmp.getLocation();
3933
Point np = new Point(p.x-location.x,
3934
p.y-location.y);
3935
if (acmp.contains(np)){
3936
return a;
3937
}
3938
}
3939
}
3940
}
3941
}
3942
}
3943
return (Accessible)this;
3944
} else {
3945
Component ret = this;
3946
if (!this.contains(p.x,p.y)) {
3947
ret = null;
3948
} else {
3949
int ncomponents = this.getComponentCount();
3950
for (int i=0; i < ncomponents; i++) {
3951
Component comp = this.getComponent(i);
3952
if ((comp != null) && comp.isShowing()) {
3953
Point location = comp.getLocation();
3954
if (comp.contains(p.x-location.x,p.y-location.y)) {
3955
ret = comp;
3956
}
3957
}
3958
}
3959
}
3960
if (ret instanceof Accessible) {
3961
return (Accessible) ret;
3962
}
3963
}
3964
return null;
3965
}
3966
}
3967
3968
/**
3969
* Returns the number of accessible children in the object. If all
3970
* of the children of this object implement <code>Accessible</code>,
3971
* then this method should return the number of children of this object.
3972
*
3973
* @return the number of accessible children in the object
3974
*/
3975
int getAccessibleChildrenCount() {
3976
synchronized (getTreeLock()) {
3977
int count = 0;
3978
Component[] children = this.getComponents();
3979
for (int i = 0; i < children.length; i++) {
3980
if (children[i] instanceof Accessible) {
3981
count++;
3982
}
3983
}
3984
return count;
3985
}
3986
}
3987
3988
/**
3989
* Returns the nth <code>Accessible</code> child of the object.
3990
*
3991
* @param i zero-based index of child
3992
* @return the nth <code>Accessible</code> child of the object
3993
*/
3994
Accessible getAccessibleChild(int i) {
3995
synchronized (getTreeLock()) {
3996
Component[] children = this.getComponents();
3997
int count = 0;
3998
for (int j = 0; j < children.length; j++) {
3999
if (children[j] instanceof Accessible) {
4000
if (count == i) {
4001
return (Accessible) children[j];
4002
} else {
4003
count++;
4004
}
4005
}
4006
}
4007
return null;
4008
}
4009
}
4010
4011
// ************************** MIXING CODE *******************************
4012
4013
final void increaseComponentCount(Component c) {
4014
synchronized (getTreeLock()) {
4015
if (!c.isDisplayable()) {
4016
throw new IllegalStateException(
4017
"Peer does not exist while invoking the increaseComponentCount() method"
4018
);
4019
}
4020
4021
int addHW = 0;
4022
int addLW = 0;
4023
4024
if (c instanceof Container) {
4025
addLW = ((Container)c).numOfLWComponents;
4026
addHW = ((Container)c).numOfHWComponents;
4027
}
4028
if (c.isLightweight()) {
4029
addLW++;
4030
} else {
4031
addHW++;
4032
}
4033
4034
for (Container cont = this; cont != null; cont = cont.getContainer()) {
4035
cont.numOfLWComponents += addLW;
4036
cont.numOfHWComponents += addHW;
4037
}
4038
}
4039
}
4040
4041
final void decreaseComponentCount(Component c) {
4042
synchronized (getTreeLock()) {
4043
if (!c.isDisplayable()) {
4044
throw new IllegalStateException(
4045
"Peer does not exist while invoking the decreaseComponentCount() method"
4046
);
4047
}
4048
4049
int subHW = 0;
4050
int subLW = 0;
4051
4052
if (c instanceof Container) {
4053
subLW = ((Container)c).numOfLWComponents;
4054
subHW = ((Container)c).numOfHWComponents;
4055
}
4056
if (c.isLightweight()) {
4057
subLW++;
4058
} else {
4059
subHW++;
4060
}
4061
4062
for (Container cont = this; cont != null; cont = cont.getContainer()) {
4063
cont.numOfLWComponents -= subLW;
4064
cont.numOfHWComponents -= subHW;
4065
}
4066
}
4067
}
4068
4069
private int getTopmostComponentIndex() {
4070
checkTreeLock();
4071
if (getComponentCount() > 0) {
4072
return 0;
4073
}
4074
return -1;
4075
}
4076
4077
private int getBottommostComponentIndex() {
4078
checkTreeLock();
4079
if (getComponentCount() > 0) {
4080
return getComponentCount() - 1;
4081
}
4082
return -1;
4083
}
4084
4085
/*
4086
* This method is overriden to handle opaque children in non-opaque
4087
* containers.
4088
*/
4089
@Override
4090
final Region getOpaqueShape() {
4091
checkTreeLock();
4092
if (isLightweight() && isNonOpaqueForMixing()
4093
&& hasLightweightDescendants())
4094
{
4095
Region s = Region.EMPTY_REGION;
4096
for (int index = 0; index < getComponentCount(); index++) {
4097
Component c = getComponent(index);
4098
if (c.isLightweight() && c.isShowing()) {
4099
s = s.getUnion(c.getOpaqueShape());
4100
}
4101
}
4102
return s.getIntersection(getNormalShape());
4103
}
4104
return super.getOpaqueShape();
4105
}
4106
4107
final void recursiveSubtractAndApplyShape(Region shape) {
4108
recursiveSubtractAndApplyShape(shape, getTopmostComponentIndex(), getBottommostComponentIndex());
4109
}
4110
4111
final void recursiveSubtractAndApplyShape(Region shape, int fromZorder) {
4112
recursiveSubtractAndApplyShape(shape, fromZorder, getBottommostComponentIndex());
4113
}
4114
4115
final void recursiveSubtractAndApplyShape(Region shape, int fromZorder, int toZorder) {
4116
checkTreeLock();
4117
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4118
mixingLog.fine("this = " + this +
4119
"; shape=" + shape + "; fromZ=" + fromZorder + "; toZ=" + toZorder);
4120
}
4121
if (fromZorder == -1) {
4122
return;
4123
}
4124
if (shape.isEmpty()) {
4125
return;
4126
}
4127
// An invalid container with not-null layout should be ignored
4128
// by the mixing code, the container will be validated later
4129
// and the mixing code will be executed later.
4130
if (getLayout() != null && !isValid()) {
4131
return;
4132
}
4133
for (int index = fromZorder; index <= toZorder; index++) {
4134
Component comp = getComponent(index);
4135
if (!comp.isLightweight()) {
4136
comp.subtractAndApplyShape(shape);
4137
} else if (comp instanceof Container &&
4138
((Container)comp).hasHeavyweightDescendants() && comp.isShowing()) {
4139
((Container)comp).recursiveSubtractAndApplyShape(shape);
4140
}
4141
}
4142
}
4143
4144
final void recursiveApplyCurrentShape() {
4145
recursiveApplyCurrentShape(getTopmostComponentIndex(), getBottommostComponentIndex());
4146
}
4147
4148
final void recursiveApplyCurrentShape(int fromZorder) {
4149
recursiveApplyCurrentShape(fromZorder, getBottommostComponentIndex());
4150
}
4151
4152
final void recursiveApplyCurrentShape(int fromZorder, int toZorder) {
4153
checkTreeLock();
4154
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4155
mixingLog.fine("this = " + this +
4156
"; fromZ=" + fromZorder + "; toZ=" + toZorder);
4157
}
4158
if (fromZorder == -1) {
4159
return;
4160
}
4161
// An invalid container with not-null layout should be ignored
4162
// by the mixing code, the container will be validated later
4163
// and the mixing code will be executed later.
4164
if (getLayout() != null && !isValid()) {
4165
return;
4166
}
4167
for (int index = fromZorder; index <= toZorder; index++) {
4168
Component comp = getComponent(index);
4169
if (!comp.isLightweight()) {
4170
comp.applyCurrentShape();
4171
}
4172
if (comp instanceof Container &&
4173
((Container)comp).hasHeavyweightDescendants()) {
4174
((Container)comp).recursiveApplyCurrentShape();
4175
}
4176
}
4177
}
4178
4179
private void recursiveShowHeavyweightChildren() {
4180
if (!hasHeavyweightDescendants() || !isVisible()) {
4181
return;
4182
}
4183
for (int index = 0; index < getComponentCount(); index++) {
4184
Component comp = getComponent(index);
4185
if (comp.isLightweight()) {
4186
if (comp instanceof Container) {
4187
((Container)comp).recursiveShowHeavyweightChildren();
4188
}
4189
} else {
4190
if (comp.isVisible()) {
4191
ComponentPeer peer = comp.getPeer();
4192
if (peer != null) {
4193
peer.setVisible(true);
4194
}
4195
}
4196
}
4197
}
4198
}
4199
4200
private void recursiveHideHeavyweightChildren() {
4201
if (!hasHeavyweightDescendants()) {
4202
return;
4203
}
4204
for (int index = 0; index < getComponentCount(); index++) {
4205
Component comp = getComponent(index);
4206
if (comp.isLightweight()) {
4207
if (comp instanceof Container) {
4208
((Container)comp).recursiveHideHeavyweightChildren();
4209
}
4210
} else {
4211
if (comp.isVisible()) {
4212
ComponentPeer peer = comp.getPeer();
4213
if (peer != null) {
4214
peer.setVisible(false);
4215
}
4216
}
4217
}
4218
}
4219
}
4220
4221
private void recursiveRelocateHeavyweightChildren(Point origin) {
4222
for (int index = 0; index < getComponentCount(); index++) {
4223
Component comp = getComponent(index);
4224
if (comp.isLightweight()) {
4225
if (comp instanceof Container &&
4226
((Container)comp).hasHeavyweightDescendants())
4227
{
4228
final Point newOrigin = new Point(origin);
4229
newOrigin.translate(comp.getX(), comp.getY());
4230
((Container)comp).recursiveRelocateHeavyweightChildren(newOrigin);
4231
}
4232
} else {
4233
ComponentPeer peer = comp.getPeer();
4234
if (peer != null) {
4235
peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(),
4236
comp.getWidth(), comp.getHeight(),
4237
ComponentPeer.SET_LOCATION);
4238
}
4239
}
4240
}
4241
}
4242
4243
/**
4244
* Checks if the container and its direct lightweight containers are
4245
* visible.
4246
*
4247
* Consider the heavyweight container hides or shows the HW descendants
4248
* automatically. Therefore we care of LW containers' visibility only.
4249
*
4250
* This method MUST be invoked under the TreeLock.
4251
*/
4252
final boolean isRecursivelyVisibleUpToHeavyweightContainer() {
4253
if (!isLightweight()) {
4254
return true;
4255
}
4256
4257
for (Container cont = this;
4258
cont != null && cont.isLightweight();
4259
cont = cont.getContainer())
4260
{
4261
if (!cont.isVisible()) {
4262
return false;
4263
}
4264
}
4265
return true;
4266
}
4267
4268
@Override
4269
void mixOnShowing() {
4270
synchronized (getTreeLock()) {
4271
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4272
mixingLog.fine("this = " + this);
4273
}
4274
4275
boolean isLightweight = isLightweight();
4276
4277
if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) {
4278
recursiveShowHeavyweightChildren();
4279
}
4280
4281
if (!isMixingNeeded()) {
4282
return;
4283
}
4284
4285
if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) {
4286
recursiveApplyCurrentShape();
4287
}
4288
4289
super.mixOnShowing();
4290
}
4291
}
4292
4293
@Override
4294
void mixOnHiding(boolean isLightweight) {
4295
synchronized (getTreeLock()) {
4296
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4297
mixingLog.fine("this = " + this +
4298
"; isLightweight=" + isLightweight);
4299
}
4300
if (isLightweight) {
4301
recursiveHideHeavyweightChildren();
4302
}
4303
super.mixOnHiding(isLightweight);
4304
}
4305
}
4306
4307
@Override
4308
void mixOnReshaping() {
4309
synchronized (getTreeLock()) {
4310
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4311
mixingLog.fine("this = " + this);
4312
}
4313
4314
boolean isMixingNeeded = isMixingNeeded();
4315
4316
if (isLightweight() && hasHeavyweightDescendants()) {
4317
final Point origin = new Point(getX(), getY());
4318
for (Container cont = getContainer();
4319
cont != null && cont.isLightweight();
4320
cont = cont.getContainer())
4321
{
4322
origin.translate(cont.getX(), cont.getY());
4323
}
4324
4325
recursiveRelocateHeavyweightChildren(origin);
4326
4327
if (!isMixingNeeded) {
4328
return;
4329
}
4330
4331
recursiveApplyCurrentShape();
4332
}
4333
4334
if (!isMixingNeeded) {
4335
return;
4336
}
4337
4338
super.mixOnReshaping();
4339
}
4340
}
4341
4342
@Override
4343
void mixOnZOrderChanging(int oldZorder, int newZorder) {
4344
synchronized (getTreeLock()) {
4345
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4346
mixingLog.fine("this = " + this +
4347
"; oldZ=" + oldZorder + "; newZ=" + newZorder);
4348
}
4349
4350
if (!isMixingNeeded()) {
4351
return;
4352
}
4353
4354
boolean becameHigher = newZorder < oldZorder;
4355
4356
if (becameHigher && isLightweight() && hasHeavyweightDescendants()) {
4357
recursiveApplyCurrentShape();
4358
}
4359
super.mixOnZOrderChanging(oldZorder, newZorder);
4360
}
4361
}
4362
4363
@Override
4364
void mixOnValidating() {
4365
synchronized (getTreeLock()) {
4366
if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
4367
mixingLog.fine("this = " + this);
4368
}
4369
4370
if (!isMixingNeeded()) {
4371
return;
4372
}
4373
4374
if (hasHeavyweightDescendants()) {
4375
recursiveApplyCurrentShape();
4376
}
4377
4378
if (isLightweight() && isNonOpaqueForMixing()) {
4379
subtractAndApplyShapeBelowMe();
4380
}
4381
4382
super.mixOnValidating();
4383
}
4384
}
4385
4386
// ****************** END OF MIXING CODE ********************************
4387
}
4388
4389
4390
/**
4391
* Class to manage the dispatching of MouseEvents to the lightweight descendants
4392
* and SunDropTargetEvents to both lightweight and heavyweight descendants
4393
* contained by a native container.
4394
*
4395
* NOTE: the class name is not appropriate anymore, but we cannot change it
4396
* because we must keep serialization compatibility.
4397
*
4398
* @author Timothy Prinzing
4399
*/
4400
class LightweightDispatcher implements java.io.Serializable, AWTEventListener {
4401
4402
/*
4403
* JDK 1.1 serialVersionUID
4404
*/
4405
private static final long serialVersionUID = 5184291520170872969L;
4406
/*
4407
* Our own mouse event for when we're dragged over from another hw
4408
* container
4409
*/
4410
private static final int LWD_MOUSE_DRAGGED_OVER = 1500;
4411
4412
private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.LightweightDispatcher");
4413
4414
private static final int BUTTONS_DOWN_MASK;
4415
4416
static {
4417
int[] buttonsDownMask = AWTAccessor.getInputEventAccessor().
4418
getButtonDownMasks();
4419
int mask = 0;
4420
for (int buttonDownMask : buttonsDownMask) {
4421
mask |= buttonDownMask;
4422
}
4423
BUTTONS_DOWN_MASK = mask;
4424
}
4425
4426
LightweightDispatcher(Container nativeContainer) {
4427
this.nativeContainer = nativeContainer;
4428
mouseEventTarget = new WeakReference<>(null);
4429
targetLastEntered = new WeakReference<>(null);
4430
targetLastEnteredDT = new WeakReference<>(null);
4431
eventMask = 0;
4432
}
4433
4434
/*
4435
* Clean up any resources allocated when dispatcher was created;
4436
* should be called from Container.removeNotify
4437
*/
4438
void dispose() {
4439
//System.out.println("Disposing lw dispatcher");
4440
stopListeningForOtherDrags();
4441
mouseEventTarget.clear();
4442
targetLastEntered.clear();
4443
targetLastEnteredDT.clear();
4444
}
4445
4446
/**
4447
* Enables events to subcomponents.
4448
*/
4449
void enableEvents(long events) {
4450
eventMask |= events;
4451
}
4452
4453
/**
4454
* Dispatches an event to a sub-component if necessary, and
4455
* returns whether or not the event was forwarded to a
4456
* sub-component.
4457
*
4458
* @param e the event
4459
*/
4460
boolean dispatchEvent(AWTEvent e) {
4461
boolean ret = false;
4462
4463
/*
4464
* Fix for BugTraq Id 4389284.
4465
* Dispatch SunDropTargetEvents regardless of eventMask value.
4466
* Do not update cursor on dispatching SunDropTargetEvents.
4467
*/
4468
if (e instanceof SunDropTargetEvent) {
4469
4470
SunDropTargetEvent sdde = (SunDropTargetEvent) e;
4471
ret = processDropTargetEvent(sdde);
4472
4473
} else {
4474
if (e instanceof MouseEvent && (eventMask & MOUSE_MASK) != 0) {
4475
MouseEvent me = (MouseEvent) e;
4476
ret = processMouseEvent(me);
4477
}
4478
4479
if (e.getID() == MouseEvent.MOUSE_MOVED) {
4480
nativeContainer.updateCursorImmediately();
4481
}
4482
}
4483
4484
return ret;
4485
}
4486
4487
/* This method effectively returns whether or not a mouse button was down
4488
* just BEFORE the event happened. A better method name might be
4489
* wasAMouseButtonDownBeforeThisEvent().
4490
*/
4491
private boolean isMouseGrab(MouseEvent e) {
4492
int modifiers = e.getModifiersEx();
4493
4494
if (e.getID() == MouseEvent.MOUSE_PRESSED
4495
|| e.getID() == MouseEvent.MOUSE_RELEASED) {
4496
modifiers ^= InputEvent.getMaskForButton(e.getButton());
4497
}
4498
/* modifiers now as just before event */
4499
return ((modifiers & BUTTONS_DOWN_MASK) != 0);
4500
}
4501
4502
/**
4503
* This method attempts to distribute a mouse event to a lightweight
4504
* component. It tries to avoid doing any unnecessary probes down
4505
* into the component tree to minimize the overhead of determining
4506
* where to route the event, since mouse movement events tend to
4507
* come in large and frequent amounts.
4508
*/
4509
private boolean processMouseEvent(MouseEvent e) {
4510
int id = e.getID();
4511
Component mouseOver = // sensitive to mouse events
4512
nativeContainer.getMouseEventTarget(e.getX(), e.getY(),
4513
Container.INCLUDE_SELF);
4514
4515
trackMouseEnterExit(mouseOver, e);
4516
4517
Component met = mouseEventTarget.get();
4518
// 4508327 : MOUSE_CLICKED should only go to the recipient of
4519
// the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a
4520
// MOUSE_CLICKED.
4521
if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) {
4522
met = (mouseOver != nativeContainer) ? mouseOver : null;
4523
mouseEventTarget = new WeakReference<>(met);
4524
}
4525
4526
if (met != null) {
4527
switch (id) {
4528
case MouseEvent.MOUSE_ENTERED:
4529
case MouseEvent.MOUSE_EXITED:
4530
break;
4531
case MouseEvent.MOUSE_PRESSED:
4532
retargetMouseEvent(met, id, e);
4533
break;
4534
case MouseEvent.MOUSE_RELEASED:
4535
retargetMouseEvent(met, id, e);
4536
break;
4537
case MouseEvent.MOUSE_CLICKED:
4538
// 4508327: MOUSE_CLICKED should never be dispatched to a Component
4539
// other than that which received the MOUSE_PRESSED event. If the
4540
// mouse is now over a different Component, don't dispatch the event.
4541
// The previous fix for a similar problem was associated with bug
4542
// 4155217.
4543
if (mouseOver == met) {
4544
retargetMouseEvent(mouseOver, id, e);
4545
}
4546
break;
4547
case MouseEvent.MOUSE_MOVED:
4548
retargetMouseEvent(met, id, e);
4549
break;
4550
case MouseEvent.MOUSE_DRAGGED:
4551
if (isMouseGrab(e)) {
4552
retargetMouseEvent(met, id, e);
4553
}
4554
break;
4555
case MouseEvent.MOUSE_WHEEL:
4556
// This may send it somewhere that doesn't have MouseWheelEvents
4557
// enabled. In this case, Component.dispatchEventImpl() will
4558
// retarget the event to a parent that DOES have the events enabled.
4559
if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) {
4560
eventLog.finest("retargeting mouse wheel to " +
4561
mouseOver.getName() + ", " +
4562
mouseOver.getClass());
4563
}
4564
retargetMouseEvent(mouseOver, id, e);
4565
break;
4566
}
4567
//Consuming of wheel events is implemented in "retargetMouseEvent".
4568
if (id != MouseEvent.MOUSE_WHEEL) {
4569
e.consume();
4570
}
4571
}
4572
return e.isConsumed();
4573
}
4574
4575
private boolean processDropTargetEvent(SunDropTargetEvent e) {
4576
int id = e.getID();
4577
int x = e.getX();
4578
int y = e.getY();
4579
4580
/*
4581
* Fix for BugTraq ID 4395290.
4582
* It is possible that SunDropTargetEvent's Point is outside of the
4583
* native container bounds. In this case we truncate coordinates.
4584
*/
4585
if (!nativeContainer.contains(x, y)) {
4586
final Dimension d = nativeContainer.getSize();
4587
if (d.width <= x) {
4588
x = d.width - 1;
4589
} else if (x < 0) {
4590
x = 0;
4591
}
4592
if (d.height <= y) {
4593
y = d.height - 1;
4594
} else if (y < 0) {
4595
y = 0;
4596
}
4597
}
4598
Component mouseOver = // not necessarily sensitive to mouse events
4599
nativeContainer.getDropTargetEventTarget(x, y,
4600
Container.INCLUDE_SELF);
4601
trackMouseEnterExit(mouseOver, e);
4602
4603
if (mouseOver != nativeContainer && mouseOver != null) {
4604
switch (id) {
4605
case SunDropTargetEvent.MOUSE_ENTERED:
4606
case SunDropTargetEvent.MOUSE_EXITED:
4607
break;
4608
default:
4609
retargetMouseEvent(mouseOver, id, e);
4610
e.consume();
4611
break;
4612
}
4613
}
4614
return e.isConsumed();
4615
}
4616
4617
/*
4618
* Generates dnd enter/exit events as mouse moves over lw components
4619
* @param targetOver Target mouse is over (including native container)
4620
* @param e SunDropTarget mouse event in native container
4621
*/
4622
private void trackDropTargetEnterExit(Component targetOver, MouseEvent e) {
4623
int id = e.getID();
4624
if (id == MouseEvent.MOUSE_ENTERED && isMouseDTInNativeContainer) {
4625
// This can happen if a lightweight component which initiated the
4626
// drag has an associated drop target. MOUSE_ENTERED comes when the
4627
// mouse is in the native container already. To propagate this event
4628
// properly we should null out targetLastEntered.
4629
targetLastEnteredDT.clear();
4630
} else if (id == MouseEvent.MOUSE_ENTERED) {
4631
isMouseDTInNativeContainer = true;
4632
} else if (id == MouseEvent.MOUSE_EXITED) {
4633
isMouseDTInNativeContainer = false;
4634
}
4635
Component tle = retargetMouseEnterExit(targetOver, e,
4636
targetLastEnteredDT.get(),
4637
isMouseDTInNativeContainer);
4638
targetLastEnteredDT = new WeakReference<>(tle);
4639
}
4640
4641
/*
4642
* Generates enter/exit events as mouse moves over lw components
4643
* @param targetOver Target mouse is over (including native container)
4644
* @param e Mouse event in native container
4645
*/
4646
private void trackMouseEnterExit(Component targetOver, MouseEvent e) {
4647
if (e instanceof SunDropTargetEvent) {
4648
trackDropTargetEnterExit(targetOver, e);
4649
return;
4650
}
4651
int id = e.getID();
4652
4653
if ( id != MouseEvent.MOUSE_EXITED &&
4654
id != MouseEvent.MOUSE_DRAGGED &&
4655
id != LWD_MOUSE_DRAGGED_OVER &&
4656
!isMouseInNativeContainer) {
4657
// any event but an exit or drag means we're in the native container
4658
isMouseInNativeContainer = true;
4659
startListeningForOtherDrags();
4660
} else if (id == MouseEvent.MOUSE_EXITED) {
4661
isMouseInNativeContainer = false;
4662
stopListeningForOtherDrags();
4663
}
4664
Component tle = retargetMouseEnterExit(targetOver, e,
4665
targetLastEntered.get(),
4666
isMouseInNativeContainer);
4667
targetLastEntered = new WeakReference<>(tle);
4668
}
4669
4670
private Component retargetMouseEnterExit(Component targetOver, MouseEvent e,
4671
Component lastEntered,
4672
boolean inNativeContainer) {
4673
int id = e.getID();
4674
Component targetEnter = inNativeContainer ? targetOver : null;
4675
4676
if (lastEntered != targetEnter) {
4677
if (lastEntered != null) {
4678
retargetMouseEvent(lastEntered, MouseEvent.MOUSE_EXITED, e);
4679
}
4680
if (id == MouseEvent.MOUSE_EXITED) {
4681
// consume native exit event if we generate one
4682
e.consume();
4683
}
4684
4685
if (targetEnter != null) {
4686
retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e);
4687
}
4688
if (id == MouseEvent.MOUSE_ENTERED) {
4689
// consume native enter event if we generate one
4690
e.consume();
4691
}
4692
}
4693
return targetEnter;
4694
}
4695
4696
/*
4697
* Listens to global mouse drag events so even drags originating
4698
* from other heavyweight containers will generate enter/exit
4699
* events in this container
4700
*/
4701
private void startListeningForOtherDrags() {
4702
//System.out.println("Adding AWTEventListener");
4703
java.security.AccessController.doPrivileged(
4704
new java.security.PrivilegedAction<Object>() {
4705
public Object run() {
4706
nativeContainer.getToolkit().addAWTEventListener(
4707
LightweightDispatcher.this,
4708
AWTEvent.MOUSE_EVENT_MASK |
4709
AWTEvent.MOUSE_MOTION_EVENT_MASK);
4710
return null;
4711
}
4712
}
4713
);
4714
}
4715
4716
private void stopListeningForOtherDrags() {
4717
//System.out.println("Removing AWTEventListener");
4718
java.security.AccessController.doPrivileged(
4719
new java.security.PrivilegedAction<Object>() {
4720
public Object run() {
4721
nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this);
4722
return null;
4723
}
4724
}
4725
);
4726
}
4727
4728
/*
4729
* (Implementation of AWTEventListener)
4730
* Listen for drag events posted in other hw components so we can
4731
* track enter/exit regardless of where a drag originated
4732
*/
4733
public void eventDispatched(AWTEvent e) {
4734
boolean isForeignDrag = (e instanceof MouseEvent) &&
4735
!(e instanceof SunDropTargetEvent) &&
4736
(e.id == MouseEvent.MOUSE_DRAGGED) &&
4737
(e.getSource() != nativeContainer);
4738
4739
if (!isForeignDrag) {
4740
// only interested in drags from other hw components
4741
return;
4742
}
4743
4744
MouseEvent srcEvent = (MouseEvent)e;
4745
MouseEvent me;
4746
4747
synchronized (nativeContainer.getTreeLock()) {
4748
Component srcComponent = srcEvent.getComponent();
4749
4750
// component may have disappeared since drag event posted
4751
// (i.e. Swing hierarchical menus)
4752
if ( !srcComponent.isShowing() ) {
4753
return;
4754
}
4755
4756
// see 5083555
4757
// check if srcComponent is in any modal blocked window
4758
Component c = nativeContainer;
4759
while ((c != null) && !(c instanceof Window)) {
4760
c = c.getParent_NoClientCode();
4761
}
4762
if ((c == null) || ((Window)c).isModalBlocked()) {
4763
return;
4764
}
4765
4766
//
4767
// create an internal 'dragged-over' event indicating
4768
// we are being dragged over from another hw component
4769
//
4770
me = new MouseEvent(nativeContainer,
4771
LWD_MOUSE_DRAGGED_OVER,
4772
srcEvent.getWhen(),
4773
srcEvent.getModifiersEx() | srcEvent.getModifiers(),
4774
srcEvent.getX(),
4775
srcEvent.getY(),
4776
srcEvent.getXOnScreen(),
4777
srcEvent.getYOnScreen(),
4778
srcEvent.getClickCount(),
4779
srcEvent.isPopupTrigger(),
4780
srcEvent.getButton());
4781
MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
4782
meAccessor.setCausedByTouchEvent(me,
4783
meAccessor.isCausedByTouchEvent(srcEvent));
4784
((AWTEvent)srcEvent).copyPrivateDataInto(me);
4785
// translate coordinates to this native container
4786
final Point ptSrcOrigin = srcComponent.getLocationOnScreen();
4787
4788
if (AppContext.getAppContext() != nativeContainer.appContext) {
4789
final MouseEvent mouseEvent = me;
4790
Runnable r = new Runnable() {
4791
public void run() {
4792
if (!nativeContainer.isShowing() ) {
4793
return;
4794
}
4795
4796
Point ptDstOrigin = nativeContainer.getLocationOnScreen();
4797
mouseEvent.translatePoint(ptSrcOrigin.x - ptDstOrigin.x,
4798
ptSrcOrigin.y - ptDstOrigin.y );
4799
Component targetOver =
4800
nativeContainer.getMouseEventTarget(mouseEvent.getX(),
4801
mouseEvent.getY(),
4802
Container.INCLUDE_SELF);
4803
trackMouseEnterExit(targetOver, mouseEvent);
4804
}
4805
};
4806
SunToolkit.executeOnEventHandlerThread(nativeContainer, r);
4807
return;
4808
} else {
4809
if (!nativeContainer.isShowing() ) {
4810
return;
4811
}
4812
4813
Point ptDstOrigin = nativeContainer.getLocationOnScreen();
4814
me.translatePoint( ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y );
4815
}
4816
}
4817
//System.out.println("Track event: " + me);
4818
// feed the 'dragged-over' event directly to the enter/exit
4819
// code (not a real event so don't pass it to dispatchEvent)
4820
Component targetOver =
4821
nativeContainer.getMouseEventTarget(me.getX(), me.getY(),
4822
Container.INCLUDE_SELF);
4823
trackMouseEnterExit(targetOver, me);
4824
}
4825
4826
/**
4827
* Sends a mouse event to the current mouse event recipient using
4828
* the given event (sent to the windowed host) as a srcEvent. If
4829
* the mouse event target is still in the component tree, the
4830
* coordinates of the event are translated to those of the target.
4831
* If the target has been removed, we don't bother to send the
4832
* message.
4833
*/
4834
void retargetMouseEvent(Component target, int id, MouseEvent e) {
4835
if (target == null) {
4836
return; // mouse is over another hw component or target is disabled
4837
}
4838
4839
int x = e.getX(), y = e.getY();
4840
Component component;
4841
4842
for(component = target;
4843
component != null && component != nativeContainer;
4844
component = component.getParent()) {
4845
x -= component.x;
4846
y -= component.y;
4847
}
4848
MouseEvent retargeted;
4849
if (component != null) {
4850
if (e instanceof SunDropTargetEvent) {
4851
retargeted = new SunDropTargetEvent(target,
4852
id,
4853
x,
4854
y,
4855
((SunDropTargetEvent)e).getDispatcher());
4856
} else if (id == MouseEvent.MOUSE_WHEEL) {
4857
retargeted = new MouseWheelEvent(target,
4858
id,
4859
e.getWhen(),
4860
e.getModifiersEx() | e.getModifiers(),
4861
x,
4862
y,
4863
e.getXOnScreen(),
4864
e.getYOnScreen(),
4865
e.getClickCount(),
4866
e.isPopupTrigger(),
4867
((MouseWheelEvent)e).getScrollType(),
4868
((MouseWheelEvent)e).getScrollAmount(),
4869
((MouseWheelEvent)e).getWheelRotation(),
4870
((MouseWheelEvent)e).getPreciseWheelRotation());
4871
}
4872
else {
4873
retargeted = new MouseEvent(target,
4874
id,
4875
e.getWhen(),
4876
e.getModifiersEx() | e.getModifiers(),
4877
x,
4878
y,
4879
e.getXOnScreen(),
4880
e.getYOnScreen(),
4881
e.getClickCount(),
4882
e.isPopupTrigger(),
4883
e.getButton());
4884
MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
4885
meAccessor.setCausedByTouchEvent(retargeted,
4886
meAccessor.isCausedByTouchEvent(e));
4887
}
4888
4889
((AWTEvent)e).copyPrivateDataInto(retargeted);
4890
4891
if (target == nativeContainer) {
4892
// avoid recursively calling LightweightDispatcher...
4893
((Container)target).dispatchEventToSelf(retargeted);
4894
} else {
4895
assert AppContext.getAppContext() == target.appContext;
4896
4897
if (nativeContainer.modalComp != null) {
4898
if (((Container)nativeContainer.modalComp).isAncestorOf(target)) {
4899
target.dispatchEvent(retargeted);
4900
} else {
4901
e.consume();
4902
}
4903
} else {
4904
target.dispatchEvent(retargeted);
4905
}
4906
}
4907
if (id == MouseEvent.MOUSE_WHEEL && retargeted.isConsumed()) {
4908
//An exception for wheel bubbling to the native system.
4909
//In "processMouseEvent" total event consuming for wheel events is skipped.
4910
//Protection from bubbling of Java-accepted wheel events.
4911
e.consume();
4912
}
4913
}
4914
}
4915
4916
// --- member variables -------------------------------
4917
4918
/**
4919
* The windowed container that might be hosting events for
4920
* subcomponents.
4921
*/
4922
private Container nativeContainer;
4923
4924
/**
4925
* This variable is not used, but kept for serialization compatibility
4926
*/
4927
private Component focus;
4928
4929
/**
4930
* The current subcomponent being hosted by this windowed
4931
* component that has events being forwarded to it. If this
4932
* is null, there are currently no events being forwarded to
4933
* a subcomponent.
4934
*/
4935
private transient WeakReference<Component> mouseEventTarget;
4936
4937
/**
4938
* The last component entered by the {@code MouseEvent}.
4939
*/
4940
private transient WeakReference<Component> targetLastEntered;
4941
4942
/**
4943
* The last component entered by the {@code SunDropTargetEvent}.
4944
*/
4945
private transient WeakReference<Component> targetLastEnteredDT;
4946
4947
/**
4948
* Is the mouse over the native container.
4949
*/
4950
private transient boolean isMouseInNativeContainer = false;
4951
4952
/**
4953
* Is DnD over the native container.
4954
*/
4955
private transient boolean isMouseDTInNativeContainer = false;
4956
4957
/**
4958
* This variable is not used, but kept for serialization compatibility
4959
*/
4960
private Cursor nativeCursor;
4961
4962
/**
4963
* The event mask for contained lightweight components. Lightweight
4964
* components need a windowed container to host window-related
4965
* events. This separate mask indicates events that have been
4966
* requested by contained lightweight components without effecting
4967
* the mask of the windowed component itself.
4968
*/
4969
private long eventMask;
4970
4971
/**
4972
* The kind of events routed to lightweight components from windowed
4973
* hosts.
4974
*/
4975
private static final long PROXY_EVENT_MASK =
4976
AWTEvent.FOCUS_EVENT_MASK |
4977
AWTEvent.KEY_EVENT_MASK |
4978
AWTEvent.MOUSE_EVENT_MASK |
4979
AWTEvent.MOUSE_MOTION_EVENT_MASK |
4980
AWTEvent.MOUSE_WHEEL_EVENT_MASK;
4981
4982
private static final long MOUSE_MASK =
4983
AWTEvent.MOUSE_EVENT_MASK |
4984
AWTEvent.MOUSE_MOTION_EVENT_MASK |
4985
AWTEvent.MOUSE_WHEEL_EVENT_MASK;
4986
}
4987
4988