Posts Tagged ‘Commands’

Eclipse 3.6M4 – Tiny nice things

Saturday, December 12th, 2009

I personally believe that little things make a difference. Eclipse 3.6 is going to be great for new (and perhaps also for experienced) plugin and RCP developers.

Especially I like in the Eclipse 3.6M4 release:

-consoleLog included per default in a new launch configuration
RCP with a View

I believe the solution of Bug for -consoleLog will solve the most common problem with getting started for new Plugin / RCP developers. Also the update of the PDE RCP templates will hopefully guide new developers in using commands instead of actions.

The change in Bug for -consoleLog was also a community decision, which is a good example that Eclipse does consider user feedback.

Thanks to all involved parties and the Eclipse community for these changes. :-)

Update Unfortunately Mail Template was not part of M4.

 

Defining menu entries (commands) at runtime in Eclipse RCP

Thursday, December 3rd, 2009

A common question I receive is how menu entries can be defined at runtime in an RCP application. The following gives an example how this can be done.

Create the RCP project “de.vogella.rcp.commands.runtimecommands” using the “Hello RCP” template.

Define a menu contribution. Maintain the class “de.vogella.rcp.commands.runtimecommands.DefineCommands” in this menu contribution.


<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

   <extension
         id="application"
         point="org.eclipse.core.runtime.applications">
      <application>
         <run
               class="de.vogella.rcp.commands.runtimecommands.Application">
         </run>
      </application>
   </extension>
   <extension
         point="org.eclipse.ui.perspectives">
      <perspective
            name="RCP Perspective"
            class="de.vogella.rcp.commands.runtimecommands.Perspective"
            id="de.vogella.rcp.commands.runtimecommands.perspective">
      </perspective>
   </extension>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            class="de.vogella.rcp.commands.runtimecommands.DefineCommands"
            locationURI="menu:org.eclipse.ui.main.menu">
      </menuContribution>
   </extension>

</plugin>

Create the following class.

package de.vogella.rcp.commands.runtimecommands;

import org.eclipse.swt.SWT;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.menus.ExtensionContributionFactory;
import org.eclipse.ui.menus.IContributionRoot;
import org.eclipse.ui.services.IServiceLocator;

public class DefineCommands extends ExtensionContributionFactory {

	@Override
	public void createContributionItems(IServiceLocator serviceLocator,
			IContributionRoot additions) {
		CommandContributionItemParameter p = new CommandContributionItemParameter(
				serviceLocator, "",
				"org.eclipse.ui.file.exit",
				SWT.PUSH);
		p.label = "Exit the application";
		p.icon = Activator.getImageDescriptor("icons/alt_window_16.gif");

		CommandContributionItem item = new CommandContributionItem(p);
		item.setVisible(true);
		additions.addContributionItem(item, null);
	}

}

Run the example, your application should have the Exit command in the menu.

Thanks to Robert Einsle for the tip.

This description has also be added to my Eclipse command tutorial.

 

API for reading Eclipse plugin dependencies

Monday, October 19th, 2009

The Eclipse platform provides an API to allows that you can access in information of the MANIFEST.MF. For example you could read the dependencies of your plugin.

For this example create a plugin “de.vogella.pde.dependencies”. See Eclipse Plugin development for examples on how to develop plugins. Use the “Hello, World Command” template.

Define dependendies to the following plugins:
– org.eclipse.ui
– org.eclipse.core.runtime

Change the command to the following.


package de.vogella.pde.dependencies.handlers;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;

public class PrintDependencies extends AbstractHandler {
	public Object execute(ExecutionEvent event) throws ExecutionException {
		String requireBundle = (String)Platform.getBundle("de.vogella.pde.dependencies").getHeaders().get(
				Constants.REQUIRE_BUNDLE);
				try {
					ManifestElement[] elements = ManifestElement.parseHeader(
					Constants.BUNDLE_CLASSPATH, requireBundle);
					for (ManifestElement manifestElement : elements) {
						System.out.println( manifestElement.getValue());
					}
				} catch (BundleException e) {
					e.printStackTrace();
				}
		return null;
	}
}

If you now run your new plugin it and select your command it will print out the dependencies of your plugin.

 

Eclipse Papercut #6 – Modifying Mylyn Context

Monday, October 5th, 2009

In this episode of Eclipse Papercuts I will demonstrate how to modify the Mylyn tasks context. Many thanks to David Green for providing sample code to access the Mylyn context.

Mylyn makes certain assumptions how the developer works. If you start a new task the Mylyn context is empty and fills up based on the selected files.

Which is not always the way I work. Frequently I know that for my task a whole package (or project) is relevant. I would like to include all classes in this package / project in my Mylyn task.

Ok, lets see how we can solve this papercut. I describe how to add Java classes from a package to an active task.

Create an command which extends the package explorer with a new popup commands as described here Extend the package explorer.

Create the command handler with the following coding:


package de.vogella.mylyn.tasksmodify.handlers;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.context.core.IInteractionContext;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.monitor.core.InteractionEvent;
import org.eclipse.mylyn.monitor.core.InteractionEvent.Kind;
import org.eclipse.ui.handlers.HandlerUtil;

public class SampleHandler extends AbstractHandler {
	public Object execute(ExecutionEvent event) throws ExecutionException {

		IStructuredSelection selection = (IStructuredSelection) HandlerUtil
				.getActiveMenuSelection(event);
		if (selection ==null){
			return null;
		}

		Object firstElement = selection.getFirstElement();

		if (firstElement instanceof IPackageFragment) {
			IPackageFragment mypackage = (IPackageFragment) firstElement;
			try {
				if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE){
					 ICompilationUnit[] compilationUnits = mypackage.getCompilationUnits();
					 for (ICompilationUnit iCompilationUnit : compilationUnits) {
						 IInteractionContext activeContext = ContextCore.getContextManager()
							.getActiveContext();
						 ContextCorePlugin.getContextManager().processInteractionEvent(iCompilationUnit,
									Kind.PROPAGATION, InteractionEvent.ID_UNKNOWN, activeContext);
					}
				}
			} catch (JavaModelException e) {
				e.printStackTrace();
			}
		}

		return null;
	}
}

Launch your plugin. Create a Mylyn task and select a package in the package explorer. Select your commands and all files of this package will be added to the task.

Further reading: If you want to access other Java Elements, e.g. Project and add them to the Mylyn task this tutorial might help you: Eclipse JDT.

Please note that ContextCorePlugin is supposed to be internal API but I did not find another way of accessing the Mylyn tasks.

 

Eclipse PDE templates – Your action is my command

Wednesday, September 23rd, 2009

The Eclipse PDE templates are fantastic to help people to learn the platform and to get oven the first initial resistence to start with Eclipse RCP or Eclipse Plugin development.

Templates indicates to their consumers that they represent best development practices. This puts a certain burden on the quality to the templates. Unfortunately the PDE RCP templates in Eclipse 3.5 were all based on actions which I believe are superseded by Eclipse Commands.

I have seen in the past lots of questions regarding actions in the Eclipse RCP and PDE newsgroups. I believe that at least some of these questions are based on the fact that the PDE templates still promote actions.

I’m therefore happy to see the changes of Bug 265231 applied for the “RCP with a view” template for the upcoming Eclipse 3.6. Special thanks for this to Chris Aniszczyk.

It also looks good for the mail example. It seems that work is happening in Bug 253105

Actions are (a little bit more) dead. Long live the command! ;-)

 

Add the error log view to your Eclipse RCP application

Monday, August 17th, 2009

The Eclipse platform provide error message in case something goes wrong.

During development I use the launch parameter -consoleLog to see if any error has occured. I assume most plugin developer use -consoleLog that is why I opened Bug for making -consoleLog a default in a new launch configuration.

Obviously you don’t want your users to check the console for errors. To make errors visible to the user you can add the exiting error log to your RCP application.

Create a new Eclipse RCP project “de.vogella.rcp.intro.errorview” for this purpose. Use the “Hello RCP” as a template.

Select the plugin.xml and add the dependency to org.eclipse.ui.views.log.

Ddd the standard Eclipse command “org.eclipse.ui.views.showView” to your menu under the Entry “Admin”. See Eclipse Commands how to do this.

This will result in the following plugin.xml


<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

   <extension
         id="application"
         point="org.eclipse.core.runtime.applications">
      <application>
         <run
               class="de.vogella.rcp.intro.errorview.Application">
         </run>
      </application>
   </extension>
   <extension
         point="org.eclipse.ui.perspectives">
      <perspective
            name="RCP Perspective"
            class="de.vogella.rcp.intro.errorview.Perspective"
            id="de.vogella.rcp.intro.errorview.perspective">
      </perspective>
   </extension>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="menu:org.eclipse.ui.main.menu">
         <menu
               label="Admin">
            <command
                  commandId="org.eclipse.ui.views.showView"
                  label="Show Error View"
                  style="push">
               <parameter
                     name="org.eclipse.ui.views.showView.viewId"
                     value="org.eclipse.pde.runtime.LogView">
               </parameter>
            </command>
         </menu>
      </menuContribution>
   </extension>

</plugin>

Run your new application. You should have a menu entry “Admin” with an entry “Show Error View”. If you select it the error view should open.

errorLogView10

 

Eclipse Activities – Hide / Display certain UI elements

Monday, July 13th, 2009

Eclipse Activities can be used to hide / display certain UI elements, for example based on the role of the user. The related extension point is “org.eclipse.ui.activities”. A common use case for using activities is authorization, e.g. certain user get to see only a certain part of the ui which fits to their role.

Via activities you can for example restrict:

  • Editors
  • Views
  • Menus
  • Wizards

You define first the activities and then one or several activityPatternBindings. The activityPatternBindings defines which UI elements belong to an activities. These elements will only be displayed if the activity is set to true.

The Eclipse workbench will automatically persists activated activities.

The following will demonstate how activities can be used.

Create a new Eclipse RCP project “de.vogella.rcp.activities” based on the “Hello RCP” template.

Add a view “de.vogella.rcp.activities.view” to your RCP application and add this view via “org.eclipse.ui.perspectiveExtensions” to your application. The view should have the id “de.vogella.rcp.activities.view”. This view will later be filtered by the activity.

See Eclipse RCP Tutorial for how to create a view and add it to the perspective.

Add now two commands “de.vogella.rcp.activities.activate” and “de.vogella.rcp.activities.deactivate” with the following default handler to your application. Comands are in detail described in Eclipse Commands.


package de.vogella.rcp.activities.handler;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.activities.IActivityManager;
import org.eclipse.ui.activities.IWorkbenchActivitySupport;
import org.eclipse.ui.handlers.HandlerUtil;

public class Activate extends AbstractHandler {

@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchActivitySupport activitySupport = HandlerUtil
.getActiveWorkbenchWindow(event).getWorkbench()
.getActivitySupport();
IActivityManager activityManager = activitySupport.getActivityManager();
Set enabledActivities = new HashSet();
String id = "de.vogella.rcp.activities.view";
if (activityManager.getActivity(id).isDefined()) {
enabledActivities.add(id);

}
activitySupport.setEnabledActivityIds(enabledActivities);
return null;
}

}

package de.vogella.rcp.activities.handler;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.activities.IWorkbenchActivitySupport;
import org.eclipse.ui.handlers.HandlerUtil;

public class DeActivate extends AbstractHandler {

@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchActivitySupport activitySupport = HandlerUtil
.getActiveWorkbenchWindow(event).getWorkbench()
.getActivitySupport();
Set<String> enabledActivities = new HashSet<String>();
activitySupport.setEnabledActivityIds(enabledActivities);
// Now I have to reset the perspective to update also the views
HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().resetPerspective();
return null;
}
}

Add both commands to the menu.

Add also the standard command “org.eclipse.ui.views.showView” to your menu. This command will later also be filtered by the activity.

Now add the extension point “org.eclipse.ui.activities”. Add an activity with the id “de.vogella.rcp.activities.view”. As you see above this activity will be activated / deactivated by the commands from above.

Add then two activityPatternBinding to your extension point. To assign a ui element to an activity you can use patterns ( isEqualityPattern=false) or Strings ( isEqualityPattern=true). The first part of the pattern / string is the plug-in id and the second part is the UI element.

For example the correct String for the view is: “de.vogella.rcp.activities/de.vogella.rcp.activities.view”.

After doing this your extension point should look like this in plugin.xml:

   <extension
         point="org.eclipse.ui.activities">
      <activity
            id="de.vogella.rcp.activities.view"
            name="Activate View">
      </activity>
      <activityPatternBinding
            activityId="de.vogella.rcp.activities.view"
            isEqualityPattern="false"
            pattern="de.vogella.rcp.activities/de.vogella.rcp.activities.view">
      </activityPatternBinding>
      <activityPatternBinding
            activityId="de.vogella.rcp.activities.view"
            isEqualityPattern="true"
            pattern="de.vogella.rcp.activities/org.eclipse.ui.views.showView">
      </activityPatternBinding>
   </extension>

If you run your application the view and menu item should not be there. If you press your command “Activate” then the view and the menu should get displayed. If you stop and re-start the application the activity should be still active as it gets persisted.

If you press your command “Deactivate” then the menu and the view is removed.

Activities can also be used together with core expressions and your own define expressions (which you define via ISourceProvider). See Eclipse Commands – Own expressions on how to define them.

Expression based activities are even better for defining authorization in your application as they will ignore API calls to them.

The full project can be downloaded here:

de.vogella.rcp.activities

 

Eclipse Papercut #1 – The annoying creation of the project package

Monday, July 6th, 2009

This series is about simplifying the handling of Eclipse for simple but repetitive tasks. See 7 Paper Cuts in Eclipse.

Ok lets start with something simple.

By convension Eclipse projects are named based on reverse URL’s, e.g. “org.eclipse.jdt” or “de.vogella.test”. Also this convension suggests to create a package with the same name as the project. For this you have to select the src folder in the project, right click on it, select New – Package then copy the name of the project from the first line and paste it into the second line of the dialog.

papercut1_10

While you may argue that this is not to bad as the amount of project you are creating is limited; I personally find this annoying as I’m writting lots of example for my articles on http://www.vogella.de/.

Time to simplify (at least a little bit).

Create an Eclipse plug-in called “de.vogella.jdt.packageexplorer”. Add a Eclipse command to it with the following default handler.


package de.vogella.jdt.packageexplorer.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFolder;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.handlers.HandlerUtil;

public class AddPackage extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {

		IStructuredSelection selection = (IStructuredSelection) HandlerUtil
				.getActiveMenuSelection(event);
		Object firstElement = selection.getFirstElement();
		if (firstElement instanceof IJavaProject) {
			IJavaProject javaProject = (IJavaProject) firstElement;
			try {
				IFolder folder = javaProject.getProject().getFolder("src");
				// folder.create(true, true, null);
				IPackageFragmentRoot srcFolder = javaProject
						.getPackageFragmentRoot(folder);
				srcFolder.createPackageFragment(javaProject.getProject()
						.getName(), true, null);
			} catch (JavaModelException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
}

Add this command to the content menu in the package explorer as described in Eclipse plug-in Development.

The resulting plugin.xml looks like the following:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:org.eclipse.jdt.ui.PackageExplorer">
         <command
               commandId="de.vogella.jdt.packageexplorer.AddPackage"
               label="Add Default Package"
               style="push">
         </command>
      </menuContribution>
   </extension>
   <extension
         point="org.eclipse.ui.commands">
      <command
            defaultHandler="de.vogella.jdt.packageexplorer.handler.AddPackage"
            id="de.vogella.jdt.packageexplorer.AddPackage"
            name="Add Default Package">
      </command>
   </extension>

</plugin>

Export your plug-in and put it into the dropin folder in your Eclipse installation. Restart Eclipse.

If you now create a new project you can right click on the project and directly create your project / default package.

papercut1_30

If you want to improve this further you can assign a keybinding to your command and use a shortcut to create the package. Or if you have more artifacts to create you can use the handler to create .java files, more packages, etc.

Here is the source bundle to download:
de.vogella.jdt.packageexplorer.source_1.0.0

Here is the exported plugin (you need you rename zip to jar before putting this into the Eclipse/dropin folder)

de.vogella.jdt.packageexplorer_1.0.0

See Eclipse Papercuts to get all posts in this series.

 

Eclipse RCP File browser

Tuesday, June 23rd, 2009

Eclipse RCP allow you to create easily utility programs.

Lets for example create a mini-file browser which will open a folder / file if you double-click the selection via the standard program.

To create a RCP based file browser create a new Eclipse RCP project, e.g. de.vogella.rcp.intro.filebrowser.

Create a package “de.vogella.rcp.intro.filebrowser.provider” and create the following label and content provider.


package de.vogella.rcp.intro.filebrowser.provider;

import java.io.File;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class FileContentProvider implements ITreeContentProvider {

@Override
public Object[] getChildren(Object parent) {
File file = (File) parent;
return file.listFiles();
}

public Object[] getElements(Object inputElement) {
return (Object[]) inputElement;
}

@Override
public Object getParent(Object element) {
File file = (File) element;
return file.getParentFile();
}

@Override
public boolean hasChildren(Object parent) {
File file = (File) parent;
return file.isDirectory();
}

@Override
public void dispose() {

}

@Override
public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
}

}

package de.vogella.rcp.intro.filebrowser.provider;

import java.io.File;

import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;

public class FileLabelProvider extends LabelProvider {
private static final Image folderImage = AbstractUIPlugin
.imageDescriptorFromPlugin("de.vogella.rcp.intro.filebrowser",
"icons/folder.gif").createImage();
private static final Image driveImage = AbstractUIPlugin
.imageDescriptorFromPlugin("de.vogella.rcp.intro.filebrowser",
"icons/filenav_nav.gif").createImage();
private static final Image fileImage = AbstractUIPlugin
.imageDescriptorFromPlugin("de.vogella.rcp.intro.filebrowser",
"icons/file_obj.gif").createImage();

@Override
public Image getImage(Object element) {
File file = (File) element;
if (file.isDirectory())
return file.getParent() != null ? folderImage : driveImage;
return fileImage;
}

@Override
public String getText(Object element) {
String fileName = ((File) element).getName();
if (fileName.length() > 0) {
return fileName;
}
return ((File) element).getPath();
}
}

For the label provider you need the referred icons in your folder icons. You can use the following download.

Download the Icons

Adjust then the view.

package de.vogella.rcp.intro.filebrowser;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;

import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

import de.vogella.rcp.intro.filebrowser.provider.FileContentProvider;
import de.vogella.rcp.intro.filebrowser.provider.FileLabelProvider;

public class View extends ViewPart {
	public static final String ID = "de.vogella.rcp.intro.filebrowser.view";
	private TreeViewer viewer;

	public void createPartControl(Composite parent) {
		viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
		viewer.setContentProvider(new FileContentProvider());
		viewer.setLabelProvider(new FileLabelProvider());
		viewer.setInput(File.listRoots());
		viewer.addOpenListener(new IOpenListener() {

			@Override
			public void open(OpenEvent event) {
				IStructuredSelection selection = (IStructuredSelection) event
						.getSelection();

				File file = (File) selection.getFirstElement();
				if (Desktop.isDesktopSupported()) {
					Desktop desktop = Desktop.getDesktop();
					if (desktop.isSupported(Desktop.Action.OPEN)) {
						try {
							desktop.open(file);
						} catch (IOException e) {
							// DO NOTHING
						}
					}
				}
			}
		});
	}

	public void setFocus() {
		viewer.getControl().setFocus();
	}
}