{"id":995,"date":"2011-01-07T14:34:08","date_gmt":"2011-01-07T13:34:08","guid":{"rendered":"http:\/\/sahits.ch\/blog\/?p=995"},"modified":"2011-01-07T14:43:54","modified_gmt":"2011-01-07T13:43:54","slug":"context-help-in-eclipse-revisited","status":"publish","type":"post","link":"http:\/\/sahits.ch\/blog\/blog\/2011\/01\/07\/context-help-in-eclipse-revisited\/","title":{"rendered":"Context Help in Eclipse revisited"},"content":{"rendered":"<p>Earlier this week Paul (who by the way took over the PHP class generator and revived it) asked me for help with help. Basically he had a problem of integrating context sensitive help into the plug-in. He read my earlier <a href=\"http:\/\/sahits.ch\/blog\/?p=448\">article on this topic<\/a> but could not manage. Therefore I promise to have a look.<!--more--><br \/>\nI must say this topic is not trivial and not entirely implemented in an obvious fashion. Further more my earlier article leaves some points a bit unclear. Therefore I stumbled a couple of times doing the implementation (not having reread my article). Therefore here we go in a second attempt. In implementing this I had the advantage of a project (<a href=\"https:\/\/sourceforge.net\/projects\/codegenjava\/develop\">Code Generator<\/a>) I could use for &#8222;cheating&#8220;.<br \/>\nThe aim is to add a context help for the file name input field of the PHP DB class generator on the first wizard page.<\/p>\n<h2>Prerequirements<\/h2>\n<h3>or the first step<\/h3>\n<p>For the context help we need the plugin org.eclipse.help which we add to the manifest in the section Required-Bundle.<br \/>\nNow we can add the extension point for the context help in the plugin.xml:<\/p>\n<pre class=\"brush:xml\">&lt;extension point=\"org.eclipse.help.contexts\"&gt;\r\n     &lt;contexts file=\"contextHelp.xml\" plugin=\"ch.sahits.phpclassgenerator\"\/&gt;\r\n     &lt;contextProvider class=\"org.eclipse.help.internal.context.ContextFileProvider\"\/&gt;\r\n&lt;\/extension&gt;<\/pre>\n<p>In the element <code>contexts<\/code> the attribute <code>plugin <\/code>defines the plug-in where the help contents is provided. I do not think that any other value than the plug-in ID of the current plug-in makes any sense. The attribute <code>file<\/code> defines an XML file that holds the context help information. The <code>contextProvider<\/code> is the class that is invoked to retrieve the help context.<\/p>\n<h2>Providing the contents<\/h2>\n<h3>or the creative work<\/h3>\n<p>As mentioned in the above section we need a file named <code>contextHelp.xml<br \/>\n<\/code> that defines our context help. This XML file can be viewed as table of contents. It defines the different contexts under which help is available and defines URLs to HTML pages that actually contain the help contents. The contextHelp.xml file is located in the root of the project, alongside the plugin.xml:<\/p>\n<pre class=\"brush:xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;contexts&gt;\r\n\t&lt;context id=\"filename\" title=\"File name\"&gt;\r\n\t\t&lt;decription&gt;Help for file name input field&lt;\/decription&gt;\r\n\t\t&lt;topic href=\"html\/context\/filename.html\" label=\"File name\"\/&gt;\r\n\t&lt;\/context&gt;\r\n&lt;\/contexts&gt;<\/pre>\n<p>The XML can define several contexts that are all defined under the <code>contexts<\/code> root element. In this example there is only one. The\u00a0 <code>title<\/code> attribute comes in handy when there are several topics per context ID. Then all topics are listed as links under the given title. The <code>id<\/code> attribute is the most important one. It is the unique identification of the context per plugin. Basically this means that the id must be unique within this XML. The <code>description<\/code> element is displayed when several topics are available as a short explanation. Finally there is the <code>topic<\/code> element that defines the URL of the help contents that is to be displayed. The <code>label<\/code> is used as title if there are multiple topics defined for one context ID. If there is only one topic the contents of the HTML file is displayed directly and the title, description and label are obsolete.<\/p>\n<p>I suppose that the structure of this XML is inherently linked to the context provider that is defined in the extension point of the plugin.xml.<\/p>\n<p>In the HTML file you can provide anything as long as it is helpful in the context. The HTML file has to be located at the designated location relative to the projects root:<\/p>\n<pre class=\"brush:xml\">&lt;!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/html4\/loose.dtd\"&gt;\r\n&lt;html&gt;\r\n&lt;head&gt;\r\n&lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\"&gt;\r\n&lt;title&gt;File name input field&lt;\/title&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n&lt;h1&gt;File name&lt;\/h1&gt;\r\n&lt;p&gt;What is the filename&lt;\/p&gt;\r\n&lt;h1&gt;Input field&lt;\/h1&gt;\r\n&lt;p&gt;Which inputfield&lt;\/p&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<h2>Calling the context help<\/h2>\n<h3>or stitching all together<\/h3>\n<p>The most simple way to call the context help is to provide a button that calls the help that is appropriate for the context. There are multiple ways. The most simple one is to provide a button for each context. O you can have one button and figuring out the correct context when clicking it. Furthermore there is the context help button on each wizard page that can be used. This however is another story. I will add add a button to the input field that opens the context help.<br \/>\nFor the simplicity let&#8217;s create a helper method that creates a help button into a parent container without any functionality:<\/p>\n<pre class=\"brush:java\">\/**\r\n * Create a help button with the help icon on it.\r\n * No action is associated with the button\r\n * @param container parent container\r\n * @return created button\r\n *\/\r\nprivate Button createHelpButton(Composite container) {\r\n\tButton help = new Button(container,SWT.PUSH);\r\n\tImage img = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_LCL_LINKTO_HELP);\r\n\thelp.setImage(img);\r\n\treturn help;\r\n}<\/pre>\n<p>The neat thing about this method is that the created button displays Eclipse&#8217;s standard help icon. Now we can create our button and add the functionality to call the appropriate context:<\/p>\n<pre class=\"brush:java\">final String ECLIPSE_HELP = \"org.eclipse.ui.help\";\r\nButton help = createHelpButton(container);\r\nhelp.addSelectionListener(new SelectionAdapter() {\r\n\t\/**\r\n\t * Open the context help for the file name input field\r\n\t *\/\r\n\t@Override\r\n\tpublic void widgetSelected(SelectionEvent e) {\r\n\t\tString contextHelpID = \"ch.sahits.phpclassgenerator.filename\";\r\n\t\tgetShell().setData(ECLIPSE_HELP,contextHelpID);\r\n\t\tPlatformUI.getWorkbench().getHelpSystem().displayHelp(contextHelpID);\r\n\t}\r\n});\r\n<\/pre>\n<p>The most important part is the definition of the String contextHelpID. It is composed of the plug-in ID of the plug-in that provides the context help, (this might be a different plug-in than the one from where the button is defined) and the ID as it is defined in the contextHelp.xml. Anything other just simply will not work as I had to find out. The cause for this lies in the class org.eclipse.help.internal.context.ContextManager which retrieves the instance of the context:<\/p>\n<pre class=\"brush:java\">\t\/*\r\n\t * Returns the Context for the given id and locale.\r\n\t *\/\r\n\tpublic IContext getContext(String contextId, String locale) {\r\n\r\n\t\tif (HelpPlugin.DEBUG_CONTEXT  &amp;&amp; contextId != null) {\r\n\t\t\tSystem.out.println(\"ContextManager.getContext(\\\"\" + contextId + \"\\\")\"); \/\/$NON-NLS-1$ \/\/$NON-NLS-2$\r\n\t\t}\r\n\r\n\t\t\/\/ ask the providers\r\n\t\tint index = contextId.lastIndexOf('.');\r\n\t\tif (index != -1) {\r\n\t\t\tString pluginId = contextId.substring(0, index);\r\n\t\t\tIterator iter = getContextProviders(pluginId).iterator();\r\n\t\t\twhile (iter.hasNext()) {\r\n\t\t\t\tAbstractContextProvider provider = (AbstractContextProvider)iter.next();\r\n\t\t\t\ttry {\r\n\t\t\t\t\tIContext context = provider.getContext(contextId, locale);\r\n\t\t\t\t\tif (context != null) {\r\n\t\t\t\t\t\tif (HelpPlugin.DEBUG_CONTEXT) {\r\n\t\t\t\t\t\t\tSystem.out.println(\"ContextManager.getContext found context, description = \\\"\" + context.getText() + '\"'); \/\/$NON-NLS-1$\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\treturn new Context(context, contextId);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcatch (Throwable t) {\r\n\t\t\t\t\t\/\/ log and skip\r\n\t\t\t\t\tString msg = \"Error querying context provider (\" + provider.getClass().getName() + \") with context Id: \" + contextId; \/\/$NON-NLS-1$ \/\/$NON-NLS-2$\r\n\t\t\t\t\tHelpPlugin.logError(msg, t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n                \/\/ snipped out some none relevant code\r\n               \u00a0return null;\r\n\t}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Earlier this week Paul (who by the way took over the PHP class generator and revived it) asked me for help with help. Basically he had a problem of integrating context sensitive help into the plug-in. He read my earlier article on this topic but could not manage. Therefore I promise to have a look.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,138,7,6],"tags":[178,304,177],"class_list":["post-995","post","type-post","status-publish","format-standard","hentry","category-eclipse","category-it","category-java","category-programmieren","tag-context","tag-eclipse","tag-help"],"_links":{"self":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts\/995","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/comments?post=995"}],"version-history":[{"count":4,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts\/995\/revisions"}],"predecessor-version":[{"id":998,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts\/995\/revisions\/998"}],"wp:attachment":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/media?parent=995"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/categories?post=995"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/tags?post=995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}