blob: 61056d0030ecd54f8feefb5fbaee2e9f9059aa57 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.draw2d;
import java.util.List;
/**
* This class is a helper to the {@link SWTEventDispatcher}. It handles the task
* of determining which Figure will gain focus upon a tab/shift-tab. It also
* keeps track of the Figure with current focus.
* <p>
* Note: When a Canvas with a {@link LightweightSystem} gains focus, it gives
* focus to the child Figure who had focus when this Canvas lost focus. If the
* canvas is gaining focus for the first time, focus is given to its first child
* Figure.
*/
public class FocusTraverseManager {
IFigure currentFocusOwner;
/**
* Default constructor.
*/
public FocusTraverseManager() {
}
private IFigure findDeepestRightmostChildOf(IFigure fig) {
while (fig.getChildren().size() != 0) {
fig = (IFigure) fig.getChildren().get(fig.getChildren().size() - 1);
}
return fig;
}
/**
* Returns the IFigure that will receive focus upon a 'tab' traverse event.
*
* @param root
* the {@link LightweightSystem LightweightSystem's} root figure
* @param prevFocus
* the IFigure who currently owns focus
* @return the next focusable figure
*/
public IFigure getNextFocusableFigure(IFigure root, IFigure prevFocus) {
boolean found = false;
IFigure nextFocus = prevFocus;
/*
* If no Figure currently has focus, apply focus to root's first
* focusable child.
*/
if (prevFocus == null) {
if (root.getChildren().size() != 0) {
nextFocus = ((IFigure) root.getChildren().get(0));
if (isFocusEligible(nextFocus))
return nextFocus;
} else
return null;
}
int siblingPos = nextFocus.getParent().getChildren().indexOf(nextFocus);
while (!found) {
IFigure parent = nextFocus.getParent();
/*
* Figure traversal is implemented using the pre-order left to right
* tree traversal algorithm.
*
* If the focused sibling has children, traverse to its leftmost
* child. If the focused sibling has no children, traverse to the
* sibling to its right. If there is no sibling to the right, go up
* the tree until a node with un-traversed siblings is found.
*/
List siblings = parent.getChildren();
if (nextFocus.getChildren().size() != 0) {
nextFocus = (IFigure) nextFocus.getChildren().get(0);
siblingPos = 0;
if (isFocusEligible(nextFocus))
found = true;
} else if (siblingPos < siblings.size() - 1) {
nextFocus = ((IFigure) (siblings.get(++siblingPos)));
if (isFocusEligible(nextFocus))
found = true;
} else {
boolean untraversedSiblingFound = false;
while (!untraversedSiblingFound) {
IFigure p = nextFocus.getParent();
IFigure gp = p.getParent();
if (gp != null) {
int parentSiblingCount = gp.getChildren().size();
int parentIndex = gp.getChildren().indexOf(p);
if (parentIndex < parentSiblingCount - 1) {
nextFocus = ((IFigure) p.getParent().getChildren()
.get(parentIndex + 1));
siblingPos = parentIndex + 1;
untraversedSiblingFound = true;
if (isFocusEligible(nextFocus))
found = true;
} else
nextFocus = p;
} else {
nextFocus = null;
untraversedSiblingFound = true;
found = true;
}
}
}
}
return nextFocus;
}
/**
* Returns the IFigure that will receive focus upon a 'shift-tab' traverse
* event.
*
* @param root
* The {@link LightweightSystem LightweightSystem's} root figure
* @param prevFocus
* The IFigure who currently owns focus
* @return the previous focusable figure
*/
public IFigure getPreviousFocusableFigure(IFigure root, IFigure prevFocus) {
if (prevFocus == null)
return null;
boolean found = false;
IFigure nextFocus = prevFocus;
while (!found) {
IFigure parent = nextFocus.getParent();
/*
* At root, return null to indicate traversal is complete.
*/
if (parent == null)
return null;
List siblings = parent.getChildren();
int siblingPos = siblings.indexOf(nextFocus);
/*
* Figure traversal is implemented using the post-order right to
* left tree traversal algorithm.
*
* Find the rightmost child. If this child is focusable, return it
* If not focusable, traverse to its sibling and repeat. If there is
* no sibling, traverse its parent.
*/
if (siblingPos != 0) {
IFigure child = findDeepestRightmostChildOf((IFigure) siblings
.get(siblingPos - 1));
if (isFocusEligible(child)) {
found = true;
nextFocus = child;
} else if (child.equals(nextFocus)) {
if (isFocusEligible(nextFocus))
found = true;
} else
nextFocus = child;
} else {
nextFocus = parent;
if (isFocusEligible(nextFocus))
found = true;
}
}
return nextFocus;
}
/**
* @return the figure that currently has focus
*/
public IFigure getCurrentFocusOwner() {
return currentFocusOwner;
}
private boolean isFocusEligible(IFigure fig) {
return (fig != null && fig.isFocusTraversable() && fig.isShowing());
}
/**
* Sets the currently focused figure.
*
* @param fig
* the figure to get focus
*/
public void setCurrentFocusOwner(IFigure fig) {
currentFocusOwner = fig;
}
}