Friday, May 18, 2007

"Revert to Base" - a few things about

In response to bug 106876 new feature has been introduced to eclipse: in the 7th milestone of 3.3 version an action "Revert to Base" appeared in the context menu Team, as shown below:


For every future commiter it is pretty important action. Why?

Let me remind you common cycle of non-commiter contributor work:
1. Pick up a bug
2. Create a patch
3a. Wait for feedback
3b. Go to 1.

Please notice, that point 3b requires switching to head and abandoning previously made changes - because we are writing new patch for another issue (but due to specialization, it may be the same work area).

And now we have quite simple solution - one click and we can restore last loaded version of our software. Always the newest soft will be loaded. Yes, this is almost the same like Team->Replace With->Another Branch or Version -> BASE, but how much less clicking ;).

A few words about sticky tags for those of you, that do not know them: Sticky tags are some ancient invention, I do not see any usage for them. But they can block CVS operations until you removed them, f.e. you cannot commit a resource marked as sticky until you remove that tag or create another branch. And the worst feature of sticky tags - they are set by server in response to certain operations - like f.e. replace with BASE.

And good news for you: in Eclipse 3.3m7 sticky tags are ignored. Whenever the server tries to set them, we gently write current tag to sync bytes. And no sticky nightmare will meet us :).


Sadly, the Revert to Base action has some limitations due to CVS limitations. Deleted files are not restored when replacing with BASE tag. Therefore it is necessary to have local history enabled, at least for one entry. Then the Revert to Base operation is able to restore deleted file and perform update/replacement on it.

I hope this action will help you all in process of eclipse bugfixing. And not only this.

Regards,
Chris

Thursday, April 19, 2007

Testing Eclipse plug-ins

When you write Eclipse plug-ins sooner or later you will start thinking about testing your work. The very first steps will lead you to the Internet. But to my (and maybe your ;) ) surprise this information is not very easy to find. I know two ways to accomplish this task and I want to describe the first one – testing Eclipse plug-ins using build-in JUnit support.

Lets imagine that we have plug-ins that provides a projects view (very useful example ;) ).
When you start with empty workspace it should show nothing, in other case it should show projects names from your workspace.

The first think which springs to your mind is to build simple JUnit test and run it.

This is an option when you are trying to test functionality which is not dependent on Eclipse API.

So to test this functionality following steps are needed:
  • build test plug-in
  • implement tests
  • create launch configuration
  • run tests

Whole procedure is not very big deal. The first thing you'll need is new plug-in. I assume that you can do it (you've just implement plug-in you want to test).

Now you need to add JUnit plug-in to your dependencies (In my case it will be JUnit 4)

We also need dependency to our tested plug-in.

There are also two others plug-ins needed so our dependencies list can be seen in the picture .


Another thing to do is to create Junit test case. While we use JUnit 4 it can be simple class (there is no need to extend TestCase class).

All we need at this level is to build empty test method to check if we are able to run our test. The code looks this way:


package org.test.views;

import static org.junit.Assert.*;

import org.junit.Test;

public class SimpleTest {

@Test
public void simpleTestMethod() {
fail("implement this method");
}

}



Now is the moment to create run configuration. From Run menu we choose in case of Eclipse >= 3.3M5 Open run dialog... (in older versions Run...). Next we create new configuration in "JUnit Plugin test".


The difference from normal plug-in is that we have another tab called Test. On this tab we are able to specify version of JUnit and how we are going to use our test (as a single test or as a group of test from specific location).

Other tabs are also available in normal plug-in configuration so I believe you will manage to config it by yourself ;).

Now you should be able to run your test. Enjoy ;)

If you are looking for inspiration you should look into Eclipse CVS. There is thousands of test in each Eclipse project from witch you can learn.

Source code for this short tutorial can be found here.

Thursday, April 5, 2007

Mylar update site

New Eclipse milestone were released M6 and we got it the same day ;) I personally am very keen of Mylar. But to my surprise it stopped working. So to make it short: version from update site doesn't work with Eclipse 3.3M6. To get working one please use http://download.eclipse.org/technology/mylar/update-site/e3.3 as your update site.

Wednesday, April 4, 2007

How to add Zoom facility to the GEF editor?


Often on the GEF newsgroup there can be found questions concerning zooming in the GEF editor. I tried to investigate this subject and found out that adding basic zooming operations isn't to complicated. All required code I found in the Logic GEF example project: org.eclipse.gef.examples.logic project, which can be checkout from the CVS (if you don't know how to access Eclipse CVS check this page: WIKI CVS HowTo).
To demonstrate the solution I will use another GEF example, but this time it will be Shape Editor project: org.eclipse.gef.examples.shapes, which also can be checkout form the CVS. Shape Editor is very simple GEF editor, which allows you only to add two figures and connect them with two connection types. We will want to add the zooming facility to this poor functionality.

Zoom actions can be added in two ways:

  • by the toolbar
  • by the menu
To add zooming action to the toolbar we need to:
  • In the class
    org.eclipse.gef.examples.shapes.ShapesEditorActionBarContributor you need to overwrite method
    EditorActionBarContributor#contributeToToolBar
    and add this code:

    String[] zoomStrings = new String[] {
    ZoomManager.FIT_ALL,
    ZoomManager.FIT_HEIGHT,
    ZoomManager.FIT_WIDTH

    };

    toolBarManager.add(newZoomComboContributionItem(getPage(), zoomStrings));


  • in the class org.eclipse.gef.examples.shapes.ShapesEditor
    in the method configureGraphicalViewer
    you need to add such code:
    List zoomLevels = new ArrayList(3);
    zoomLevels.add(ZoomManager.FIT_ALL);
    zoomLevels.add(ZoomManager.FIT_WIDTH);

    zoomLevels.add(ZoomManager.FIT_HEIGHT);

    root.getZoomManager().setZoomLevelContributions(zoomLevels);
Where root is an instance of ScalableFreeformRootEditPart which you should pass as a parameter to: viewer.setRootEditPart(root); These string values - ZoomManager.FIT_ALL, ZoomManager.FIT_WIDTH and ZoomManager.FIT_HEIGHT are the additional zoom levels added to the zoom combobox.
  • in the class org.eclipse.gef.examples.shapes.ShapesEditor
    in the method getAdapter
    you need to add such code:
    if (type == ZoomManager.class) {
    return getGraphicalViewer().getProperty(ZoomManager.class.toString());
    }
And that's all! You should see similar effect to this one in the picture below:


Now let's see what are we suppose to do to add the zooming to the main Eclipse menu

  • in the class org.eclipse.gef.examples.shapes.ShapesEditor in the method configureGraphicalViewer you need to add such code:

  • IAction zoomIn = new ZoomInAction(root.getZoomManager());
    IAction zoomOut = new
    ZoomOutAction(root.getZoomManager())
    getActionRegistry().registerAction(zoomIn);
    getActionRegistry().registerAction(zoomOut);

    and additionaly if you want to have the keyboard shortcuts you have to add:
    getSite().getKeyBindingService().registerAction(zoomIn);
    getSite().getKeyBindingService().registerAction(zoomOut);
  • in the class org.eclipse.gef.examples.shapes.ShapesEditorActionBarContributoryou need to overwrite method
    EditorActionBarContributor#contributeToMenu(IMenuManager)and add there:
    super.contributeToMenu(menubar);
    MenuManager viewMenu = newMenuManager("ZOOM");
    viewMenu.add(getAction(GEFActionConstants.ZOOM_IN));
    viewMenu.add(getAction(GEFActionConstants.ZOOM_OUT));
    menubar.insertAfter(IWorkbenchActionConstants.M_EDIT,viewMenu); //where the menu should placed on the menu bar

The effect you can see below:

Friday, March 30, 2007

Where to start?

A developer that starts his adventure with eclipse contributions, always hit one obstacle - Eclipse is big. Huge. Enormous.

A dozens of plugins in newly downloaded distribution. Thousands of classes, and uncountable amount of code lines.

So, how to get from user interface the underlying code?

I will show you the easy way:

1. Check out all plugins from repository that are connected with your area of interests.


2. Lets say we are trying to modify 'Apply Patch...' action. So press Ctrl-H and perform search.


3. There is no much results:



4. When you check them, you will see another terms to search:


5. Search for them again:


6. Voila - we have the action (and the code):



Best Regards,
Chris

Wednesday, March 21, 2007

How to report operation progress?

Recently I had to learn a little bit about how to report the progress of an operation. I mean this component which is shown below and which you possibly very often see while using Eclipse:



Never before I had to take care about this, so I knew only that, there were some progress monitors, which I had to pass to some methods. I started digging into the web and found two very good articles: How to Correctly and Uniformly Use Progress Monitors and FAQ How do I use progress monitors? . Both documents contain very useful information and give nice examples. However, these two papers describe the approach in which class SubProgressMonitor is used. This solution is good, but why use good solution, when better one can be used? Since Eclipse 3.3 class SubMonitor is available (in the project org.eclipse.equinox.common in package org.eclipse.core.runtime) and this is a very good news. Why?
Basically because:
  • we don't have to call methods beginTask() and done() on the instance of SubMonitor class
  • it is easier now to create submonitors (there is a method newChild(int totalWork))
  • in SubMonitor we can find method setWorkRemining() which allows us to redistribute the remaining space on the progress monitor
  • SubMonitor protects the caller from common progress reporting bugs in a called method
I was trying to find some information in the Web concerning SubMonitor, but I failed. Fortunately I found useful info in the javadoc, so I decided to make it more public to make this solution more popular.
First of all we have to convert any other kind of progress monitor into SubMonitor. This is very easy, because we can use one of two static methods:
public
static SubMonitor convert(IProgressMonitor monitor, int work)

and
public
static SubMonitor convert(IProgressMonitor monitor, String taskName, int work)

So after invoking:
SubMonitor progress = SubMonitor.convert(monitor, 100);

we can benefit from all the advances of SubMonitor class.
The basic example of using SubMonitor could look like this:

void someOperation(IProgressMonitor monitor) {

// Convertion of the given monitor
SubMonitor progressSubMonitor = SubMonitor.convert(monitor, 100);

// 70% of work is consumed
doSomeWork(progressSubMonitor.newChild(70));

// 30% of work is consumed
progressSubMonitor.worked(30);

}

My main concern about reporting the progress was how to manipulate the number of work items, when some operation will or will not be executed (so when we have a condition). Fortunately with SubMonitor it is pretty easy. The example below shows how to do this:

void
someOperation(IProgressMonitor monitor) {

SubMonitor progressSubMonitor = SubMonitor.convert(monitor, 100);

if (condition) {
// 50% of work is consumed

doSomeWork(progressSubMonitor.newChild(40));
}

//if there is any work item resumed from the first 40% then use it

progress.setWorkRemaining(40);

// the rest of work items is consumed

doSomeWork(progress.newChild(60));

}


It is also easy to handle the loop case:

void someOperation(IProgressMonitor monitor, Collection someCollection) {

SubMonitor progressSubMonitor = SubMonitor.convert(monitor, 100);

// Create a new progress monitor that uses 70% of the total progress
SubMonitor loopProgress = progressSubMonitor.newChild(70);

// Allocate one tick for each element of the given collection.
loopProgress.setWorkRemaining(someCollection.size());

for (Iterator iter = someCollection.iterator(); iter.hasNext();) {
Object next = iter.next();
//Do something with the element from collection and
//consume one work item
doSomeWorkOnElement(next, loopProgress.newChild(1));
}

// Use the remaining 30% of the progress monitor to do some work outside
// the loop
doSomeWork(progressSubMonitor .newChild(30));

}

Have fun with using SubMonitor ;-)

Wednesday, February 14, 2007

Eclipse Europa

Maybe it's not the longest post but one of the most cheerful ;)
Eclipse Europa update site is working :)