Question

I am developing an e4 RCP application, using Eclipse 4.2 RC1.

I have a control (Composite) that contains a number of TableViewers. The viewers are arranged vertically. If the user hits the down arrow when the last element of a table is selected, I want the first element of the next table (below) to become selected. Conversely, if the first element is selected and the up arrow is pressed, I want the last element of the previous table (above) to become selected. Because my my column setup, it is impossible to use a single TableViewer. The following function is called in the control's initializer, with all of the viewers passed as arguments:

private void init(IEclipseContext context, IMDecisionTable input, DecisionTableTable...viewers) {
    for (int i = 0; i < viewers.length; i++) {
        viewers[i].hookMenuSupport(context);
        viewers[i].setInput(input);
        viewers[i].getTable().addTraverseListener(new TraverseSelector(
            i > 0 ? viewers[i-1] : null, i < viewers.length - 1 ? viewers[i+1] : null
        ));
    }
}

`TraverseSelector is a nested class of my control:

public class TraverseSelector implements TraverseListener {
    public DecisionTableTable p, n;

    public TraverseSelector(DecisionTableTable previous, DecisionTableTable next) {
        p = previous; n = next;
    }

    @Override public void keyTraversed(TraverseEvent e) {
        if (e.getSource() instanceof Table) {
            Table t = (Table) e.getSource();
            if (e.keyCode == SWT.ARROW_UP && p != null && t.getSelectionIndex() == 0) {
                select(p, -1, true);
                e.detail = SWT.TRAVERSE_NONE;
                e.doit = true;
                p.getTable().setFocus();
            } else if (e.keyCode == SWT.ARROW_DOWN && n != null && t.getSelectionIndex() == t.getItemCount() - 1) {
                select(n, 0, true);
                e.detail = SWT.TRAVERSE_NONE;
                e.doit = true;
                n.getTable().setFocus();
            }
        }
    }
}

When the conditions are met, it attempts to set the selection appropriately. Other relavent code within the class of the control:

private boolean selecting = false;
private ISelection selection = null;
@Override public ISelection getSelection() { return selection; }
@Override public void setSelection(ISelection sel, boolean reveal) {
    if (!selecting) {
        synchronized (this) { selecting = true; }
        selection = sel;
        for (TableViewer viewer : Arrays.asList(ftable, ctable, iatable, catable, pstable))
            viewer.setSelection(selection, reveal);
        synchronized (this) { selecting = false; }
    }
}
@Override public void selectionChanged(SelectionChangedEvent event) {
    if (!selecting) {
        synchronized (this) { selecting = true; }
        selection = event.getSelection();
        for (ISelectionProvider sp : Arrays.asList(ftable, ctable, iatable, catable, pstable))
            if (event.getSelectionProvider() != sp)
                sp.setSelection(null);
        synchronized (this) { selecting = false; }
    }
}
private void select(DecisionTableTable viewer, int index, boolean reveal) {
    Table t = viewer.getTable(); int count = t.getItemCount();
    setSelection(new StructuredSelection(t.getItem((index + count) % count).getData()), reveal);
}

My confusion lies with the two lines e.detail = SWT.TRAVERSE_NONE; and e.doit = true;. If I remove these two statements, things don't work. If I remove those and the setFocus statement, the selection is set to the first or last element of the current table, looping the selection within a single table. detail and doit are 32 and false, respectively, before those statements.

Était-ce utile?

La solution 2

What worked for me was implementing a KeyListener instead of a TransverseListener and adding the line e.doit = false; in the key listener. It seems that some kind of event propagation was causing another selection, and the line above stopped said propagation. This is my final code:

private boolean selecting;
private ISelection selection = null;
@Override public ISelection getSelection() { return selection; }
@Override public void setSelection(ISelection sel, boolean reveal) {
    if (!selecting) {
        synchronized (this) { selecting = true; }
        selection = sel;
        for (DecisionTableTable viewer : Arrays.asList(ftable, ctable, iatable, catable, pstable))
            viewer.setSelection(selection, reveal);
        synchronized (this) { selecting = false; }
    }
}
@Override public void selectionChanged(SelectionChangedEvent event) {
    if (!selecting) {
        synchronized (this) { selecting = true; }
        selection = event.getSelection();
        for (DecisionTableTable viewer : Arrays.asList(ftable, ctable, iatable, catable, pstable))
            if (event.getSelectionProvider() != viewer)
                viewer.setSelection(selection);
        synchronized (this) { selecting = false; }
    }
}

public class KeyHandler extends KeyAdapter {
    public DecisionTableTable p, n;

    public KeyHandler(DecisionTableTable previous, DecisionTableTable next) {
        p = previous; n = next;
    }

    @Override public void keyPressed(KeyEvent e) {
        if (e.getSource() instanceof Table) {
            Table t = (Table) e.getSource();
            if (e.keyCode == SWT.ARROW_UP && p != null && t.getSelectionIndex() == 0) {
                p.getTable().setFocus();
                p.setSelection(new StructuredSelection(p.getElementAt(p.getTable().getItemCount() - 1)));
                e.doit = false;
            } else if (e.keyCode == SWT.ARROW_DOWN && n != null && t.getSelectionIndex() == t.getItemCount() - 1) {
                n.getTable().setFocus();
                n.setSelection(new StructuredSelection(n.getElementAt(0)));
                e.doit = false;
            }
        }
    }
}

Autres conseils

I think your problem lies in your select(DecisionTableTable, int, boolean) method. I'm not sure of exactly the effects of the overridden setSelection\selectionChanged methods are but they seem over complicated. Could you not just achieve your requirement with:

private void select(DecisionTableTable viewer, int index, boolean reveal) {
    int count = viewer.getTable().getItemCount();
    viewer.setSelection(new StructuredSelection(viewer.getElementAt((index + count) % count), reveal);
}

Also I think you should be setting doit=false when you are switching tables as you don't want the event to be applied to the current table.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top