Content Sensitive Object Contributions

Last modified December 10, 2003

Context menus for some applications have previously only been able to exclude some menu options based on peripheral information known about the resources selected (the number of resources selected, the physical name of the file, the type of the resource, etc.). There are some cases where a restricted amount of information, known about the contents of the resource would significantly reduce unusable options from the menus. The first area targeted is that of XML files. There are numerous situations where an action is applicable for one type of XML file but not another. For example, some XML files contain Ant scripts. The action "Run Ant..." makes sense in its context menu. But this action is not applicable to an XML file used to define a plug-in.

It will now be possible to define object contributions which are specific to an XML file with a given top level tag or which specify a given DTD. The objectState key of an ActionExpression will be used to specify these values as follows:

<objectState name="xmlFirstTag" value="tagValue"/>

<objectState name="xmlDTDName" value="dtdValue"\>

where tagValue represents the name of the top level tag to match and

dtdValue represents the name of the DTD as seen in the XML file.

Consider the following object contribution in a plugin.xml file:

   <extension point = "org.eclipse.ui.popupMenus">
     <objectContribution
	    id="org.eclipse.ui.examples.objectContributions"
		objectClass="org.eclipse.core.resources.IFile"
		nameFilter="*.xml">
		<visibility>
			<or>
			  <objectState name="xmlFirstTag" value="myTag"/>
			  <objectState name="xmlDTDName" value="myDTD.xml"/>
			</or>
	    </visibility>
		<action id="org.eclipse.ui.examples.objectContributions.action1"
		   label="%PopupMenus.action"
		   icon="icons/ctool16/openbrwsr.gif"
		   menubarPath="additions"
		   class="org.eclipse.ui.examples.objectContributions.PopupMenuActionDelegate"
		   enablesFor="1">
		</action>
	  </objectContribution>
	</extension>

This will make action1 visible for any IFile with a name matching *.xml provided it contains myTag as the top level XML tag or it uses the DTD called myDTD.xml. So the following XML files will match:

<?xml version="1.0" encoding="UTF-8"?>
<myTag
  id="org.eclipse.ui.workbench"
  name="%pluginName"
  version="3.0.0"
  provider-name="%providerName"
  class="org.eclipse.ui.internal.WorkbenchPlugin">
</myTag>

Or

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Book SYSTEM "myDTD.xml">
<fragment
   id="org.eclipse.ui.workbench"
   name="%pluginName"
	version="3.0.0"
	provider-name="%providerName"
	class="org.eclipse.ui.internal.WorkbenchPlugin">
	<runtime>
	   <library name="workbench.jar">
	      <export name="*"/>
		  <packages prefixes="org.eclipse.ui, org.eclipse.jface"/>
	   </library>
	</runtime>
</fragment>

A new parser, called PropertyParser, will be used to collect this information. This parser will be a SAX based parser as we don't necessarily need to parse the entire file.

New persistent properties will be stored for any file that requires this information. First, a property called "xmlLastMod" will be used to store the last modified time of the file (as know by IResource). This will ensure that we don't re-parse this file if it isn't necessary. Two other properties, "xmlFirstTag" and "xmlDTDName" will be used to store the name of the root level tag and a DTD file (if specified) respectively. Note that if the parser is called for either one of these, both will be stored (if they exist). The structure of XML dictates that the DTD specification, if it exists, must occur before the root level tag. As a result, once PropertyParser has parsed to the root level tag, it's work is done. At this point, all other parsing is stopped.

Any exceptions thrown by the parser are output to the .log file. PropertyParser will explicitly test for an empty file as many SAX parsers will throw an exception if they encounter an XML file without a root level tag.

It should be noted that if a DTD is specified in a file, Crimson, a commonly used SAX parser in Eclipse, requires that the DTD file exists and is readable. If this is not the case, a SAXException will be thrown. The PropertyParser does not require the DTD to be present, but the underlying parser often does.

Related Bug Reports

33018 - [Contributions] plugin.xml context menu should not have "Run Ant..." item

45024 - JAXP and old Xerces functionality