Geertjan's Blog

  • March 2, 2006

Merging Javadoc with JavaHelp

Geertjan Wielenga
Product Manager
I've extended the plug-in module that I blogged about two days ago. There, I was able to select a Java keyword in the editor and then display a help topic specifically for that keyword. My implementation was kind of cheating—the selected word was determined to be a Java keyword purely based on whether a map id had been created for it in the JavaHelp map file. My extension to the plug-in module is a bit more "honest": it looks at whether the word under the cursor (a.k.a. "caret") is a "MultipartId". If the word is a MultipartId (i.e., it is something like java.lang.String), a map id with the same name is found in the map file. And then... the related HTML file from the related Javadoc appears! Here's the proof:

The thing is, I find it much easier to use Javadoc inside JavaHelp than in the odd browser thing that you get in the IDE. Another issue with the IDE's Javadoc viewer is that it opens in a new pane in the editor, which means you've got to switch between the pane you're in and the pane containing the Javadoc (unless, of course, you split the editor). And, now I just use Ctrl-F1 (which is my plug-in module's shortcut) instead of Shift-F1.

One thing you might be wondering is, "how is the Javadoc accessed"? Well, I created a plug-in module that contains (part of) the Javadoc (not all because all is too much). Ultimately, I'd like to put the Javadoc into a few separate plug-in modules, currently I only have one of these plug-in modules—for the java top package. Then, inside my plug-in module's map file, I refer to the JavaHelp topic I need (in the same way as all the other help sets in the IDE cross reference each other). For example, this is how the Javadoc for java.lang.String is found:

<mapID target="java.lang.String" 

The cool thing is that the IDE doesn't only identify the String in java.lang.String as a MultipartId , but also String on its own. So, I would also get the String.html file from Javadoc if my cursor is on String() in the line below:

new String();

Maybe the best part of all is that I learnt about MultipartId (and other ways of identifying other parts of code in the editor) from Sandip. If you take a look at his Java tools modules, you'll find that there's a lot to learn there. The most important part of the code is below—the line in bold should help to orientate you. Basically what happens is if the word under the cursor is not a MultipartId, the code branches to the same code discussed two days ago—a check is done to see whether a map id exists and, if it does, a help topic is displayed. If the word under the cursor is a MultipartId, a substring of the type (because MultipartId is always in the form "Class bla.bla.bla.class" instead of what is needed to call the Javadoc: "bla.bla.bla.class") is sent to the getHelpCtx method, which checks to see if a map id exists for it and then displays the Javadoc's HTML file, which is mapped to the map id:

protected void performAction(Node[] activatedNodes) {
DataObject dataObject = (DataObject) activatedNodes[0].getLookup().lookup(DataObject.class);
FileObject fileObject = dataObject.getPrimaryFile();
Resource resource = null;
resource = JavaModel.getResource(fileObject);
ElementFinder elementFinder = new ElementFinder(resource);
EditorCookie ec = (EditorCookie) activatedNodes[0].getCookie(EditorCookie.class);
if(dataObject instanceof JavaDataObject) {
if (ec != null) {
JEditorPane[] panes = ec.getOpenedPanes();
if (panes != null) {
TopComponent activetc = TopComponent.getRegistry().getActivated();
for (int i = 0; i < panes.length; i++) {
if (activetc.isAncestorOf(panes[i])) {
int dot = panes[i].getCaret().getDot();
Element element = elementFinder.getElementByOffset(dot);
Type type = null;
if (element instanceof MultipartId) {
type = ((MultipartId)element).getType();
if (type != null) {
String stringifiedType = type.toString();
//By default, "type" consists of "class bla.bla.bla.class", so
//we need to remove the first 6 characters, i.e., "class ".
String removeFirstSixLettersType = stringifiedType.substring(6);
} else {
} else {
} else {
NotifyDescriptor.Message msg = new NotifyDescriptor.Message("Not a Java file");

So, the two biggest problems with this entire story are:

  • Creating Map Ids. For each HTML page in Javadoc, I need to create a map id. There's got to be some way of automating that, based on the index.html file which accompanies the Javadoc. (Update: Take a look at JavaHelp Map IDs for Lazy People for a cool solution.)
  • Creating plug-in modules for Javadoc. For each set (or subset, depending on the size of the set) of Javadoc , a separate plug-in module must be created (and installed). Not very nice. And it makes the IDE much larger, but unfortunately you can't set a variable in the map file. If that were possible, then maybe there'd be some way to refer to an external folder containing the Javadoc.

Anyway, I think it's pretty cool and I'm going to be much more interested in Javadoc now that there's this much simpler way of accessing it.

Be the first to comment

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