Geertjan's Blog

  • January 4, 2013

Getting Started with Diff Viewer from Scratch

Geertjan Wielenga
Product Manager
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;
category = "Tools",
id = "org.my.diff.DiffViewerAction")
asynchronous = true,
displayName = "#CTL_DiffViewerAction")
path = "Menu/Tools",
position = 0)
@Messages("CTL_DiffViewerAction=Open Diff Viewer")
public final class DiffViewerAction implements ActionListener {
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() {
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);
} 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:

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) {
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"/>

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:

Join the discussion

Comments ( 15 )
  • guest Friday, January 4, 2013

    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.

  • Geertjan Friday, January 4, 2013

    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.

  • Geertjan Friday, January 4, 2013

    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:


  • guest Saturday, January 5, 2013

    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

  • Tom Saturday, January 5, 2013

    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!

  • guest Monday, January 7, 2013

    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!

  • Kevin Monday, January 7, 2013

    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?

  • guest Thursday, January 31, 2013

    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.


  • guest Friday, April 5, 2013


    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 ?


  • Geertjan Friday, April 5, 2013

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

  • guest Friday, April 5, 2013


    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 ?

  • blavins Friday, April 5, 2013


    ... 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.)

  • Geertjan Friday, April 5, 2013

    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.

  • blavins Friday, April 5, 2013


    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.

  • Geertjan Friday, April 5, 2013

    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.

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.