Project: bndtools
package bndtools.editor.common;
 
import org.eclipse.jface.viewers.CellEditor; 
import org.eclipse.jface.viewers.IStructuredSelection; 
import org.eclipse.jface.viewers.TableViewer; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.events.KeyAdapter; 
import org.eclipse.swt.events.KeyEvent; 
import org.eclipse.swt.events.TraverseEvent; 
import org.eclipse.swt.events.TraverseListener; 
import org.eclipse.swt.widgets.Table; 
 
/**
 * Well ... the JFace <CODE>TableViewer<CODE> class does not provide 
 * text celleditor keyboard support like if TAB is pressed in a column, 
 * the focus does not go into the next column etc., 
 *  
 * After observing JDT method signature refactoring widget which does the 
 * desired keyboard support, a generic utility listener has been developed 
 * on the same lines. 
 *  
 * Usage goes as ... 
 *  
 * <P><PRE><CODE> 
 *  
 *   TableViewer tblViewer = new TableViewer(SWT.SINGLE | SWT.FULL_SELECTION | SWT.| SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER) 
 *   ... 
 *   CellEditor[] cellEditors = ... 
 *   ... 
 *   tblViewer.setCellEditors(cellEditors); 
 *    
 *   TableViewerKeyBoardSupporter supporter = new TableViewerKeyBoardSupporter(tblViewer); 
 *   supporter.startSupport(); 
 *   
 * </CODE></PRE></P> 
 */
 
public class TableViewerKeyBoardSupporter { 
    protected TableViewer fTableViewer = null
 
    public TableViewerKeyBoardSupporter(TableViewer tableViewer) { 
        fTableViewer = tableViewer; 
    } 
 
    /**
     * After the cell editors have been set on tableviewer, this method should be called to start giving keyboard 
     * support. 
     */
 
    public void startSupport() { 
        /* add table key listener */ 
        getTable().addKeyListener(new TableKeyListener(this)); 
 
        /* add table traverse listener */ 
        getTable().addTraverseListener(new TableTraverseListener(this)); 
 
        /* add table-textcelleditors key and traverse listeners */ 
        CellEditor[] cellEditors = fTableViewer.getCellEditors(); 
        if (cellEditors != null) { 
            for (int colIndex = 0; colIndex < cellEditors.length; colIndex++) { 
                CellEditor cellEditor = cellEditors[colIndex]; 
                if (cellEditor != null) { 
                    // cellEditor.getControl().addKeyListener(new 
                    // CellEditorKeyListener(this, cellEditor, colIndex)); 
                    cellEditor.getControl().addTraverseListener(new CellEditorTraverseListener(this, cellEditor, colIndex)); 
                } 
            } 
        } 
    } 
 
    protected TableViewer getTableViewer() { 
        return fTableViewer; 
    } 
 
    protected Table getTable() { 
        return fTableViewer.getTable(); 
    } 
 
    protected int nextColumn(int column) { 
        return (column >= getTable().getColumnCount() - 1) ? 0 : column + 1
    } 
 
    protected int prevColumn(int column) { 
        return (column <= 0) ? getTable().getColumnCount() - 1 : column - 1
    } 
 
    protected void editColumnOrNextPossible(final int column) { 
        Object selectedElem = getSelectedElement(); 
        if (selectedElem == null
            return
 
        int nextColumn = column; 
        do { 
            fTableViewer.editElement(selectedElem, nextColumn); 
            if (fTableViewer.isCellEditorActive()) 
                return
            nextColumn = nextColumn(nextColumn); 
        } while (nextColumn != column); 
    } 
 
    protected void editColumnOrPrevPossible(int column) { 
        Object selectedElem = getSelectedElement(); 
        if (selectedElem == null
            return
 
        int prevColumn = column; 
        do { 
            fTableViewer.editElement(selectedElem, prevColumn); 
            if (fTableViewer.isCellEditorActive()) 
                return
            prevColumn = prevColumn(prevColumn); 
        } while (prevColumn != column); 
    } 
 
    private Object getSelectedElement() { 
        IStructuredSelection selection = (IStructuredSelection) fTableViewer.getSelection(); 
        if (selection == null || selection.isEmpty()) 
            return null
 
        return selection.getFirstElement(); 
    } 
 
class CellEditorKeyListener extends KeyAdapter { 
    private TableViewerKeyBoardSupporter fKeyBoardSupporter = null
    private CellEditor fEditor = null
    private int fEditorColumn = -1
 
    public CellEditorKeyListener(TableViewerKeyBoardSupporter keyBoardSupporter, CellEditor editor, int editorColumn) { 
        fKeyBoardSupporter = keyBoardSupporter; 
        fEditor = editor; 
        fEditorColumn = editorColumn; 
    } 
 
    @Override 
    public void keyPressed(KeyEvent e) { 
        if (e.stateMask == SWT.MOD1 || e.stateMask == SWT.MOD2) { 
            if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN) { 
                // allow starting multi-selection even if in edit mode 
                fEditor.deactivate(); 
                e.doit = false
                return
            } 
        } 
 
        if (e.stateMask != SWT.NONE) 
            return
 
        switch (e.keyCode) { 
        case SWT.ARROW_DOWN : 
            e.doit = false
            int nextRow = fKeyBoardSupporter.getTable().getSelectionIndex() + 1
            if (nextRow >= fKeyBoardSupporter.getTable().getItemCount()) 
                break
            fKeyBoardSupporter.getTable().setSelection(nextRow); 
            fKeyBoardSupporter.editColumnOrPrevPossible(fEditorColumn); 
            break
 
        case SWT.ARROW_UP : 
            e.doit = false
            int prevRow = fKeyBoardSupporter.getTable().getSelectionIndex() - 1
            if (prevRow < 0
                break
            fKeyBoardSupporter.getTable().setSelection(prevRow); 
            fKeyBoardSupporter.editColumnOrPrevPossible(fEditorColumn); 
            break
 
        case SWT.F2 : 
            e.doit = false
            fEditor.deactivate(); 
            break
 
        default : 
            break
        } 
    } 
 
class CellEditorTraverseListener implements TraverseListener { 
    private TableViewerKeyBoardSupporter fKeyBoardSupporter = null
    private CellEditor fEditor = null
    private int fEditorColumn = -1
 
    public CellEditorTraverseListener(TableViewerKeyBoardSupporter keyBoardSupporter, CellEditor editor, int editorColumn) { 
        fKeyBoardSupporter = keyBoardSupporter; 
        fEditor = editor; 
        fEditorColumn = editorColumn; 
    } 
 
    /*
     * (non-Javadoc) 
     * @see org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse.swt. events.TraverseEvent) 
     */
 
    public void keyTraversed(TraverseEvent e) { 
 
        switch (e.detail) { 
        case SWT.TRAVERSE_TAB_NEXT : 
            fKeyBoardSupporter.editColumnOrNextPossible(fKeyBoardSupporter.nextColumn(fEditorColumn)); 
            e.detail = SWT.TRAVERSE_NONE; 
            break
 
        case SWT.TRAVERSE_TAB_PREVIOUS : 
            fKeyBoardSupporter.editColumnOrPrevPossible(fKeyBoardSupporter.prevColumn(fEditorColumn)); 
            e.detail = SWT.TRAVERSE_NONE; 
            break
 
        case SWT.TRAVERSE_ESCAPE : 
            fKeyBoardSupporter.getTableViewer().cancelEditing(); 
            e.detail = SWT.TRAVERSE_NONE; 
            break
 
        case SWT.TRAVERSE_RETURN : 
            fEditor.deactivate(); 
            e.detail = SWT.TRAVERSE_NONE; 
            break
 
        default : 
            break
        } 
    } 
 
class TableTraverseListener implements TraverseListener { 
    private TableViewerKeyBoardSupporter fKeyBoardSupporter = null
 
    public TableTraverseListener(TableViewerKeyBoardSupporter keyBoardSupporter) { 
        fKeyBoardSupporter = keyBoardSupporter; 
    } 
 
    /*
     * (non-Javadoc) 
     * @see org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse.swt. events.TraverseEvent) 
     */
 
    public void keyTraversed(TraverseEvent e) { 
        if (e.detail == SWT.TRAVERSE_RETURN && e.stateMask == SWT.NONE) { 
            fKeyBoardSupporter.editColumnOrNextPossible(0); 
            e.detail = SWT.TRAVERSE_NONE; 
        } 
    } 
 
class TableKeyListener extends KeyAdapter { 
    private TableViewerKeyBoardSupporter fKeyBoardSupporter = null
 
    public TableKeyListener(TableViewerKeyBoardSupporter keyBoardSupporter) { 
        fKeyBoardSupporter = keyBoardSupporter; 
    } 
 
    /*
     * (non-Javadoc) 
     * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events. KeyEvent) 
     */
 
    @Override 
    public void keyPressed(KeyEvent e) { 
        if (e.keyCode == SWT.F2 && e.stateMask == SWT.NONE) { 
            fKeyBoardSupporter.editColumnOrNextPossible(0); 
            e.doit = false
        } 
    } 
}