Getting Started with Diff Viewer from Scratch

Let's get started creating an application from scratch integrating the NetBeans Diff Viewer. Create a new application:

Give it a name and store it somewhere:

Create a new module:

Give it a name and store it somewhere:

Give it a unique identifier and display name:

Right-click the application, choose Properties, go to Libraries, and select "Diff" from the "ide" cluster and then click the Resolve button to include the related modules:

Create a new Action:

Let it always be enabled:

Specify the locations where the Action will be invoked:

Provide class name, display name, and icon:

Right-click the module and specify that you want to add a dependency:

Add a dependency on the Diff module:

Do the same as the above for the Window System module.

Define the Action as follows, replacing the hardcoded files with your own:

package org.my.diff;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.swing.SwingUtilities;
import org.netbeans.api.diff.Diff;
import org.netbeans.api.diff.DiffView;
import org.netbeans.api.diff.StreamSource;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;

@ActionID(
        category = "Tools",
        id = "org.my.diff.DiffViewerAction")
@ActionRegistration(
        asynchronous = true,
        displayName = "#CTL_DiffViewerAction")
@ActionReference(
        path = "Menu/Tools", 
        position = 0)
@Messages("CTL_DiffViewerAction=Open Diff Viewer")
public final class DiffViewerAction implements ActionListener {

     @Override
    public void actionPerformed(ActionEvent e) {
        StreamSource local = StreamSource.createSource("name1",
                "title1", "text/html", new File("C:/tutorials/nbm-google.html"));
        StreamSource remote = StreamSource.createSource("name2",
                "title2", "text/html", new File("C:/tutorials/72/nbm-google.html"));
        diff(local, remote);
    }

    public void diff(final StreamSource local, final StreamSource remote) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    DiffView view = Diff.getDefault().createDiff(local, remote);
                    TopComponent tc = new TopComponent();
                    tc.setDisplayName("Diff Viewer");
                    tc.setLayout(new BorderLayout());
                    tc.add(view.getComponent(), BorderLayout.CENTER);
                    tc.open();
                    tc.requestActive();
                } catch (IOException ex) {
                }
            }
        });
    }
    
}

Alternatively, let's assume that the files we want to diff are within the module, for some reason, rather than externally on disk. This is how the "actionPerformed" above would be rewritten:

@Override
public void actionPerformed(ActionEvent e) {
    StreamSource ss1 = null;
    StreamSource ss2 = null;
    InputStreamReader ir1 = null;
    InputStreamReader ir2 = null;
    try {
        ir1 = new InputStreamReader(FileUtil.getConfigFile("files/one").getInputStream());
        ir2 = new InputStreamReader(FileUtil.getConfigFile("files/two").getInputStream());
        ss1 = StreamSource.createSource("name1", "title1", "text/html", ir1);
        ss2 = StreamSource.createSource("name2", "title2", "text/html", ir2);
    } catch (FileNotFoundException ex) {
        Exceptions.printStackTrace(ex);
    }
    diff(ss1, ss2);
}

And here are the related layer elements:

<folder name="files">
    <file name="one" url="file1.html"/> 
    <file name="two" url="file2.html"/> 
</folder>

The above assumes the layer.xml is in the same package as the two files "file1.html" and "file2.html".

Run the application and go to the Tools menu to invoke the Action:

You'll see this:

Go back to the Project Properties dialog of the application and include these two modules from the "ide" cluster:

Clean the application. Build the application. Run the application. Invoke the Action. You'll see the Diff Viewer, as below, diffing the two files you passed in:

Comments:

FYI my NB 7.2 experience: adding Plain Editor and Plain Editor Library does not solve the Unsupported TextUI problem. Selecting _all_ modules in the IDE cluster does and the Diff display is as you indicate. So there seems to be an additional module(s) requirement.

Posted by guest on January 04, 2013 at 01:50 PM PST #

Can you, please, just take the steps above? Thanks. Forget your ideas and findings for the moment. Just start with the start of the blog entry and work your way to the end. Thanks.

Posted by Geertjan on January 04, 2013 at 02:53 PM PST #

Took the steps above in 7.2. It took all of 5 minutes and works exactly as described. The 5 minutes included the process of creating the ZIP and uploading it for you:

https://blogs.oracle.com/geertjan/resource/DiffViewer.zip

Posted by Geertjan on January 04, 2013 at 03:04 PM PST #

Hi Geertjan. Nice clean sample, but could you please extend it by making the diff editable?! This would be even more useful. Thank you. Markiewb

Posted by guest on January 04, 2013 at 05:21 PM PST #

Whoever it was, in the first comment, suggesting that _all_ modules in the IDE cluster need to be selected for the Diff functionality to work, doesn't know much about NetBeans modularity and hasn't taken the very clear steps described in this blog entry. Thanks for writing it, works perfectly!

Posted by Tom on January 05, 2013 at 05:09 AM PST #

WRT my initial comment about there being additional dependencies, it was due to this change, which seemed an obvious generalization:

I changed "text/html" to FileUtil.toFileObject(<file>).getMIMEType() so that the code would work for any type of file. Silly me!

Posted by guest on January 07, 2013 at 05:18 AM PST #

WRT making the diff editable:

Shouldn't calling diff/src/org/netbeans/modules/diff/DiffAction.java::performAction directly give the same display that NetBeans gives -- editable with a toolbar and other controls? If so, how does one construct the Nodes that represent the files?

Posted by Kevin on January 07, 2013 at 06:14 AM PST #

Hi Geertjan,

I am try to create a Diff View using the createDiff() method.

It is working properly for small files given to it.

I am trying to find the Difference in to String variables which contain a data which amounts to a 10 MB .txt file.

It is creating the Diff View and placing it into the ScrollPane, but it is not showing any differences between the files even though they have a lot of omissions and changes found between them.

Nigel.

Posted by guest on January 31, 2013 at 01:42 AM PST #

G'day

I have a large Java Web Start project under construction to which I would like to add Diff functionality. To see how the NetBeans Diff functionality looks I created an R&D project that starts out not as a Netbeans Module application like yours but as a standard Java application. I have very similar code to you i.e. turn the files to be Diff'd into StreamSources and then give them to Diff within an InvokeLater Runnable. I use DiffController rather than DiffView but I still get to the "You'll see this" step above. And what you said I'll see is indeed what I see. (I had to download and add 13 JARs to Libraries by hand, some of which conflict with each other but that is another story.) The next step obviously is to involve the Plain Editor. Is there a way to do that for a Java application. I presume its a case of adding appropriate JARs to the library list for the project but, not being a NetBeans Module application, it isn't as straightforward as you describe. Can you advise what I need to do ?

Ian

Posted by guest on April 04, 2013 at 09:32 PM PDT #

I advise that you need to port your application to the NetBeans Platform, instead of continuing with a standard Java application.

Posted by Geertjan on April 04, 2013 at 10:26 PM PDT #

G'day

I created a second RandD project that starts as a NetBeans Module and then just followed along the steps you lay out. Sure enough I saw what you said I would see and I overcame that by involving the Plain Editor. So, yes, that works.

As a byproduct I was able to find better sources for the 13 Jar files that I had added to the libraries of my first RandD project (the one that starts as an ordinary Java application) - they all now come from my NetBeans install directory rather than from downloads. So they are now a consistent set and that would be acceptable for use in the tool I am building. (The 13 turned into 21 along the way but that is okay. If I can add Diff functionality to my Tool then carrying another 21 JARs is okay.)

I've found the plain editor and plain editor library JARs and added them to my first RandD project. But that, on its own, doesn't make the display in the panes of the message about unsupported Text UI go away.

From my perspective it looks like I am very close (ignorance is like that). Is the approach really fundamentally broken ?

Posted by guest on April 04, 2013 at 11:59 PM PDT #

G'day

... and what I didn't say is that I don't give 2 hoots about what the RandD projects start life as - NetBeans modules or plain Java apps. But I way too far in (8 months and counting) to change the base of the Tool to something else.)

Posted by blavins on April 05, 2013 at 12:03 AM PDT #

Yeah, I think you're going to run into more and more problems, since you're not using the NetBeans Platform. I'd be happy to help you via a few free Skype sessions to reconstitute your existing application to be on the NetBeans Platform, would help things out for you in the long run. The approach you're currently taking I can't help you with, though, so on that score you can stop asking questions because I simply don't know.

Posted by Geertjan on April 05, 2013 at 12:39 AM PDT #

G'day

Thanks for the offer but I won't take it up. I'll think about what I want to do. Having Diff would be valuable. But the tool started life as an Enterprise Application Client and having that work is way more important than having Diff work. I might spend a day seeing if I can have my cake and eat it too but I'm not optimistic.

Thanks for your help.

Posted by blavins on April 05, 2013 at 01:15 AM PDT #

Well, my offer wasn't so much about the Diff, but about helping you create an application that has a window system, loose coupling, modularity, extensibility, and pluggability all built into it. With no overhead. Really useful features and would make it possible for your app to leverage features from other apps created on the same infrastructure.

Posted by Geertjan on April 05, 2013 at 01:17 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
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
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today