javatreeswtjfacetreeviewer

SWT/JFace TreeColumn reordering - issue with setMoveable()


I am trying to set up a multi-column SWT Tree (via a JFace TreeViewer) that allows its columns to be re-ordered by the user by dragging the column headers. However, the first column should remain fixed and unmoveable. I can use the setMoveable(true) method on each TreeColumn except the first to get real close, but that doesn't prevent the user dragging a different column to the left of it. Any ideas how to resolve this?

Here's a simplified working snippet (without JFace) to illustrate the problem:

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;

public class TreeTableColumnMove {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new RowLayout(SWT.HORIZONTAL));
        Tree tree = new Tree(shell, SWT.BORDER | SWT.CHECK);
        tree.setLayoutData(new RowData(-1, 100));
        tree.setHeaderVisible(true);
        for (int i = 0; i < 5; i++) {
            TreeColumn column = new TreeColumn(tree, SWT.CENTER);
            column.setText("Col " + i);
            column.setWidth(60);
            if (i > 0) column.setMoveable(true);
        }
        TreeItem item = new TreeItem(tree, SWT.NONE);
        item.setText(new String[] { "c0", "c1", "c2", "c3", "c4" });
        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
}

Solution

  • I don't know if it's possible to actually prevent it, but you can handle the result of the column moving, and react to it to achieve what you want.

    Maybe something along these lines would be a good starting point? Essentially it listens for the first column being moved (not directly, but being shifted as a result of another column being moved to the left of it), and then re-shuffles the order so it is the first column visually again.

    Note that regardless of the visual order, the first column created will always be zero (and so on). The method tree.getColumnOrder() will be ordered visually, with the values being the created order indexes (so if you swap the 2nd and 3rd columns, the method will return [0, 2, 1, 3, 4])

    for (int i = 0; i < 5; i++) {
        TreeColumn column = new TreeColumn(tree, SWT.CENTER);
        column.setText("Col " + i);
        column.setWidth(60);
        if (i > 0) column.setMoveable(true);
    
        // NEW CODE HERE
        if (i == 0) {
    
            column.addControlListener(new ControlAdapter() {
    
                public void controlMoved(ControlEvent e) {
    
                    List<Integer> newOrder = new ArrayList<Integer>();
    
                    // add the first
                    newOrder.add(0);
    
                    // loop around all columns
                    for (int col : tree.getColumnOrder()) {
    
                        // if not the first that was added, add to list
                        if (col != 0) {
                            newOrder.add(col);
                        }
                    }
    
                    // convert list to array
                    int[] newOrderArray = new int[newOrder.size()];
                    for (int j = 0; j < newOrder.size(); j++) {
                        newOrderArray[j] = newOrder.get(j);
                    }
    
                    // update tree order
                    tree.setColumnOrder(newOrderArray);
                }
            });
        }
    }