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