/*******************************************************************************
* Copyright (c) 2016 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.foundation.ui.widget;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* A utility for all tasks that may require logic for visiting controls,
* composites, or other widgets.
*/
public class WidgetVisitorUtility {
public static final int DEPTH_FIRST = 1;
public static final int BREADTH_FIRST = 2;
private int traversal;
private boolean visitRoot;
/**
* Uses a breadth-first traversal that does visit the root element
*/
public WidgetVisitorUtility() {
this(BREADTH_FIRST);
}
/**
* Uses an arbitrary traversal that does visit the root element
*
* @param traversal One of DEPTH_FIRST or BREADTH_FIRST
*/
public WidgetVisitorUtility(int traversal) {
this(traversal, true);
}
/**
* Uses a breadth-first traversal that may or may not visit the root element
*
* @param visitRoot Whether to visit the root element
*/
public WidgetVisitorUtility(boolean visitRoot) {
this(BREADTH_FIRST, visitRoot);
}
/**
* Create a visitor utility using a traversal type as provided,
* and visiting root element as provided.
*
* @param traversal
* @param visitRoot
*/
public WidgetVisitorUtility(int traversal, boolean visitRoot) {
this.traversal = traversal;
this.visitRoot = visitRoot;
}
/**
* Optionally enable or disable all children (recursive) of this composite
* @param enabled
* @param composite
*/
public void setEnablementRecursive(final Composite composite, final boolean enabled) {
accept(composite, new IWidgetVisitor() {
@Override
public boolean visit(Control control) {
if(!control.isDisposed()) {
control.setEnabled(enabled);
}
return true;
}
});
}
public void setEnablementRecursive(final Composite composite, final boolean enabled, Control[] ignored) {
if( ignored == null ) {
setEnablementRecursive(composite, enabled);
return;
}
boolean[] status = new boolean[ignored.length];
if( status != null ) {
for( int i = 0; i < status.length; i++ ) {
status[i] = ignored[i].getEnabled();
}
}
setEnablementRecursive(composite, enabled);
for( int i = 0; i < ignored.length; i++ ) {
ignored[i].setEnabled(status[i]);
if( status[i] ) {
// if this 'ignored' should be enabled, set all parents as enabled too
Composite c = ignored[i].getParent();
while( c != null ) {
if( !c.isDisposed()) {
c.setEnabled(true);
c = c.getParent();
}
}
}
}
}
/**
* Accepts the given visitor.
*
* The visitor's <code>visit</code> method is called on the given composite first.
*
* The list of children for the given composite will then be visited.
* If the <code>visit</code> method returns true for a given child
* widget, and that widget is also a composite, the <code>accept</code>
* method will be called on all children of that composite as well.
*
* This is a shortcut accept(visitor, composite, false)
*
* @param composite The composite to visit
* @param visitor The visitor
*/
public void accept(Composite composite, IWidgetVisitor visitor) {
accept(composite, visitor, (traversal == DEPTH_FIRST), visitRoot);
}
/**
* Accepts the given visitor.
*
* The visitor's <code>visit</code> method is called on the given composite first,
* or last, depending on the value of <code>depthFirst</code>. This will not occur
* if <code>visitRoot</code> is set to <code>false</code>
*
* The list of children for the given composite will then be visited.
* If the <code>visit</code> method returns true for a given child
* widget, and that widget is also a composite, the <code>accept</code>
* method will be called on all children of that composite as well.
*
* @param composite The composite to visit
* @param visitor The visitor
* @param depthFirst Whether to perform depth first or not
* @param visitRoot Whether to visit the parent or to proceed directly to the children
*/
private void accept(Composite composite, IWidgetVisitor visitor, boolean depthFirst, boolean visitRoot) {
if (composite == null || composite.isDisposed()) {
// Do not visit children if parent is disposed or null,
// but do continue with siblings
return;
}
Control children[] = composite.getChildren();
boolean traverseChildren = true;
if (!depthFirst && visitRoot)
traverseChildren = visitor.visit(composite);
if (traverseChildren) {
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Composite) {
accept(((Composite)children[i]), visitor, depthFirst, true);
} else {
visitor.visit(children[i]);
}
}
}
if (depthFirst && visitRoot)
visitor.visit(composite);
}
}