X

Geertjan's Blog

  • April 11, 2006

Opening Multiple Files Simultaneously (Part 1)

Geertjan Wielenga
Product Manager
Wicket has a very specific scenario—each web page consists of two files, an HTML file and a Java file (I wonder how often I have blogged those words in this blog, must be at least two dozen times). Hence, chances are that you're working with both files simultaneously. For this reason, it would be handy if opening one of them meant opening the other as well. I gotta tell you—I was up until 2 a.m. this morning, working on this problem (which, for more experienced module developers, would probably a piece of cake) and, with the help of a code snippet from Sandip, I got most of the job done (although there are still a few bugs that I haven't resolved yet).

So, here's what happens, anecdotally: assuming you want the corresponding Java file to open when the HTML file opens, you need to listen for the opening of HTML files. This you cannot do anywhere else, as far as I (and Sandip) can work out than in a ModuleInstall class. It has a restored() method, which is called during IDE startup. So, from startup, the restored() method makes sure that the IDE is listening for the opening of HTML files. This is the snippet that Sandip sent me (the additions/changes I made are in bold):

final TopComponent.Registry registry = TopComponent.getRegistry();
registry.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (TopComponent.Registry.PROP_OPENED.equals(evt.getPropertyName())) {
Set openedSet = registry.getOpened();
if (openedSet != null) {
for (Iterator iter = openedSet.iterator(); iter.hasNext(); ) {
TopComponent topComponent = (TopComponent ) iter.next();
// now see if the topComponent contains Java file
Node[] nodes = topComponent.getActivatedNodes();
if (nodes != null && nodes.length > 0) {
// you may want to go through all nodes here...I am showing 0th node only
DataObject dataObject = (DataObject) nodes[0].getLookup().lookup(DataObject.class);
if (dataObject instanceof HtmlDataObject) {FileObject theFile = dataObject.getPrimaryFile();
OpenJavaClassThread run = new OpenJavaClassThread(theFile);
RequestProcessor.getDefault().post(run);

}
}
}
}
}
}
}
);

Sandip's code checked for the opening of Java files. Mine checks for the opening of HTML files. When an HTML file opens, the file is sent to this class, which is based on a class created by Petr Pisl for the hyperlinking support for Wicket:

private class OpenJavaClassThread implements Runnable {
private String fqn;
private FileObject theFile;
public OpenJavaClassThread(FileObject theFile){
super();
this.theFile = theFile;
}
public void run() {JavaClass jclass = WicketUtilities.findJavaClass(theFile);
if (jclass != null) {
org.netbeans.modules.editor.java.JMIUtils.openElement(jclass);
} else {
String key = "goto_source_not_found"; // NOI18N
String msg = NbBundle.getBundle(WicketHTMLHyperlingProvider.class).getString(key);
org.openide.awt.StatusDisplayer.getDefault().setStatusText(msg);
}
}
}

The important bit above, where the related Java file is retrieved, is in bold. It works with this method (inline comments in bold for clarity):

public static JavaClass findJavaClass(FileObject theFile){
FileObject foJava;// Get Java file of same name
foJava = theFile.getParent().getFileObject(theFile.getName(), "java");
if (foJava==null) {
String key = "goto_source_not_found"; // NOI18N
String msg = NbBundle.getBundle(WicketHTMLHyperlingProvider.class).getString(key);
org.openide.awt.StatusDisplayer.getDefault().setStatusText(msg);
}// Construct FQPN for the Java file
String fqpn = foJava.getPath();
fqpn = fqpn.substring(fqpn.indexOf("/java/")+6, fqpn.indexOf(".java")).replace('/','.');
return JMIUtil.findClass(fqpn, ClassPath.getClassPath(foJava, ClassPath.SOURCE));
}

So then the retrieved class is returned to OpenJavaClassThread and is opened together with the HTML file of the same name and in the same source structure. For example, when I double-click Home.html below, Home.java also opens, as can be seen below:

It wouldn't be hard, I think, to extend this so that a .properties file of the same name and in the same source structure, would be opened as well.

However, there are a few problems (aren't there always): the opened Java file won't close, the HTML file can't receive focus because the Java file is always activated, and an uncaught error is thrown when the HTML file does not have a corresponding Java file. So, there's still a bit of work to be done. One thing that needs to happen, I think, is that something should happen after the corresponding Java file opens. Currently it just isn't opening correctly. But at least it is open!

Join the discussion

Comments ( 3 )
  • Alex Lam Tuesday, April 11, 2006
    Feels like a very good feature to get into NB.next itself - keep up the good work!
  • Jesse Glick Wednesday, April 12, 2006
    Maybe I'm being stupid, but why are you fooling around with javamodel? There is no need for that as far as I can tell. If you've found the FileObject for the .java file, then just DataObject.find(it).getCookie(OpenCookie.class).open(), plus null/error checking.
  • Geertjan Thursday, April 13, 2006
    Alex, thanks for the encouragement. Jesse, I'll investigate; thanks a lot for the feedback.
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.