package org.simantics.browsing.ui.nattable;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.simantics.browsing.ui.GraphExplorer;
import org.simantics.utils.ui.AdaptionUtils;
/**
* Selects tree items based on pressed key events.
*
*
* @author Marko Luukkainen
*
*/
public class KeyToSelectionAdapter extends KeyAdapter {
private static final int KEY_INPUT_DELAY = 500;
private final NatTableGraphExplorer explorer;
private String matcher = "";
private int prevEvent = 0;
private int columns = 0;
protected Pattern alphaNum;
/**
* @param contextProvider
* @param explorer
*/
public KeyToSelectionAdapter(GraphExplorer explorer) {
assert explorer != null;
this.explorer = (NatTableGraphExplorer)explorer;
this.alphaNum = Pattern.compile("\\p{Alnum}");
}
@Override
public void keyPressed(KeyEvent e) {
if (explorer.isDisposed())
return;
if (!alphaNum.matcher(Character.toString(e.character)).matches())
return;
// concatenate / replace matcher.
if ((e.time - prevEvent) > KEY_INPUT_DELAY )
matcher = "";
prevEvent = e.time;
matcher = matcher += Character.toString(e.character);
NatTable tree = explorer.getControl();
columns = explorer.getColumns().length;
IStructuredSelection sel = (IStructuredSelection)explorer.getWidgetSelection();
Collection selected = AdaptionUtils.adaptToCollection(sel, RowSelectionItem.class);
TreeNode item = find(tree, selected);
if (item == null && matcher.length() > 1) {
matcher = matcher.substring(matcher.length()-1);
item = find(tree, selected);
}
if (item != null) {
explorer.select(item);
explorer.show(item);
}
// without this the default handling would take over.
e.doit = false;
}
private TreeNode previous = null;
private boolean foundPrev = false;
private TreeNode find(NatTable tree, Collection selected) {
TreeNode item = null;
List items = explorer.getItems();
if (selected.size() == 0) {
previous = null;
foundPrev = true;
item = findItem(items);
} else {
previous = selected.iterator().next().item;
foundPrev = false;
item = findItem(items);
if (item == null) {
previous = null;
foundPrev = true;
item = findItem(items);
}
}
return item;
}
private TreeNode findItem(List items) {
for (int i = 0; i < items.size(); i++) {
TreeNode item = items.get(i);
if (item != previous) {
if (foundPrev && matches(item, columns, matcher))
return item;
} else {
foundPrev = true;
}
}
return null;
}
/**
*
* @param item
* @param depth Depth of the item in the tree.
* @param columns Number of columns.
* @param string Matching string.
* @return
*/
protected boolean matches(TreeNode item, int columns, String matcher) {
for (int c = 0; c < columns; c++) {
if (matchesColumn(item, c, matcher)) {
return true;
}
}
return false;
}
/**
*
* @param item
* @param column
* @param matcher
* @return
*/
protected boolean matchesColumn(TreeNode item, int column, String matcher) {
String text = item.getValueString(column);
if (text.toLowerCase().startsWith(matcher)) {
return true;
}
return false;
}
}