Tuesday Jan 08, 2013

How to Create an Editable Diff Viewer

Well, I've learned a lot of cool things about the NetBeans APIs over the years, but this probably takes the cake. All you need to do if you want an editable diff viewer is put a FileObject into the Lookup of a Node and then you can reuse the standard Diff Action that's part of NetBeans IDE.

In the right pane, you can type, i.e., the right pane is editable. All the editing functionality, e.g., code completion, is available too. That's exactly how it is when using NetBeans IDE's diff functionality. No surprise there, since the Diff Action in the IDE is being reused, completely as-is, unchanged, in this scenario.

Here's the definition of the Node above:

public class CustomerNode extends BeanNode<Customer> {
    
    public CustomerNode(Customer bean) throws IntrospectionException {
       this(bean, new InstanceContent());
    }
    
    private CustomerNode(Customer bean, InstanceContent ic) 
            throws IntrospectionException {
        super(bean, Children.LEAF, new AbstractLookup(ic));
        ic.add(bean.getFileObject());
        setDisplayName(bean.getFileObject().getName());
    }

    @Override
    public Action[] getActions(boolean context) {
        return new Action[]{FileUtil.getConfigObject(
                "Actions/Tools/org-netbeans-modules-diff-DiffAction.instance", 
                Action.class)};
    }

} 

What's magical about the above is that the org-netbeans-modules-diff-DiffAction becomes active when one or more Nodes are selected and opens the Diff Viewer for the FileObjects found in the Nodes. So, therefore, since my Customer object is defined by a FileObject read from the layer file, when multiple Customers are selected multiple FileObjects are available (because I put the FileObject into the Node Lookup).

Now, what happens if MORE than two FileObjects are available, i.e., more than two Nodes are selected (or the two selected Nodes have more than two FileObjects in their Lookups)? Well, automatically, the Diff Action is disabled:

And what about if there are LESS than two FileObjects? Then you see the following, i.e., you are prompted to browse on disk for a file that you'd like to compare with the available FileObject:

Next, just make sure that the editor modules for the language of your choice are in the application. For example, because I have the HTML Editor modules, the diff view uses the HTML Editor to display the two FileObjects... because the two FileObjects are recognized as being HTML files, since their file extension is "html".

And what if your Customer object does not define a FileObject, i.e., you want to compare something different? Somehow, create a FileObject anyway. Put into that FileObject the data you'd like to diff. For example, I have this in the module's layer file:

    <folder name="customers">
        <file name="james.html" url="resources/james.html"/> 
        <file name="john.html" url="resources/john.html"/> 
        <file name="henry.html" url="resources/henry.html"/> 
    </folder> 

I then construct the Node hierarchy from the layer folder you see above:

public class CustomerChildFactory extends ChildFactory<Customer> {
    @Override
    protected boolean createKeys(List<Customer> list) {
        FileObject customersFolder = FileUtil.getConfigFile("customers");
        for (FileObject customerFile : customersFolder.getChildren()) {
            list.add(new Customer(customerFile));
        }
        return true;
    }
    @Override
    protected Node createNodeForKey(Customer key) {
        CustomerNode node = null;
        try {
            node = new CustomerNode(key);
        } catch (IntrospectionException ex) {
            Exceptions.printStackTrace(ex);
        }
        return node;
    }
    
} 

Each file you see in the layer folder snippet above is a FileObject, defined by a name (ending in "html", so that the HTML Editor will be used to display the file) and an HTML file that is within the module. Once I have the Node hierarchy, I put the FileObject into the Node Lookup, as shown in the CustomerNode definition above, after which I reuse the Diff Action, as you can see in the getActions method of the CustomerNode. That's all it takes.

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
« January 2013 »
SunMonTueWedThuFriSat
  
25
26
27
30
  
       
Today