How do I preserve the column attributes of a TreeTableView?

Apache NetBeans Wiki Index

Note: These pages are being reviewed.

Assuming you are embedding a TreeTableView (TTV) inside a TopComponent, you can override the readExternal(ObjectInput) and writeExternal(ObjectOutput) methods for preserving the attributes of the columns in your TTV (e.g. the column ordering, sorted-ness, sorting order, visibility, and width).

Start by keeping a reference to the Node.Property array used to define the columns of the TTV, since there is no way to get those properties from the TTV (i.e. there is no getProperties() method). The examples below will refer to this Node.Property array as "columns".

In order to get and set the column widths of the tree-table, we need to subclass TreeTableView and provide a getTable() method that returns the treeTable protected field of the TreeTableView class. In the examples below, this reference will be referred to as treeTable for brevity.

First let us save the column attributes to the serialized TopComponent via the writeExternal() method.

    public void writeExternal(ObjectOutput out) throws IOException {
        super.writeExternal(out);
        out.writeInt(columns.length);
        for (int ii = 0; ii < columns.length; ii++) {
            Boolean b = (Boolean) columns[Ii].getValue("InvisibleInTreeTableView");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
            Integer i = (Integer) columns[Ii].getValue("OrderNumberTTV");
            if (i == null) {
                i = new Integer(ii);
            }
            out.writeInt(i.intValue());
            b = (Boolean) columns[Ii].getValue("SortingColumnTTV");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
            b = (Boolean) columns[Ii].getValue("DescendingOrderTTV");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
        }
        try {
            TableColumnModel tcm = treeTable.getColumnModel();
            int count = tcm.getColumnCount();
            for (int index = 0; index < count; index++) {
                TableColumn tc = tcm.getColumn(index);
                out.writeInt(tc.getWidth());
            }
        } catch (IOException ioe) {
            ErrorManager.getDefault().notify(ErrorManager.WARNING, ioe);
        }
    }

Next, we see how to deserialize the column attributes.

    public void readExternal(ObjectInput in)
            throws IOException, ClassNotFoundException {
        super.readExternal(in);
        try {
            int count = in.readInt();
            for (int ii = 0; ii < count; ii++) {
                boolean b = in.readBoolean();
                columns[Ii].setValue("InvisibleInTreeTableView", Boolean.valueOf(b));
                int i = in.readInt();
                columns[Ii].setValue("OrderNumberTTV", Integer.valueOf(i));
                b = in.readBoolean();
                columns[Ii].setValue("SortingColumnTTV", Boolean.valueOf(b));
                b = in.readBoolean();
                columns[Ii].setValue("DescendingOrderTTV", Boolean.valueOf(b));
            }
        } catch (Exception e) {
            // Could be reading an old instance which is missing data.
            // In any case, ignore this as there is no use in reporting it.
        }
        nodeView.setProperties(columns);

        // Read the column widths from the stream immediately and save them
        // to a final array for the Runnable below to access them.
        TableColumnModel tcm = treeTable.getColumnModel();
        int count = tcm.getColumnCount();
        final int[[ | ]] widths = new int[Count];
        try {
            for (int index = 0; index < count; index++) {
                widths[Index] = in.readInt();
            }
        } catch (IOException ioe) {
            // Could be reading an old instance which is missing data.
            // In any case, ignore this as there is no use in reporting it
            // (and return immediately so as not to invoke the runnable).
            return;
        }

        // Changing Swing widgets must be done on the AWT event thread.
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                // TreeTableView prohibits moving the tree
                // column, so it is always offset zero.
                setTreePreferredWidth(widths[0]);
                for (int index = 1; index < widths.length; index++) {
                    setTableColumnPreferredWidth(index - 1, widths[Index]);
                }
            }
        });
    }