Saturday, April 5, 2008

Dynamic Context Help

I admit that I've passed over this user assistance feature for the last few years. My reasons: it's fluff, the documentation is vague, and no one will use it. I couldn't have been more wrong.

We first wired up dynamic help to our job deck editor in January. Looking at the above image you will see that the *TFSUPPRESS tag NOISEDIP has been selected with the help view offered a link for more details. It is simple, it works, and it is not annoying.

The idea is to offer the user help on what has been selected in the active view or editor. The help appears in the Eclipse help view. I've put together an example plugin that shows how it works. It is a view listing three characters from the classic movie "The Good, the Bad and the Ugly". The view class is called DynamicHelpView.

Download the plugin source here from SourceForge.net. The code assumes you are using Eclipse 3.3 and at least Java 5.0. I'm assuming you have some experience in adding help to your plugin. If not, spend a few minutes looking at the plugin.xml, context.xml and reference/*.* files.

The Eclipse help view, if visible, will listen for view or editor activation and selection events. In our example, when it sees one of these events it calls DynamicHelpView.getAdapter(Class) with a request for an IContextProvider.

To get this to work, make a selection and request dynamic help by pressing the F1 key.

public Object getAdapter(Class adapter) {
  if (IContextProvider.class.equals(adapter)) {
    return new ContextProvider(Activator.PLUGIN_ID + ".context_dynamichelpview",
                               (IStructuredSelection) viewer.getSelection());
    }
  return super.getAdapter(adapter);
}

The ContextProvider retrieves the current table selection and returns a SelectionContext which provides the help view with help context resources to display. The help context resources can be related topics links or external links.

public class ContextProvider implements IContextProvider {
  public IContext getContext(Object target) {
    IContext context = HelpSystem.getContext(fContextId);
    if (!fSelected.isEmpty()) {
      context = new SelectionContext(context, fSelected);
    }
    return context;
  }

  public int getContextChangeMask() {
    return SELECTION;
  }
}

The SelectionContext creates a list of IHelpResources. The first is a a single external link to Wikipedia followed by some internal links to related static help. The static help was registered in plugin.xml.

public class SelectionContext implements IContext2 {
  private IHelpResource[] fHelpResources;
  private String fText;
  private String fTitle;

  public SelectionContext(IContext context, IStructuredSelection selection) {
    Assert.isNotNull(selection);
    if (context instanceof IContext2) {
      fTitle = ((IContext2) context).getTitle();
    }
    List helpResources = new ArrayList();
    String label = null;
    StringBuffer location = new StringBuffer("http://en.wikipedia.org/wiki/");
    if (selection.getFirstElement().equals("The Good")) {
      label = "Clint Eastwood " + selection.toString();
      location.append("Man_with_No_Name");
    } else if (selection.getFirstElement().equals("The Bad")) {
      label = "Lee Van Cleef " + selection.toString();
      location.append("Angel_Eyes_%28The_Good%2C_the_Bad_and_the_Ugly%29");
    } else if (selection.getFirstElement().equals("The Ugly")) {
      label = "Eli Wallach " + selection.toString();
      location.append("Tuco_%28The_Ugly%29");
    }
    helpResources.add(new SelectionHelpResource(label, location.toString()));
    // Add static help topics
    if (context != null) {
      IHelpResource[] resources = context.getRelatedTopics();
      if (resources != null) {
        for (int j = 0; j < resources.length; j++) {
          helpResources.add(resources[j]);
        }
      }
    }
    fHelpResources = helpResources.toArray(new IHelpResource[helpResources.size()]);
    if (context != null) {
      fText = context.getText();
    }
    if (fText == null) {
      fText = "";
    }
  }
}

Set a few break points in the plugin to learn how dynamic help works.

There is a small bug 173073 which requires you to hit a few keys to have the help view update its list of links. It has been fixed in Eclipse 3.4 (to be released in June 2008). Don't let this bug stop you from using the dynamic help.

4 comments:

otter606 said...

Thanks for the post, it was really clear and useful.
I am trying to get the 'text' part of the help content to be displayed as html of simple text markup, but annoyingly in the Eclipe Help part all tags except <b> are stripped away and you just get plain text. I hope they make this more extendable in upcoming versions.

vishvesh said...

Hi David,
I am very new to eclipse. I needed to display context help in my plugin and I followed the instructions provided by you and made good progress in setting up context help, but I have hit a road block now. Whenever I run/debug my plugin from elcipse the context help shows up but when I export it as plugin and use it, the context help doesn't show up

My code :
public void createControl(Composite parent) {
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,"myplugin.panic_button");
}

private void openDialog(IProject project){

Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

SignatureWidgetPkgWizard wizard = new SignatureWidgetPkgWizard(project);


WizardDialog wizardDialog = new WizardDialog(shell, wizard);
try{
wizardDialog.create();
}catch(Exception e){
e.printStackTrace();

}
wizardDialog.getShell().setText("Export");
PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, "myplugin.panic_button");
wizardDialog.open();
}

My contextContext.xml


Exports



plugin.xml





I have also noticed that the jar created on export doesn't have context.xml in it. I add context.xml file manually to the jar, is that the reason for this problem ?

Can you please help me in fixing this issue.

David Kyle said...

Take a look at the plugin build.properties file using the plug-in manifest editor. Is the context.xml files selected to be included in the binary build?

vishvesh said...

Thank you very much for posting the context help blog and also for bailing me out David. Looking at it now it's looks like rookie issue.

Thank you very much.