Imediava's Blog

Just another WordPress.com site

Tag Archives: GroovyMonkey

Using Eclipse completion features in your own plug-in

One of the coolest things I found when I first moved to Eclipse was code completion. It was useful and pretty, it allowed me to save typing and it provided useful information in a visually appealing way.

When you’re developing your own plugin for Eclipse you want it to be as cool as possible, so using Eclipse code completion system may come to your mind.

However I could not find many examples online about how to benefit from the system from a plugin developer’s perspective. This post is my try to facilitate the task of familiarizing with the tool. It’s an extension from some of the few links I’ve found with useful and simple information about the subject (http://www.eclipsezone.com/eclipse/forums/t83426.html) .

As the link says, it’s really easy to add content assistance to a text field. Just the following two lines do the trick:

Text t = new Text(parent, SWT.BORDER) // your SWT text field
ContentProposalAdapter adapter = new ContentProposalAdapter( t,
	new TextContentAdapter(),
	new SimpleContentProposalProvider(new String [] {"A", "B", "C"}),
	null,  null)

However there’s a few things that we can modify in the example to give the proposals a better, more Eclipse-like behaviour. The code for the examples is going to be coded with groovyMonkey but translating it to Java it’s fairly simple.

First thing I want to change is the filtering behaviour. With the code from the first example the suggestion is not affected by a change in the text field content. However when developing a plugin what we usually want is that only the proposals that match the typed text are shown. This can be modified enabling the filtering for the proposals provider:

proposalsProvider = new SimpleContentProposalProvider(proposals)
proposalsProvider.setFiltering(true)

The next behaviour we can replace is the way the proposals accepted are handled. The default behaviour is appending the proposal text to the text field content, but that’s not the way we usually want our assistant to behave. What we usually want is to set the selected proposal as the current text for the field. To get that, all we have to do is modify the “acceptance style” to PROPOSAL_REPLACE:

adapter = new ContentProposalAdapter( nameText,  new TextContentAdapter(), proposalsProvider, null,  null)
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE)

A bigger example

Finally I’m gonna show how the whole code works in a bigger example. Thanks to groovyMonkey features, playing with Eclipse API is quite easy. I’m gonna use this features to take the names of all the user-defined types in the workspace. This can be done using groovyMonkey with the following snippet:

List types = []
workspace.root.projects.each { project ->

   //selects only the java projects
   if (project.isOpen() && project.isNatureEnabled("org.eclipse.jdt.core.javanature")){
 	   javaProject = JavaCore.create(project)
	   roots = javaProject.getPackageFragments()

	   // Filters the source code packages
	   .findAll{ fragment -> fragment.getKind() == IPackageFragmentRoot.K_SOURCE}

	   .each { fragment ->
	 	    fragment.compilationUnits.each { compilationUnit ->

	 	        for(type in compilationUnit.getAllTypes()){
	 	        	types.add(type.getElementName())
	 	        }
	 	    }

	   }

   }
}

Now I can create a really simple wizard with a text field that uses all the code completion features I have talked about in the post. When the content of the field is modified it suggests user-defined types from the workspace.

/*
 * Menu: CodeCompletion
 * Script-Path: /GroovyMonkeyScripts/propios/CodeCompletion.gm
 * Kudos: imediava
 * License: EPL 1.0
 * Job: UIJob
 */

def wizardDialog1

import org.eclipse.swt.widgets.Text;

import org.eclipse.jface.fieldassist.ContentProposalAdapter
import org.eclipse.jface.fieldassist.SimpleContentProposalProvider
import org.eclipse.jface.fieldassist.TextContentAdapter

import org.eclipse.core.resources.*
import org.eclipse.jdt.core.IPackageFragmentRoot
import org.eclipse.core.runtime.Path
import org.eclipse.jdt.core.JavaCore

List types = []
workspace.root.projects.each { project ->

   //selects only the java projects
   if (project.isOpen() && project.isNatureEnabled("org.eclipse.jdt.core.javanature")){
 	   javaProject = JavaCore.create(project)
	   roots = javaProject.getPackageFragments()

	   // Filters the source code packages
	   .findAll{ fragment -> fragment.getKind() == IPackageFragmentRoot.K_SOURCE}

	   .each { fragment ->
	 	    fragment.compilationUnits.each { compilationUnit ->

	 	        for(type in compilationUnit.getAllTypes()){
	 	        	types.add(type.getElementName())
	 	        }
	 	    }

	   }

   }
}

mainapp = jface.shell( window.getShell()) {

	wizardDialog1 = wizardDialog() {

				wizardPage1 = wizardPage( title:"Step 1", description:"Step 1", closure: { parent ->

					jface.composite( parent ) {
						gridLayout( numColumns : 2, verticalSpacing: 20)

						label( text: "Name" )
						nameText = text(style: "border")

						proposals = types.toArray(new String[0])
						proposalsProvider = new SimpleContentProposalProvider(proposals)
						proposalsProvider.setFiltering(true)
						adapter = new ContentProposalAdapter( nameText,  new TextContentAdapter(), proposalsProvider, null,  null)
						adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE)
					}
				})
	}

  	wizardDialog1.open()

	wizardPage1.setPageComplete(false)
}

I’ll leave for following posts other changes that can improve the assistant’s look and behaviour like adding icons next to every proposal.

Create search for type dialog with Eclipse JDT API

If you’ve ever wondered how to get the cool window that allow you to select a class type in Eclipse (see the snapshot above) and reuse it for your plugin, the good news are that doing so is fairly simple.

Selec type window

You just have to decide what types you want Eclipse to allow the user to chose. If you want Eclipse to allow any type within a project, get the reference to the project and pass it to JavaUI.createTypeDialog(). Here’s how to do it with groovyMonkey:

/*
 * Menu: Remove Markers
 * Script-Path: /GroovyMonkeyScripts/propios/seleccion_classes.gm
 * Kudos: ERVIN
 * License: EPL 1.0
 * Job: UIJob
 * DOM: http://groovy-monkey.sourceforge.net/update/plugins/net.sf.groovyMonkey.dom
 */

import org.eclipse.jdt.core.JavaCore
import org.eclipse.jdt.core.search.SearchEngine
import org.eclipse.jdt.ui.JavaUI
import org.eclipse.jdt.ui.IJavaElementSearchConstants
import org.eclipse.jdt.core.IJavaElement
import org.eclipse.jface.dialogs.ProgressMonitorDialog

project = workspace.root.projects.find { project -> project.isOpen() && project.isNatureEnabled("org.eclipse.jdt.core.javanature")}
javaProject = JavaCore.create(project)
typeDialog = JavaUI.createTypeDialog(window.getShell(), new ProgressMonitorDialog(window.getShell()),
                                     project,
                                     IJavaElementSearchConstants.CONSIDER_TYPES,
                                     false)
typeDialog.open()

// Type selected by the user
result = typeDialog.getResult()

First you get the project from the workspace and then you need to use JavaCore.create() to get a reference to it as an IJavaProject.

If you want to be picky and decide what specific types you want to be int the dialog, you can do so using SearchEngine.createJavaSearchScope(). Here’s an example on how to add any type in any open Java project in the workspace to the dialog:

/*
 * Menu: Remove Markers
 * Script-Path: /GroovyMonkeyScripts/propios/seleccion_classes.gm
 * Kudos: ERVIN
 * License: EPL 1.0
 * Job: UIJob
 * DOM: http://groovy-monkey.sourceforge.net/update/plugins/net.sf.groovyMonkey.dom
 */

import org.eclipse.jdt.core.JavaCore
import org.eclipse.jdt.core.search.SearchEngine
import org.eclipse.jdt.ui.JavaUI
import org.eclipse.jdt.ui.IJavaElementSearchConstants
import org.eclipse.jdt.core.IJavaElement
import org.eclipse.jface.dialogs.ProgressMonitorDialog

import org.eclipse.core.resources.*
import org.eclipse.jdt.core.IPackageFragmentRoot
import org.eclipse.core.runtime.Path

List types = []
workspace.root.projects.each { project ->

   //selects only the java projects
   if (project.isOpen() && project.isNatureEnabled("org.eclipse.jdt.core.javanature")){
 	   javaProject = JavaCore.create(project)
	   roots = javaProject.getPackageFragments()

	   // Filters the source code packages
	   .findAll{ fragment -> fragment.getKind() == IPackageFragmentRoot.K_SOURCE}

	   .each { fragment ->
	 	    fragment.compilationUnits.each { compilationUnit ->
	 	        types.addAll(compilationUnit.getAllTypes())
	 	    }

	   }

   }
}

searchScope = SearchEngine.createJavaSearchScope(types.toArray(new IJavaElement[0]))
typeDialog = JavaUI.createTypeDialog(window.getShell(),
                                  new ProgressMonitorDialog(window.getShell()),
                                  searchScope,
                                  IJavaElementSearchConstants.CONSIDER_TYPES,
                                  false)
typeDialog.open()

// Type selected by the user
result = typeDialog.getResult()
%d bloggers like this: