mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
6852592: invalidate() must be smarter
Introduce validate roots in AWT Reviewed-by: alexp, art, dcherepanov
This commit is contained in:
parent
a77b6a72e0
commit
b50342c24e
13 changed files with 355 additions and 114 deletions
|
@ -229,6 +229,21 @@ public class Applet extends Panel {
|
||||||
resize(d.width, d.height);
|
resize(d.width, d.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this container is a validate root.
|
||||||
|
* <p>
|
||||||
|
* {@code Applet} objects are the validate roots, and, therefore, they
|
||||||
|
* override this method to return {@code true}.
|
||||||
|
*
|
||||||
|
* @return {@code true}
|
||||||
|
* @since 1.7
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValidateRoot() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests that the argument string be displayed in the
|
* Requests that the argument string be displayed in the
|
||||||
* "status window". Many browsers and applet viewers
|
* "status window". Many browsers and applet viewers
|
||||||
|
|
|
@ -2764,8 +2764,11 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that this component has a valid layout. This method is
|
* Validates this component.
|
||||||
* primarily intended to operate on instances of <code>Container</code>.
|
* <p>
|
||||||
|
* The meaning of the term <i>validating</i> is defined by the ancestors of
|
||||||
|
* this class. See {@link Container#validate} for more details.
|
||||||
|
*
|
||||||
* @see #invalidate
|
* @see #invalidate
|
||||||
* @see #doLayout()
|
* @see #doLayout()
|
||||||
* @see LayoutManager
|
* @see LayoutManager
|
||||||
|
@ -2794,12 +2797,24 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidates this component. This component and all parents
|
* Invalidates this component and its ancestors.
|
||||||
* above it are marked as needing to be laid out. This method can
|
* <p>
|
||||||
* be called often, so it needs to execute quickly.
|
* All the ancestors of this component up to the nearest validate root are
|
||||||
|
* marked invalid also. If there is no a validate root container for this
|
||||||
|
* component, all of its ancestors up to the root of the hierarchy are
|
||||||
|
* marked invalid as well. Marking a container <i>invalid</i> indicates
|
||||||
|
* that the container needs to be laid out.
|
||||||
|
* <p>
|
||||||
|
* This method is called automatically when any layout-related information
|
||||||
|
* changes (e.g. setting the bounds of the component, or adding the
|
||||||
|
* component to a container).
|
||||||
|
* <p>
|
||||||
|
* This method might be called often, so it should work fast.
|
||||||
|
*
|
||||||
* @see #validate
|
* @see #validate
|
||||||
* @see #doLayout
|
* @see #doLayout
|
||||||
* @see LayoutManager
|
* @see LayoutManager
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
* @since JDK1.0
|
* @since JDK1.0
|
||||||
*/
|
*/
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
|
@ -2818,9 +2833,18 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||||
if (!isMaximumSizeSet()) {
|
if (!isMaximumSizeSet()) {
|
||||||
maxSize = null;
|
maxSize = null;
|
||||||
}
|
}
|
||||||
if (parent != null) {
|
invalidateParent();
|
||||||
parent.invalidateIfValid();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the parent of this component if any.
|
||||||
|
*
|
||||||
|
* This method MUST BE invoked under the TreeLock.
|
||||||
|
*/
|
||||||
|
void invalidateParent() {
|
||||||
|
if (parent != null) {
|
||||||
|
parent.invalidateIfValid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1492,20 +1492,59 @@ public class Container extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidates the container. The container and all parents
|
* Indicates if this container is a <i>validate root</i>.
|
||||||
* above it are marked as needing to be laid out. This method can
|
* <p>
|
||||||
* be called often, so it needs to execute quickly.
|
* Layout-related changes, such as bounds of the validate root descendants,
|
||||||
|
* do not affect the layout of the validate root parent. This peculiarity
|
||||||
|
* enables the {@code invalidate()} method to stop invalidating the
|
||||||
|
* component hierarchy when the method encounters a validate root.
|
||||||
|
* <p>
|
||||||
|
* If a component hierarchy contains validate roots, the {@code validate()}
|
||||||
|
* method must be invoked on the validate root of a previously invalidated
|
||||||
|
* component, rather than on the top-level container (such as a {@code
|
||||||
|
* Frame} object) to restore the validity of the hierarchy later.
|
||||||
|
* <p>
|
||||||
|
* The {@code Window} class and the {@code Applet} class are the validate
|
||||||
|
* roots in AWT. Swing introduces more validate roots.
|
||||||
*
|
*
|
||||||
* <p> If the {@code LayoutManager} installed on this container is
|
* @return whether this container is a validate root
|
||||||
* an instance of {@code LayoutManager2}, then
|
* @see #invalidate
|
||||||
* {@link LayoutManager2#invalidateLayout(Container)} is invoked on
|
* @see java.awt.Component#invalidate
|
||||||
* it supplying this {@code Container} as the argument.
|
* @see javax.swing.JComponent#isValidateRoot
|
||||||
|
* @see javax.swing.JComponent#revalidate
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public boolean isValidateRoot() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the parent of the container unless the container
|
||||||
|
* is a validate root.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void invalidateParent() {
|
||||||
|
if (!isValidateRoot()) {
|
||||||
|
super.invalidateParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the container.
|
||||||
|
* <p>
|
||||||
|
* If the {@code LayoutManager} installed on this container is an instance
|
||||||
|
* of the {@code LayoutManager2} interface, then
|
||||||
|
* the {@link LayoutManager2#invalidateLayout(Container)} method is invoked
|
||||||
|
* on it supplying this {@code Container} as the argument.
|
||||||
|
* <p>
|
||||||
|
* Afterwards this method marks this container invalid, and invalidates its
|
||||||
|
* ancestors. See the {@link Component#invalidate} method for more details.
|
||||||
*
|
*
|
||||||
* @see #validate
|
* @see #validate
|
||||||
* @see #layout
|
* @see #layout
|
||||||
* @see LayoutManager
|
* @see LayoutManager2
|
||||||
* @see LayoutManager2#invalidateLayout(Container)
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
LayoutManager layoutMgr = this.layoutMgr;
|
LayoutManager layoutMgr = this.layoutMgr;
|
||||||
if (layoutMgr instanceof LayoutManager2) {
|
if (layoutMgr instanceof LayoutManager2) {
|
||||||
|
@ -1518,35 +1557,39 @@ public class Container extends Component {
|
||||||
/**
|
/**
|
||||||
* Validates this container and all of its subcomponents.
|
* Validates this container and all of its subcomponents.
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>validate</code> method is used to cause a container
|
* Validating a container means laying out its subcomponents.
|
||||||
* to lay out its subcomponents again. It should be invoked when
|
* Layout-related changes, such as setting the bounds of a component, or
|
||||||
* this container's subcomponents are modified (added to or
|
* adding a component to the container, invalidate the container
|
||||||
* removed from the container, or layout-related information
|
* automatically. Note that the ancestors of the container may be
|
||||||
* changed) after the container has been displayed.
|
* invalidated also (see {@link Component#invalidate} for details.)
|
||||||
*
|
* Therefore, to restore the validity of the hierarchy, the {@code
|
||||||
* <p>If this {@code Container} is not valid, this method invokes
|
* validate()} method should be invoked on a validate root of an
|
||||||
|
* invalidated component, or on the top-most container if the hierarchy
|
||||||
|
* does not contain validate roots.
|
||||||
|
* <p>
|
||||||
|
* Validating the container may be a quite time-consuming operation. For
|
||||||
|
* performance reasons a developer may postpone the validation of the
|
||||||
|
* hierarchy till a set of layout-related operations completes, e.g. after
|
||||||
|
* adding all the children to the container.
|
||||||
|
* <p>
|
||||||
|
* If this {@code Container} is not valid, this method invokes
|
||||||
* the {@code validateTree} method and marks this {@code Container}
|
* the {@code validateTree} method and marks this {@code Container}
|
||||||
* as valid. Otherwise, no action is performed.
|
* as valid. Otherwise, no action is performed.
|
||||||
* <p>
|
|
||||||
* Note that the {@code invalidate()} method may invalidate not only the
|
|
||||||
* component it is called upon, but also the parents of the component.
|
|
||||||
* Therefore, to restore the validity of the hierarchy, the {@code
|
|
||||||
* validate()} method must be invoked on the top-most invalid container of
|
|
||||||
* the hierarchy. For performance reasons a developer may postpone the
|
|
||||||
* validation of the hierarchy till a bunch of layout-related operations
|
|
||||||
* completes, e.g. after adding all the children to the container.
|
|
||||||
*
|
*
|
||||||
* @see #add(java.awt.Component)
|
* @see #add(java.awt.Component)
|
||||||
* @see #invalidate
|
* @see #invalidate
|
||||||
|
* @see Container#isValidateRoot
|
||||||
* @see javax.swing.JComponent#revalidate()
|
* @see javax.swing.JComponent#revalidate()
|
||||||
* @see #validateTree
|
* @see #validateTree
|
||||||
*/
|
*/
|
||||||
public void validate() {
|
public void validate() {
|
||||||
/* Avoid grabbing lock unless really necessary. */
|
/* Avoid grabbing lock unless really necessary. */
|
||||||
if (!isValid()) {
|
if (!isValid() || descendUnconditionallyWhenValidating) {
|
||||||
boolean updateCur = false;
|
boolean updateCur = false;
|
||||||
synchronized (getTreeLock()) {
|
synchronized (getTreeLock()) {
|
||||||
if (!isValid() && peer != null) {
|
if ((!isValid() || descendUnconditionallyWhenValidating)
|
||||||
|
&& peer != null)
|
||||||
|
{
|
||||||
ContainerPeer p = null;
|
ContainerPeer p = null;
|
||||||
if (peer instanceof ContainerPeer) {
|
if (peer instanceof ContainerPeer) {
|
||||||
p = (ContainerPeer) peer;
|
p = (ContainerPeer) peer;
|
||||||
|
@ -1557,7 +1600,11 @@ public class Container extends Component {
|
||||||
validateTree();
|
validateTree();
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
p.endValidate();
|
p.endValidate();
|
||||||
updateCur = isVisible();
|
// Avoid updating cursor if this is an internal call.
|
||||||
|
// See validateUnconditionally() for details.
|
||||||
|
if (!descendUnconditionallyWhenValidating) {
|
||||||
|
updateCur = isVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1567,6 +1614,39 @@ public class Container extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether valid containers should also traverse their
|
||||||
|
* children and call the validateTree() method on them.
|
||||||
|
*
|
||||||
|
* Synchronization: TreeLock.
|
||||||
|
*
|
||||||
|
* The field is allowed to be static as long as the TreeLock itself is
|
||||||
|
* static.
|
||||||
|
*
|
||||||
|
* @see #validateUnconditionally()
|
||||||
|
*/
|
||||||
|
private static boolean descendUnconditionallyWhenValidating = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unconditionally validate the component hierarchy.
|
||||||
|
*/
|
||||||
|
final void validateUnconditionally() {
|
||||||
|
boolean updateCur = false;
|
||||||
|
synchronized (getTreeLock()) {
|
||||||
|
descendUnconditionallyWhenValidating = true;
|
||||||
|
|
||||||
|
validate();
|
||||||
|
if (peer instanceof ContainerPeer) {
|
||||||
|
updateCur = isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
descendUnconditionallyWhenValidating = false;
|
||||||
|
}
|
||||||
|
if (updateCur) {
|
||||||
|
updateCursorImmediately();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively descends the container tree and recomputes the
|
* Recursively descends the container tree and recomputes the
|
||||||
* layout for any subtrees marked as needing it (those marked as
|
* layout for any subtrees marked as needing it (those marked as
|
||||||
|
@ -1578,16 +1658,20 @@ public class Container extends Component {
|
||||||
*/
|
*/
|
||||||
protected void validateTree() {
|
protected void validateTree() {
|
||||||
checkTreeLock();
|
checkTreeLock();
|
||||||
if (!isValid()) {
|
if (!isValid() || descendUnconditionallyWhenValidating) {
|
||||||
if (peer instanceof ContainerPeer) {
|
if (peer instanceof ContainerPeer) {
|
||||||
((ContainerPeer)peer).beginLayout();
|
((ContainerPeer)peer).beginLayout();
|
||||||
}
|
}
|
||||||
doLayout();
|
if (!isValid()) {
|
||||||
|
doLayout();
|
||||||
|
}
|
||||||
for (int i = 0; i < component.size(); i++) {
|
for (int i = 0; i < component.size(); i++) {
|
||||||
Component comp = component.get(i);
|
Component comp = component.get(i);
|
||||||
if ( (comp instanceof Container)
|
if ( (comp instanceof Container)
|
||||||
&& !(comp instanceof Window)
|
&& !(comp instanceof Window)
|
||||||
&& !comp.isValid()) {
|
&& (!comp.isValid() ||
|
||||||
|
descendUnconditionallyWhenValidating))
|
||||||
|
{
|
||||||
((Container)comp).validateTree();
|
((Container)comp).validateTree();
|
||||||
} else {
|
} else {
|
||||||
comp.validate();
|
comp.validate();
|
||||||
|
|
|
@ -767,7 +767,7 @@ public class Window extends Container implements Accessible {
|
||||||
isPacked = true;
|
isPacked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate();
|
validateUnconditionally();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -943,7 +943,7 @@ public class Window extends Container implements Accessible {
|
||||||
if (peer == null) {
|
if (peer == null) {
|
||||||
addNotify();
|
addNotify();
|
||||||
}
|
}
|
||||||
validate();
|
validateUnconditionally();
|
||||||
|
|
||||||
isInShow = true;
|
isInShow = true;
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
@ -2599,6 +2599,21 @@ public class Window extends Container implements Accessible {
|
||||||
super.addPropertyChangeListener(propertyName, listener);
|
super.addPropertyChangeListener(propertyName, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this container is a validate root.
|
||||||
|
* <p>
|
||||||
|
* {@code Window} objects are the validate roots, and, therefore, they
|
||||||
|
* override this method to return {@code true}.
|
||||||
|
*
|
||||||
|
* @return {@code true}
|
||||||
|
* @since 1.7
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValidateRoot() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an event to this window or one of its sub components.
|
* Dispatches an event to this window or one of its sub components.
|
||||||
* @param e the event
|
* @param e the event
|
||||||
|
|
|
@ -4878,7 +4878,9 @@ public abstract class JComponent extends Container implements Serializable,
|
||||||
* @see #revalidate
|
* @see #revalidate
|
||||||
* @see java.awt.Component#invalidate
|
* @see java.awt.Component#invalidate
|
||||||
* @see java.awt.Container#validate
|
* @see java.awt.Container#validate
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isValidateRoot() {
|
public boolean isValidateRoot() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -725,8 +725,10 @@ public class JRootPane extends JComponent implements Accessible {
|
||||||
* because both classes override <code>isValidateRoot</code> to return true.
|
* because both classes override <code>isValidateRoot</code> to return true.
|
||||||
*
|
*
|
||||||
* @see JComponent#isValidateRoot
|
* @see JComponent#isValidateRoot
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
* @return true
|
* @return true
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isValidateRoot() {
|
public boolean isValidateRoot() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,10 +453,12 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce
|
||||||
* @see java.awt.Container#validate
|
* @see java.awt.Container#validate
|
||||||
* @see JComponent#revalidate
|
* @see JComponent#revalidate
|
||||||
* @see JComponent#isValidateRoot
|
* @see JComponent#isValidateRoot
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
*
|
*
|
||||||
* @beaninfo
|
* @beaninfo
|
||||||
* hidden: true
|
* hidden: true
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isValidateRoot() {
|
public boolean isValidateRoot() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -947,10 +947,12 @@ public class JSplitPane extends JComponent implements Accessible
|
||||||
*
|
*
|
||||||
* @return true
|
* @return true
|
||||||
* @see JComponent#revalidate
|
* @see JComponent#revalidate
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
*
|
*
|
||||||
* @beaninfo
|
* @beaninfo
|
||||||
* hidden: true
|
* hidden: true
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isValidateRoot() {
|
public boolean isValidateRoot() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,7 +288,9 @@ public class JTextField extends JTextComponent implements SwingConstants {
|
||||||
*
|
*
|
||||||
* @see JComponent#revalidate
|
* @see JComponent#revalidate
|
||||||
* @see JComponent#isValidateRoot
|
* @see JComponent#isValidateRoot
|
||||||
|
* @see java.awt.Container#isValidateRoot
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isValidateRoot() {
|
public boolean isValidateRoot() {
|
||||||
return SwingUtilities2.getViewport(this) == null;
|
return SwingUtilities2.getViewport(this) == null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -469,49 +469,12 @@ public class JViewport extends JComponent implements Accessible
|
||||||
* is the synchronous version of a <code>revalidate</code>.
|
* is the synchronous version of a <code>revalidate</code>.
|
||||||
*/
|
*/
|
||||||
private void validateView() {
|
private void validateView() {
|
||||||
Component validateRoot = null;
|
Component validateRoot = SwingUtilities.getValidateRoot(this, false);
|
||||||
|
|
||||||
/* Find the first JComponent ancestor of this component whose
|
|
||||||
* isValidateRoot() method returns true.
|
|
||||||
*/
|
|
||||||
for(Component c = this; c != null; c = c.getParent()) {
|
|
||||||
if ((c instanceof CellRendererPane) || (c.getPeer() == null)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((c instanceof JComponent) &&
|
|
||||||
(((JComponent)c).isValidateRoot())) {
|
|
||||||
validateRoot = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no validateRoot, nothing to validate from.
|
|
||||||
if (validateRoot == null) {
|
if (validateRoot == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure all ancestors are visible.
|
|
||||||
Component root = null;
|
|
||||||
|
|
||||||
for(Component c = validateRoot; c != null; c = c.getParent()) {
|
|
||||||
// We don't check isVisible here, otherwise if the component
|
|
||||||
// is contained in something like a JTabbedPane when the
|
|
||||||
// component is made visible again it won't have scrolled
|
|
||||||
// to the correct location.
|
|
||||||
if (c.getPeer() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((c instanceof Window) || (c instanceof Applet)) {
|
|
||||||
root = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure there is a Window ancestor.
|
|
||||||
if (root == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the root.
|
// Validate the root.
|
||||||
validateRoot.validate();
|
validateRoot.validate();
|
||||||
|
|
||||||
|
|
|
@ -310,47 +310,13 @@ public class RepaintManager
|
||||||
delegate.addInvalidComponent(invalidComponent);
|
delegate.addInvalidComponent(invalidComponent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Component validateRoot = null;
|
Component validateRoot =
|
||||||
|
SwingUtilities.getValidateRoot(invalidComponent, true);
|
||||||
|
|
||||||
/* Find the first JComponent ancestor of this component whose
|
|
||||||
* isValidateRoot() method returns true.
|
|
||||||
*/
|
|
||||||
for(Component c = invalidComponent; c != null; c = c.getParent()) {
|
|
||||||
if ((c instanceof CellRendererPane) || (c.getPeer() == null)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((c instanceof JComponent) && (((JComponent)c).isValidateRoot())) {
|
|
||||||
validateRoot = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There's no validateRoot to apply validate to, so we're done.
|
|
||||||
*/
|
|
||||||
if (validateRoot == null) {
|
if (validateRoot == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the validateRoot and all of its ancestors aren't visible
|
|
||||||
* then we don't do anything. While we're walking up the tree
|
|
||||||
* we find the root Window or Applet.
|
|
||||||
*/
|
|
||||||
Component root = null;
|
|
||||||
|
|
||||||
for(Component c = validateRoot; c != null; c = c.getParent()) {
|
|
||||||
if (!c.isVisible() || (c.getPeer() == null)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((c instanceof Window) || (c instanceof Applet)) {
|
|
||||||
root = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lazily create the invalidateComponents vector and add the
|
/* Lazily create the invalidateComponents vector and add the
|
||||||
* validateRoot if it's not there already. If this validateRoot
|
* validateRoot if it's not there already. If this validateRoot
|
||||||
* is already in the vector, we're done.
|
* is already in the vector, we're done.
|
||||||
|
|
|
@ -1967,4 +1967,54 @@ public class SwingUtilities implements SwingConstants
|
||||||
SwingUtilities.updateComponentTreeUI(component);
|
SwingUtilities.updateComponentTreeUI(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the validate root of a given container.
|
||||||
|
*
|
||||||
|
* If the container is contained within a {@code CellRendererPane}, this
|
||||||
|
* method returns {@code null} due to the synthetic nature of the {@code
|
||||||
|
* CellRendererPane}.
|
||||||
|
* <p>
|
||||||
|
* The component hierarchy must be displayable up to the toplevel component
|
||||||
|
* (either a {@code Frame} or an {@code Applet} object.) Otherwise this
|
||||||
|
* method returns {@code null}.
|
||||||
|
* <p>
|
||||||
|
* If the {@code visibleOnly} argument is {@code true}, the found validate
|
||||||
|
* root and all its parents up to the toplevel component must also be
|
||||||
|
* visible. Otherwise this method returns {@code null}.
|
||||||
|
*
|
||||||
|
* @return the validate root of the given container or null
|
||||||
|
* @see java.awt.Component#isDisplayable()
|
||||||
|
* @see java.awt.Component#isVisible()
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
static Container getValidateRoot(Container c, boolean visibleOnly) {
|
||||||
|
Container root = null;
|
||||||
|
|
||||||
|
for (; c != null; c = c.getParent())
|
||||||
|
{
|
||||||
|
if (!c.isDisplayable() || c instanceof CellRendererPane) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (c.isValidateRoot()) {
|
||||||
|
root = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; c != null; c = c.getParent()) {
|
||||||
|
if (!c.isDisplayable() || (visibleOnly && !c.isVisible())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (c instanceof Window || c instanceof Applet) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
@test
|
||||||
|
@bug 6852592
|
||||||
|
@summary invalidate() must stop when it encounters a validate root
|
||||||
|
@author anthony.petrov@sun.com
|
||||||
|
@run main InvalidateMustRespectValidateRoots
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
|
||||||
|
public class InvalidateMustRespectValidateRoots {
|
||||||
|
private static volatile JRootPane rootPane;
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
SwingUtilities.invokeAndWait(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
// The JRootPane is a validate root. We'll check if
|
||||||
|
// invalidate() stops on the root pane, or goes further
|
||||||
|
// up to the frame.
|
||||||
|
JFrame frame = new JFrame();
|
||||||
|
final JButton button = new JButton();
|
||||||
|
|
||||||
|
frame.add(button);
|
||||||
|
|
||||||
|
// To enable running the test manually: use the Ctrl-Shift-F1
|
||||||
|
// to print the component hierarchy to the console
|
||||||
|
button.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent ev) {
|
||||||
|
if (button.isValid()) {
|
||||||
|
button.invalidate();
|
||||||
|
} else {
|
||||||
|
button.revalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rootPane = frame.getRootPane();
|
||||||
|
|
||||||
|
// Now the component hierarchy looks like:
|
||||||
|
// frame
|
||||||
|
// --> rootPane
|
||||||
|
// --> layered pane
|
||||||
|
// --> content pane
|
||||||
|
// --> button
|
||||||
|
|
||||||
|
// Make all components valid first via showing the frame
|
||||||
|
// We have to make the frame visible. Otherwise revalidate() is
|
||||||
|
// useless (see RepaintManager.addInvalidComponent()).
|
||||||
|
frame.pack(); // To enable running this test manually
|
||||||
|
frame.setVisible(true);
|
||||||
|
|
||||||
|
if (!frame.isValid()) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"setVisible(true) failed to validate the frame");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now invalidate the button
|
||||||
|
button.invalidate();
|
||||||
|
|
||||||
|
// Check if the 'valid' status is what we expect it to be
|
||||||
|
if (rootPane.isValid()) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"invalidate() failed to invalidate the root pane");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frame.isValid()) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"invalidate() invalidated the frame");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now validate the hierarchy again
|
||||||
|
button.revalidate();
|
||||||
|
|
||||||
|
// Now let the validation happen on the EDT
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
SwingUtilities.invokeAndWait(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
// Check if the root pane finally became valid
|
||||||
|
if (!rootPane.isValid()) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"revalidate() failed to validate the hierarchy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue