views:

97

answers:

1

When I use HelpBroker.setCurrentID("[some help id]"), JavaHelp correctly shows the page I want but the associated topic is not automatically selected/highlighted in the table of contents. This makes it difficult for a user to know where in the topic tree the current page is located.

Is there any way to programmatically highlight the current topic in the TOC when I use a HelpBroker to navigate to a specific Help page?

Note that when the user follows links within the Java help system, the new topic is properly selected in the table of contents.

+1  A: 

You should be able to just call the navigate() function, the rest are helpers. id is the id of course, and nodeLabel is the visible text on the node you want to select. Do note that this code doesn't check for errors, namely preventing trying to go somewhere that doesn't exist.

import java.awt.Component;
import java.util.Enumeration;
import javax.help.*;
import javax.help.plaf.basic.BasicTOCNavigatorUI;
import javax.swing.JTree;
import javax.swing.JScrollPane;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultMutableTreeNode;

public class Nav
{
    private static DefaultMutableTreeNode match = null;

    private Nav()
    {
    }

    public static void navigate(HelpSet set, HelpBroker broker, String id, String nodeLabel)
    {
        broker.setCurrentID(id);
        JHelp jhelp = new JHelp(set);
        JHelpNavigator nav = getNavigator(jhelp);
        JTree tree = getTree(nav);
        TreeModel model = tree.getModel();
        Object root = model.getRoot();
        match = null;
        findNode(model, root, nodeLabel);
        TreePath path = new TreePath(match.getPath());
        tree.setSelectionPath(path);
        tree.scrollPathToVisible(path);
    }

    //http://www.google.com/codesearch/p?hl=en#WiboLAWeTd0/xena/ext/src/javahelp/jhMaster/JavaHelp/src/new/javax/help/WindowPresentation.java&t=0&d=30&l=272
    private static JHelpNavigator getNavigator(JHelp jhelp)
    {
        JHelpNavigator nav = null;
        for (Enumeration e = jhelp.getHelpNavigators(); e.hasMoreElements(); ) 
        {
            nav = (JHelpNavigator) e.nextElement();
            if (nav.getNavigatorName().equals("TOC"))
            {
                return nav;
            }
        }
        return null;
    }

    //http://forums.sun.com/thread.jspa?threadID=350180#1459484
    private static JTree getTree(JHelpNavigator nav)
    {
        JTree tree = null;
        Component[] components = nav.getComponents();
        int count = components.length;
        int i = 0;
        while(i < count && !(components[i] instanceof JScrollPane))
        {
            i++;
        }
        if(i < count)
        {
            JScrollPane sp = (JScrollPane) components[i];
            components = sp.getViewport().getComponents();
            count = components.length;
            i = 0;
            while(i < count && !(components[i] instanceof JTree))
            {
                i++;
            }
            tree = (JTree) components[i];
        }
        return tree;
    }

    //http://www.rkcole.com/articles/swing/TraverseJtree-2000-11-17.html
    private static void findNode(TreeModel model, Object o, String search)
    {
        if(match != null)
            return;

        int count = model.getChildCount(o);
        for( int i=0;  i < count;  i++ )
        {
            Object child = model.getChild(o, i );
            if (  model.isLeaf( child ) )
            {
                if(search.equals(((TOCItem)((DefaultMutableTreeNode)child).getUserObject()).getName()))
                {
                    match = (DefaultMutableTreeNode)child;
                    return;
                }
            }
            else
                findNode( model, child, search );
        }
    }
}
Matt Blaine
Thanks for the possible solution. I'm not certain I can make it work though since it would require knowing the node labels.I'm concerned that this makes the mapping of topics much more involved and difficult to maintain, and I would have to do something to figure out how to support localization of the node labels.I will look into whether or not this could work for us.
dcstraw
I modified the code to find by ID instead of name, but the call to tree.setSelectionPath(path) just deselects the current selection without selecting the new one. The new value is set in the model but the tree does not show a selection rectangle around the new node. I'll keep looking into this. Let me know if you have any ideas.
dcstraw
Well I got it working but not in a capacity that I would feel comfortable releasing to production. In your code you create a new JHelp each time, but this doesn't work for me. I got it to work by reflecting on a private field of the DefaultHelpBroker to get it's internal JHelp object. Does your code work for you? If so any ideas why it wouldn't for me?
dcstraw
Got it to work without reflection, though it is still somewhat of a hack. I now intercept the creation of the JHelpTOCNavigator by creating a derived TOCView. That way I have a reference to the navigator when it comes time to call setCurrentID.
dcstraw
@dcstraw I'm not ignoring you, I promise. :) I'm familiar with Java, but not Java Help. What I did was find some sample code http://www.ibm.com/developerworks/java/library/j-javahelp2/ and dig through the source for Java Help itself until I could get what you described working. Sorry I didn't have anything to add to your comments. But you managed to get it working for you, right?
Matt Blaine
Yep, I got it to work. I've been waiting to see if there is a simpler solution, but if not I'll make sure to accept your answer before the bounty ends.
dcstraw