Showing posts with label rcp. Show all posts
Showing posts with label rcp. Show all posts

Saturday, February 20, 2010

CopyTo...Pastebin (and others) Plug-In for Eclipse

The situation

Do you hang out in IRC channels often? And do you use pastebin.com or other services to show the users snippets of your source code that illustrates a problem you have? Then you no longer need to switch between your Eclipse IDE, a webbrowser and the IRC chat window.

A small solution that can save time

I have finished today the first alpha version of a small Eclipse Plugin that adds a new menu and toolbar button to the Eclipse Workbench.

In its basic version it allows you to click any resource in the Package/Project Explorer and copies the content of the resource to the pastebin service of your choice. I have created some default configurations for the most used ones. The one working most stable is "pastebin.com". "Codepad.org" is experimental and "pastebin.ca" returns invalid URLs in its JSON response. I have contacted the author of the service already. They merely serve as samples and I am sure most users will just use "pastebin.com". And if you choose to only install one "Target", like "pastebin.com" then there will be no submenu but you can directly select "Copy to pastebin.com" as shown below:

The targets are configurable in the preferences and are persisted in your Eclipse configuration location. That means you do not have to re-configure the targets for each workspace (a feature I would wish for a lot of Eclipse options to be the default).

You can also install the "CopyTo JDT" feature which allows you to copy Java methods or classes from the Outline view, the source editor or the Package Explorer. For "pastebin.com" this will also enable Java syntax highlighting. Since the whole plugin code is available at github others could contribute specialized modules for Ruby, PHP, etc.

After the selected content was sent to the target and the target returned a valid redirection URL (or JSON response, that contains a URL) there are several actions possible. The default action is the "Copy to clipboard" action which is supplied by default.

You can install additional "PasteTo" actions like for direct pasting into your favorite IRC client.
I have implemented support for Eclipse ECF (IRC) Chats (newest ECF 3.2 required) and some experimental for my favorite IRC client that comes with Miranda-IM for Windows. You can see that in action in the video below:

Of course having many actions will slow down your workflow so there will be a mechanism to select a default action and display the dialog only if you hold down the "CTRL" key. If there is only one action available, then no dialog will be displayed. And for the "Copy to clipboard" action you can disable the initial warning it gives you when the clipboard contains (probably) valuable data.

Unfortunately there is no way to get the "CopyTo" menu at a consistent place in popups and main menu. That's because some popup menus do not provide anchors or group-markers. And sometimes the group marker is below the seperator (Text editor popup). If anyone has an idea how to solve that placement problem he can say or change the source :)

Test it out

I am already using the plugin in my daily Eclipse life and if you want to give it a test run you can add the Update URL http://pke.github.com/CopyTo/update/ to your Eclipse Installation. Don't forget to select at least the main feature and the "pastebin.com target". The update manager will warn you that the features are not signed but you can safely ignore the message (if you trust my code :) You need to restart the workbench to get the pastebin.com configuration visible to "CopyTo". That's currently an known issue.

I would like to hear from you, especially if you have suggestions for the workflow.

Friday, February 5, 2010

P2 error messages are useless - for users and for me as a programmer

I handed out the update site URL of my "copyto" Plug-in to a friend and when he wanted to install it, p2 threw this message at him:
Cannot complete the install because one or more required items could not be found. Software being installed: codepad.org support 0.1.0.201002050243 (eclipseutils.ui.copyto.codepad.feature.feature.group 0.1.0.201002050243) Missing requirement: eclipseutils.ui.copyto 0.1.0.201002050243 requires 'package org.eclipse.core.runtime.preferences 3.3.0' but it could not be found Cannot satisfy dependency: From: codepad.org support 0.1.0.201002050243 (eclipseutils.ui.copyto.codepad.feature.feature.group 0.1.0.201002050243) To: eclipseutils.ui.copyto 0.0.0
I would guess that there is at least one package with the name "org.eclipse.core.runtime.preferences" installed and it would be very helpful if p2 prints out the available versions of that package. That would have made it easier for me to recognize, that 3.3.0 is obviously an Eclipse 3.6 package (I am using the I-Build as my target). Beside that, this error message displayed to a non-programmer is equally useless. It's filled with cryptic numbers and too much information the average user cannot understand. Heck, I do not even understand it and then it's also missing crucial information for me as a programmer. I filed a bug to get at least the required information into the error message.

CopyTo...Pastebin (and others) Plug-In for Eclipse

I am currently working on a small Plug-In that some of you might find useful (especially if you are hanging out in IRC a lot). The plugin allows you to select resources, classes or methods in Java projects and posts them to your favorite pastebin. After that it provides the URL of the pastebin entry in your clipboard so you can easily send it to others. This little video demonstrates this: Some pastebins allow the user to specify additional options when posting. This will be covered when the user helds down the "CTRL" while selecting the menu entry. A dialog is then display where the user can adjust such options. Likewise he could change the content type of the pasted text, if the automatic detection failed. The Plug-In will be released under EPL 1.0 and the source will be up at github. Now, if anyone of you have a nicer name for the Plug-In, I would like to replace the rather generic "CopyTo" (Pasty?). The Plug-In is very easily extensible with new pastebin providers. In fact all current providers are supplied via Fragement-Bundles that basically just add their menuContribution the the CopyTo menu. There is support for the usual redirect based pastebins, as well as ones that send back JSON. Additional response handlers can be easily plugged in (SOAP *yikes*) and additional JSON helpers, that extract the new location URL component from a JSON response are queried using the Eclipse IAdapterManager. Currently there is only support for copying JDT elements (Classes, Methods) but other sources of "Copyable" content can be also plugged in via Adapters. I also plan to provide a "History" view of pastes that allows you to copy the URL again into the clipboard at any time.

Tuesday, December 15, 2009

Toggle Commands that toggle other contributions

Introduction

This is a follow up to Commands Part 6: Toggle & Radio menu contributions of fellow blogger Prakash G.R.. He described how to use command toggle and radio states. Here I will show you how to drive other contributions in the Eclipse Workbench using a toggle command.

What we want to achieve

I needed to show another toolbar button when a certain toggle command was executed. Imagine something like "Show clock" that will show or hide a little clock in the worbench window status bar. Such contribution can be easily added using a menuContribution for the trim area. First create a toolbar in the trim area and then contribute controls/commands to this toolbar also using the menuContribution extension point. Since we want the clock contribution
<menucontribution locationuri="toolbar:mytoolbar">
<control class="test.ui.clocl.internal.ClockControlContribution" id="test.ui.clock">
<visiblewhen checkenabled="false">
<with variable="activeWorkbenchWindow">
  <test args="test.ui.clock.ToggleCommand"
    forcepluginactivation="true"
    property="org.eclipse.core.commands.toggle"
    value="true"/>
</with>
</visiblewhen>
</control>
</menucontribution>
That will create a toolbar contribution that is only visible when the test.ui.clock.ToggleCommand is in the "true" state, when its checked. Lets define the command:
<command defaulthandler="org.eclipse.core.commands.extender.ToggleCommandHandler" id="test.ui.clock.ToggleCommand" name="Show clock">
<state
class="org.eclipse.ui.handlers.RegistryToggleState:true"
id="org.eclipse.ui.commands.toggleState">
</state>
</command>
How this command works and what the state is you have already read in Prakash's blog entry. The default handler for this command does a little more than the one in the latter mentioned blog entry. It is defined like this:
/**
* Generic command that toggles the executed command and re-evaluates property testers for the
* org.eclipse.core.commands.toggle property.
*
*/
public class ToggleCommandHandler extends AbstractHandler {

public Object execute(final ExecutionEvent event) throws ExecutionException {
HandlerUtil.toggleCommandState(event.getCommand());
final IWorkbenchWindow ww = HandlerUtil.getActiveWorkbenchWindowChecked(event);
final IEvaluationService service = (IEvaluationService) ww.getService(IEvaluationService.class);
if (service != null) {
  service.requestEvaluation("org.eclipse.core.commands.toggle");
}
return null;
}
}

How to toggle the visibility of the clock contribution

The connection between toggling the command and making the clock contribution visible is hidden in a property tester, that the clock contribution uses:
public class CommandsPropertyTester extends PropertyTester {
public static final String NAMESPACE = "org.eclipse.core.commands"; //$NON-NLS-1$
public static final String PROPERTY_BASE = NAMESPACE + '.';
public static final String TOGGLE_PROPERTY_NAME = "toggle"; //$NON-NLS-1$
public static final String TOGGLE_PROPERTY = PROPERTY_BASE + TOGGLE_PROPERTY_NAME;

public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {
if (receiver instanceof IServiceLocator && args.length == 1 && args[0] instanceof String) {
  final IServiceLocator locator = (IServiceLocator) receiver;
  if (TOGGLE_PROPERTY_NAME.equals(property)) {
    final String commandId = args[0].toString();
    final ICommandService commandService = (ICommandService)locator.getService(ICommandService.class);
    final Command command = commandService.getCommand(commandId);
    final State state = command.getState(RegistryToggleState.STATE_ID);
    if (state != null) {
      return state.getValue().equals(expectedValue);
    }
  }
}
return false;
}
}
It is defined in plugin.xml like this:
<propertytester
class="org.eclipse.core.commands.extender.internal.CommandsPropertyTester"
id="org.eclipse.core.expressions.testers.CommandsPropertyTester"
namespace="org.eclipse.core.commands"
properties="toggle"
type="org.eclipse.ui.services.IServiceLocator"/>
That means we define a new property for the namespace "org.eclipse.core.command" and the property is named "toggle". It will operate on IServiceLocator variables. Such variable that is an IServiceLocator is the "activeWorkbenchWindow" variable. Now you should understand the visibleWhen expression of the clock contribution. It should be only visible when the toggle for the clock toggle command is "true". The re-evaluation of the property testers is triggered by the generic ToggleCommand.

A little tip at the end

If you put the ToggleCommand and property tester in a seperate bundle for easier re-use in all your projects and other bundles make sure you either start the bundle at the beginning or set the "test" expressions "forcePluginActivation" to true to let the Eclipse expression framework activate the bundle for you. Otherwise the property tester is completly ignored and the clock would be always visible.

Bonus

Since the state of the toggle is preserved in an instance preference value, the visibility of all associated contributions that use the property tester to check for the toggle state of the command is as well. Of course you can also reverse the test expression for your contributions if you have a toggle command that says something like "Hide clock".

Monday, December 7, 2009

Allow contributions to Forms

Introduction

Each Form has a toolbar associated with it, as you probably already know. You can get it by calling form.getToolBarManager(). Once you got the manager you can add your own contribution items or (legacy) actions to it. But what if you could allow other bundles/developers to add contributions to your forms toolbar too? There exists already an extension point that allows adding of contributions to menus and toolbars. You most likely used it already to customize your popup menus or your RCP applications main menu.

How to implement

The menuConstribution extension point works in conjunction with the IMenuService. This service allows you to put matching contributions into any ContributionManager. It respects the current workbench evaluation state so contributions with expressions are carefully evaluated before they are added to the ContributionManager. The menu service also takes care of enabling the contributions and manages their visibility dynamically. Basically all that you already know from addin contributions to the various Eclipse menus and toolbars. To get the contributions you are interested in, you first have to decide on a menu URI schema that identifies contributions for your form. We should follow the Eclipse Schema and define "form:" as our new schema and the following parameter is the ID of the form. The ID can be anything and you as a programmer decide for each form that you create what its ID should be. A common way I use is, if the form is embedded into a ViewPart, to use the ViewPart.getSite().getId() method. So I would call
menuService.populateContributionManager(toolbarManager, "form:"+getSite().getId());

Cleanup

You have to remember to release the contributions when your form is disposed or otherwise the IMenuService will continue to track your contributions and waste time as well as resources. So be a good contribution citizen and call menuService.releaseContributions(toolbarManager) and also toolbarManager.dispose()to allow it to clean up its resources. I recommend using a DisposeListener on the form to perform the cleanup.

Extension: Allow contributions to any form

Much like you can add contributions to the global popup menu using the "popup:org.eclipse.ui.popup.any" we can define our new "form:org.eclipse.ui.form.any" URI that allows contributions to be added to each forms toolbar.
ContributionHelper.contributeTo(toolbarManager, "form:" + getSite().getId(), "form:org.eclipse.ui.form.any");


  
    
    
  


/**
* Adds menu contributions to a {@link ContributionManager} using the
* {@link IMenuService}.
*
* @param contributionManager
* @param locations
*            The format is the Menu API URI format.
*/
public static void contributeTo(final ContributionManager contributionManager, final String... locations) {
final IMenuService menuService = (IMenuService)PlatformUI.getWorkbench().getService(IMenuService.class);

for (final String location : locations) {
 menuService.populateContributionManager(contributionManager, location);
}
contributionManager.update(false);
}

Thursday, July 23, 2009

How to replace the default JFace message icons

We all know the standard JFace icons very well. They appear in Dialogs, Wizards and Forms.

And in a form they look like this:

Now, there is a quick and easy way to replace them with your own icons if you like.

You just have to create a Fragment bundle and set org.eclipse.jface as its Bundle-Host. In your fragment bundle you include the icons you want to replace in the following folder structure:
Don't forget to add the icons folder and all of its subfolder and content into your build.properties file:
bin.includes = META-INF/,\
             .,\
             OSGI-INF/,\
             icons/
Interesting fact: You can replace the JFace icons with PNGs too. You can just rename them to have the .GIF extensions. The image file loader of SWT does not care about the extension but analyses the content of the file.