Geertjan's Blog

  • April 12, 2006

Opening Multiple Files Simultaneously (Part 2)

Geertjan Wielenga
Product Manager
I encountered a few problems since yesterday. First, for no reason I can determine, I suddenly wasn't able to use HTMLDataObject anymore. (I started getting messages saying that the org.netbeans.modules.html.HtmlDataObject couldn't be found. It might have something to do with the HTML module not being an API module, but that still doesn't explain why it first worked and then later didn't.) As a result, I couldn't check whether the current dataobject is an instance of HTMLDataObject. I was stumped for a while and then suddenly realized that an alternative way to identify an HTML file is by its extension. If you use this line, you'll get HTML files only:


Another problem I had was that, even though I could open an HTML file together with its corresponding Java file, there was something weird going on that prevented me from activating the HTML file, even though it was open. Hours of debugging later, I discovered that the problem was that I didn't understand what an "activated node" is. An activated node, in the context of this scenario, is (1) the selected node in the explorer (e.g., the Projects window) as well as (2) the active tab (a.k.a. editor) in the Source Editor. So, if I select a Java file in the Projects window while an HTML file is open in the Source Editor, my activated nodes are (1) the Java file and (2) the tab (which you could also refer to as "the HTML editor" or "the currently open HTML file") in the Source Editor. As a result of this, because the opening of the corresponding Java file took place within a for loop, per activated node, assuming that the fileobject's extension is ".html", at least two nodes were applicable: the activated node in the Projects window and the active tab in the Source Editor. But only one node was needed, the first activated node that is recognized as such, which is the open tab in the Source Editor (i.e., the HTML Editor), and so, by adding a break, I now exit the for loop after the first node is successflly identified. I guess there's a bit of mixed up thinking on my part here, but this is how I understand it currently:

public void installOptions() {
// The TopComponent.Registry instance is an object that
// manages the lifecycle of all the topcomponents and
// thus can tell you which is the active topcomponent:final TopComponent.Registry registry = TopComponent.getRegistry();
// Lets attach a property change listener to the registry
// so that we can detect which topcomponents (e.g., HTML editor,
// Java editor, Properties edtitor,
// etc.)are open. If the HTML editor top component is open,
// that means we're dealing with an HTML file, etc.:registry.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {

// We're going to limit everything we do to those topcomponents
// that are open:if (TopComponent.Registry.PROP_OPENED.equals(evt.getPropertyName())) {
// Here we get a set of all the open topcomponents:Set openedSet = registry.getOpened();
// Now, if there is at least one open topcomponent...
// which means at least one document must be open in the editor...if (openedSet != null) {
// ...let's iterate through the open top components, i.e., open
// documents in the Source Editor,
// and determine if there's an HTML topcomponent among them:for (Iterator iter = openedSet.iterator(); iter.hasNext(); ) {
// So, on each iteration, we get the next topcomponent,
// which in this case is the next open document...TopComponent topComponent = (TopComponent ) iter.next();
// ...and we get all the activated nodes for the
// current topcompoent (which means, the selected node
// in the explorer window on the left, as well as the
// active topcomponent itself, which is also a node)...Node[] nodes = topComponent.getActivatedNodes();
// Now we need to get a subset of all the activated nodes:
// only those that have an HTML extension:if (nodes != null && nodes.length > 0) {
DataObject dataObject = (DataObject) nodes[0].getCookie(DataObject.class);
FileObject f = dataObject.getPrimaryFile();
if (f.getNameExt().endsWith("html")) {
FileObject theFile = dataObject.getPrimaryFile();
OpenJavaClassThread run = new OpenJavaClassThread(theFile);

// The first time we succeed here, we can break out
// of the for loop. Bit messy, but gets the job done.
// We don't have to deal with nodes other than the first
// node, which is the one in the topcomponent.break;

But, now that the Java file opens and I can also activate the HTML file and work with it, because I'm no longer stuck in a loop, I'm still unable to close the Java file for some reason... (Anyone reading this can be as scathing as they like in correcting my misinterpretations of things!)

Join the discussion

Comments ( 5 )
  • Gregg Sporar Wednesday, April 12, 2006
    This seems kinda' fragile:

    if (f.getNameExt().endsWith("html"))

    What about files with ".htm" ?
  • Geertjan Wednesday, April 12, 2006
    Well, if that's the only line that turns out to be fragile, I'll buy myself a beer.
  • Tor Norbye Wednesday, April 12, 2006

    Faster than f.getNameExt().endsWith("html") would be f.getExt().equals("html")...

    But, you should not use file extensions to recognize file types. Instead, you should use the mime type. If you look at the mime resolver for html, you'll notice that it will use the Html editor for all files of extension .html, .htm, .shtml, .xhtml, and even XML files that use mime type application/xhtml+xml!

    Luckily, there's an easy and clean fix for this: Instead of calling fileObject.getExt(), call fileObject.getMIMEType() and compare it to text/html.

  • Geertjan Wednesday, April 12, 2006
    Thanks Tor!
  • guest Thursday, July 13, 2006
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.