Tuesday Jun 03, 2008

Swing Outline Component

Announcing the new Swing Tree Table today, Tim writes:

Usage is incredibly easy - you just provide a standard Swing TreeModel of whatever sort you like, and an additional RowModel that can be queried for the other columns contents, editability and so forth.

I found an example from sometime ago, by Tim, and have been playing with it to get used to this new development. The result is as follows:

To get started, I simply download the latest NetBeans IDE development build from netbeans.org and then attached the platform8/org-netbeans-swing-outline.jar to my Java SE project. Then I created a JFrame.

To work with this Swing tree table, you need to provide the new "org.netbeans.swing.outline.Outline" class with the new "org.netbeans.swing.outline.OutlineModel" which, in turn, is built from a plain old javax.swing.tree.TreeModel, together with the new "org.netbeans.swing.outline.RowModel". Optionally, to change the default rendering, you can use the new "org.netbeans.swing.outline.RenderDataProvider".

Let's first create a TreeModel for accessing files on disk. We will receive the root of the file system as a starting point:

private static class FileTreeModel implements TreeModel {

    private File root;

    public FileTreeModel(File root) {
        this.root = root;
    }

    @Override
    public void addTreeModelListener(javax.swing.event.TreeModelListener l) {
        //do nothing
    }

    @Override
    public Object getChild(Object parent, int index) {
        File f = (File) parent;
        return f.listFiles()[index];
    }

    @Override
    public int getChildCount(Object parent) {
        File f = (File) parent;
        if (!f.isDirectory()) {
            return 0;
        } else {
            return f.list().length;
        }
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        File par = (File) parent;
        File ch = (File) child;
        return Arrays.asList(par.listFiles()).indexOf(ch);
    }

    @Override
    public Object getRoot() {
        return root;
    }

    @Override
    public boolean isLeaf(Object node) {
        File f = (File) node;
        return !f.isDirectory();
    }

    @Override
    public void removeTreeModelListener(javax.swing.event.TreeModelListener l) {
        //do nothing
    }

    @Override
    public void valueForPathChanged(javax.swing.tree.TreePath path, Object newValue) {
        //do nothing
    }

}

Next, let's introduce the RowModel class:

private class FileRowModel implements RowModel {

    @Override
    public Class getColumnClass(int column) {
        switch (column) {
            case 0:
                return Date.class;
            case 1:
                return Long.class;
            default:
                assert false;
        }
        return null;
    }

    @Override
    public int getColumnCount() {
        return 2;
    }

    @Override
    public String getColumnName(int column) {
        return column == 0 ? "Date" : "Size";
    }

    @Override
    public Object getValueFor(Object node, int column) {
        File f = (File) node;
        switch (column) {
            case 0:
                return new Date(f.lastModified());
            case 1:
                return new Long(f.length());
            default:
                assert false;
        }
        return null;
    }

    @Override
    public boolean isCellEditable(Object node, int column) {
        return false;
    }

    @Override
    public void setValueFor(Object node, int column, Object value) {
        //do nothing for now
    }
    
}

Now, after dragging-and-dropping an Outline object onto your JFrame (which is possible after adding the beans from the JAR to the Palette Manager) which, in turn, automatically creates a JScrollPane as well, this is how you could code the JFrame's constructor:

public NewJFrame() {

    //Initialize the ui generated by the Matisse GUI Builder, which,
    //for example, adds the JScrollPane to the JFrame ContentPane:
    initComponents();

    //Here I am assuming we are not on Windows,
    //otherwise use Utilities.isWindows() ? 1 : 0
    //from the NetBeans Utilities API:
    TreeModel treeMdl = new FileTreeModel(File.listRoots()[0]);

    //Create the Outline's model, consisting of the TreeModel and the RowModel,
    //together with two optional values: a boolen for something or other,
    //and the display name for the first column:
    OutlineModel mdl = DefaultOutlineModel.createOutlineModel(
            treeMdl, new FileRowModel(), true, "File System");

    //Initialize the Outline object:
    outline1 = new Outline();

    //By default, the root is shown, while here that isn't necessary:
    outline1.setRootVisible(false);

    //Assign the model to the Outline object:
    outline1.setModel(mdl);

    //Add the Outline object to the JScrollPane:
    jScrollPane1.setViewportView(outline1);    

}

At this point, you can run the JFrame, with this result:

So, we see a lot of superfluous info that doesn't look very nice. Let's implement "org.netbeans.swing.outline.RenderDataProvider", as follows:

private class RenderData implements RenderDataProvider {

    @Override
    public java.awt.Color getBackground(Object o) {
        return null;
    }

    @Override
    public String getDisplayName(Object o) {
        return ((File) o).getName();
    }

    @Override
    public java.awt.Color getForeground(Object o) {
        File f = (File) o;
        if (!f.isDirectory() && !f.canWrite()) {
            return UIManager.getColor("controlShadow");
        }
        return null;
    }

    @Override
    public javax.swing.Icon getIcon(Object o) {
        return null;

    }

    @Override
    public String getTooltipText(Object o) {
        File f = (File) o;
        return f.getAbsolutePath();
    }

    @Override
    public boolean isHtmlDisplayName(Object o) {
        return false;
    }

}

Now, back in the constructor, add the renderer to the outline:

outline1.setRenderDataProvider(new RenderData());

Run the JFrame again and the result should be the same as in the first screenshot above. Look again at the rendering code and note that, for example, you have tooltips:

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« June 2008 »
SunMonTueWedThuFriSat
1
6
13
19
26
28
29
     
       
Today