Archive for the 'Eclipse' Category

Jan 14 2009

Using Eclipse Jobs API

Published by under Eclipse,IT,Java

Eclipse platform offers great API for managing long running operations in the background. Besides the API for starting, stopping and monitoring progress of the Job – there is also standard UI for managing all those operations. I’m going to present sample usage of Jobs API in you own plug-in/application.

Creating and scheduling Job may look like this:

 TrainJob job = new TrainJob(TRAIN_JOB_NAME + file.getName(), classifier);
 job.setRule(file);
 job.setUser(true);
 job.setPriority(Job.SHORT);
 job.schedule(); // start as soon as possible

Sample of custom Job:

package pl.edu.agh.caracal.classifier.popup.jobs;
 
import static org.eclipse.core.runtime.Status.OK_STATUS;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.jobs.Job;
import pl.edu.agh.caracal.classifier.ext.classifiers.AbstractClassifier;
 
/**
 * Class for execution of training of a classifier
 *
 * @since 1.0
 */
public class TrainJob extends Job {
 private AbstractClassifier classifier;
 
/**
  * Public constructor TrainJob
  *
  * @param name Train job name
  * @param classifier Classifier to be trained
  */
 public TrainJob(String name, AbstractClassifier classifier) {
 	super(name);
 	this.classifier = classifier;
 }
 
 @Override
 protected IStatus run(IProgressMonitor monitor) {
 	// Long running operation - in this case classifier training
       // ...
       return OK_STATUS;
 }
 
}

Standard GUI for presenting Job progress:

Jobs API View

3 responses so far

Sep 09 2008

Eclipse RCP tips and tricks

Published by under Eclipse,IT,Java

Recently I had to do couple of tricks Eclipse RCP applications. Basically all of the pieces of code presented below need to be placed in method initialize(IWorkbenchConfigurer configurer). You need to override this method in WorkbenchAdvisor subclass.

  • Displaying icons in Navigator View
    final String ICONS_PATH = "icons/full/";
    final String PATH_OBJECT = ICONS_PATH + "obj16/";
    Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH);
    declareWorkbenchImage(configurer, ideBundle,
    IDE.SharedImages.IMG_OBJ_PROJECT, PATH_OBJECT + "prj_obj.gif", true);
    declareWorkbenchImage(configurer, ideBundle,
    IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT
    + "cprj_obj.gif", true);
  • Enabling Decoration Context
    DecorationContext dc = (DecorationContext) DecorationContext.DEFAULT_CONTEXT;
    dc.putProperty(IDecoration.ENABLE_REPLACE, Boolean.TRUE);
  • Enabling Jobs Progress Bar
    IWorkbench wb = PlatformUI.getWorkbench();
    wb.getProgressService();

Probably you don’t need any of those when running your plug-ins in Eclipse IDE. The tricky part is running it in a stripped to minimum RCP based applications.

One response so far

Aug 12 2008

Eclipse RCP launcher icon

Published by under Eclipse,IT,Java

Eclipse RCP allows easily create an application. Additional advantage of the platform is a native launcher of the application which allows it to behave more like “native” application. It much better to have a process called your_application.exe running instead of another java.exe process.  You will probably also want to have some nice icon attached to *.exe file of your application. This can be done easily in Eclipse 3.4. First you need to create *.ico file (containing all necassary images inside) – one of the generators available on the web can be used for this (for example).

Next step is configuration in *.product file:

   <launcher name="caracal">
      <solaris>
      <win useico="true">
         <ico path="/pl.edu.agh.caracal.application/icons/caracal.ico"></ico>
         <bmp></bmp>
      </win>
   </solaris>
</launcher>

You can also use product file editor for this (a lot of enhancements were added in Eclipse 3.4):

Launcher icon configuration

After building the application based on product file launcher will have your custom icon. No resource hacking, nor recompiling native C code is required!

Launcher custom icon

2 responses so far

Aug 05 2008

Long-running operation in a wizard page

Published by under Eclipse,IT,Java

Some time you may need to do some long running operation in one of the pages in your wizard. Probably the best solution would be to redesign the flow of an application in such way that this operation can be performed outside the wizard as a background task (using Eclipse Jobs API). If you really need to place this inside wizard than in order to not freeze your application completely with such operation you can use IRunnableWithProgress. Sample usage of this interface is presented below.

import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
 
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
 
/**
 * Wizard Page with long running operation
 *
 */
public class DummyWizardPage extends WizardPage {
    private Logger logger = Logger.getLogger(DummyWizardPage.class.getName());
 
    protected DummyWizardPage(String pageName) {
	super(pageName);
    }
 
    /**
     * {@inheritDoc}
     */
    public void createControl(Composite parent) {
	Composite composite = new Composite(parent, SWT.NONE);
 
	Button button = new Button(composite, SWT.PUSH);
	button.addSelectionListener(new SelectionAdapter() {
	    public void widgetSelected(SelectionEvent event) {
		try {
 
		    // Invoking long running operation
		    getContainer().run(true, false,
			    new IRunnableWithProgress() {
				public void run(IProgressMonitor monitor)
					throws InvocationTargetException,
					InterruptedException {
				    // Some time consuming operation
				}
 
			    });
		} catch (InvocationTargetException e) {
		    logger.warning(e.getMessage());
		} catch (InterruptedException e) {
		    logger.warning(e.getMessage());
		}
	    }
	});
 
	// Setting control for Wizard Page
	setControl(composite);
    }
}

3 responses so far

Jul 26 2008

Help in Eclipse RCP application

Published by under Eclipse,IT,Java

Until you are working at Google or Apple your applications probably requires some sort of help system (UX). Eclipse help system can be easily reused in your custom application based on Eclipse RCP.

Let assume that you already have RCP application (if not you can use one of the wizards provided in Eclipse to get one).  In order to enable help there you need to add three dependencies explicitly in plugin.xml:

  • org.eclipse.help.ui
  • org.eclipse.help.ui.webapp
  • org.eclipse.equinox.http.jetty

After adding those make sure to update *.product configuration and add all new required dependencies.

The next step is adding an extension which will provide the help content in plug-ins that will contribute it. The extension point that provides this feature is: org.eclipse.help.toc (there is one template with dummy help content available to choose in Extension Point Selection form).

Now some menu item that will launch help needs to be added. It can be done in plugin.xml:

  • Add an extension (if you don’t have it already) : org.eclipse.ui.menus
  • Add new element: menuContribution with locationURI menu:file
  • Add new command with id: org.eclipse.ui.help.helpContents

Last step is registering an action that will be binded to previously created menu item. It can be done in a class that extends ActionBarAdvisor (if you created your RCP application using default wizard it will be called ApplicationActionBarAdvisor. You need to override one method:

protected void makeActions(IWorkbenchWindow window) {
	this.contentsHelpAction = ActionFactory.HELP_CONTENTS.create(window);
	register(this.contentsHelpAction);
}

Now help system with sample content should be available in Help menu. It will launch separate window and display content there. A help content can be provided by any plug-in extending org.eclipse.help.toc extension point. It is set of HTML documents which are displayed together in one common place, framework provides built-in search, index, table of contents etc (Eclipse uses Jetty as a web server, try this in a browser).

2 responses so far

Jul 22 2008

JFace Binding

Published by under Eclipse,IT,Java

Recently I have started using JFace Binding. Unfortunately there are not many resources available on the web with non-trivial examples.

Let present example of master-detail view: a drop-down list and two text fields which display some details regarding option chosen from the list.

POJO Category. It contains two fields: name and description which will be displayed as details of the object chosen from the drop-down list:

import java.beans.PropertyChangeListener;
import java.io.Serializable;
 
/**
* Domain object representing category
*
*/
public class Category implements Serializable {
 
private static final long serialVersionUID = -5542167952605551865L;
 
private String name;
private String description;
 
/**
* Default constructor
*/
public Category() {
// Do nothing
}
 
/**
* Constructor
*
* @param name
*            name of a category
* @param description
*            description of a category
*/
public Category(String name, String description) {
this.name = name;
this.description = description;
}
 
/**
* @return the name
*/
public String getName() {
return name;
}
 
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
 
/**
* @return the description
*/
public String getDescription() {
return description;
}
 
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
}

Class of model that will be used to bind the data to the view:

import java.util.List;
 
/**
* Model for displaying categories
*
*/
public class CategoriesModel extends AbstractModelObject {
private List<Category> categories;
private IDataManager dataManager;
private Category category;
 
/**
* The constructor
*/
public CategoriesModel() {
this.dataManager = Activator.getDataManager();
this.categories = this.dataManager.getAllCategories();
}
 
/**
* @return the category
*/
public Category getCategory() {
return this.category;
}
 
/**
* @param category
*            the category to set
*/
public void setCategory(Category category) {
this.category = category;
}
 
/**
* @return the categories
*/
public List<Category> getCategories() {
return categories;
}
 
/**
* @param categories the categories to set
*/
public void setCategories(List<Category> categories) {
this.categories = categories;
}
}

Class of view (in this case it is Eclipse View containing managed form):

import java.util.logging.Logger;
 
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.ManagedForm;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.part.ViewPart;
 
/**
* Allows to view list of categories and their details
*
*/
public class CategoryView extends ViewPart {
 
private Logger logger = Logger.getLogger(CategoryView.class.getName());
 
private static final String FORM_TITLE = Messages
.getString("category.view.form.title");
 
private FormToolkit formToolkit;
 
private CategoriesModel model;
private Text nameText;
private Text descriptionText;
private ComboViewer categoriesComboViewer;
private DataBindingContext dbc;
 
/**
* {@inheritDoc}
*/
@Override
public void createPartControl(Composite parent) {
model = new CategoriesModel();
 
ManagedForm mForm = new ManagedForm(parent);
ScrolledForm scrolledForm = mForm.getForm();
FormToolkit formToolkit = mForm.getToolkit();
Composite formBody = scrolledForm.getBody();
formToolkit.decorateFormHeading(scrolledForm.getForm());
scrolledForm.setText(FORM_TITLE);
formBody.setLayout(new GridLayout(2, true));
 
categoriesComboViewer = new ComboViewer(formBody, SWT.DROP_DOWN
| SWT.READ_ONLY);
GridData comboGridData = new GridData();
comboGridData.horizontalSpan = 2;
comboGridData.horizontalAlignment = GridData.FILL;
categoriesComboViewer.getCombo().setLayoutData(comboGridData);
 
nameText = formToolkit.createText(formBody, "", SWT.NONE);
GridData nameGridData = new GridData();
nameGridData.horizontalSpan = 2;
nameGridData.horizontalAlignment = GridData.FILL;
nameText.setLayoutData(nameGridData);
 
descriptionText = formToolkit.createText(formBody, "", SWT.MULTI);
GridData textGridData = new GridData();
textGridData.horizontalSpan = 2;
textGridData.horizontalAlignment = GridData.FILL;
textGridData.heightHint = 100;
descriptionText.setLayoutData(textGridData);
 
formToolkit.paintBordersFor(formBody);
bindData();
}
 
/**
* {@inheritDoc}
*/
@Override
public void setFocus() {
// Do nothing
}
 
/**
* This method binds the value from UI layer to the model object
*/
protected void bindData() {
dbc = new DataBindingContext();
 
// Seting content provider for combo viewer
ObservableListContentProvider categoryViewerContentProvider = new ObservableListContentProvider();
categoriesComboViewer.setContentProvider(categoryViewerContentProvider);
IObservableMap[] attributeMaps = BeansObservables.observeMaps(
categoryViewerContentProvider.getKnownElements(),
Category.class, new String[] { "name" });
categoriesComboViewer.setLabelProvider(new ObservableMapLabelProvider(
attributeMaps));
categoriesComboViewer.setInput(new WritableList(model.getCategories(),
Category.class));
 
// Observing changes in selection in combo viewer
IObservableValue selection = ViewersObservables
.observeSingleSelection(categoriesComboViewer);
 
// Observing the properties of the current selection
IObservableValue detailNameObservable = BeansObservables
.observeDetailValue(Realm.getDefault(), selection, "name",
String.class);
 
IObservableValue detailDescriptionObservable = BeansObservables
.observeDetailValue(Realm.getDefault(), selection,
"description", String.class);
 
// Binding the Text widgets to the name and description details
// (selection's properties).
dbc.bindValue(SWTObservables.observeText(nameText, SWT.None),
detailNameObservable, new UpdateValueStrategy(false,
UpdateValueStrategy.POLICY_NEVER), null);
 
dbc.bindValue(SWTObservables.observeText(descriptionText, SWT.None),
detailDescriptionObservable, new UpdateValueStrategy(false,
UpdateValueStrategy.POLICY_NEVER), null);
}
 
/**
* {@inheritDoc}
*/
public void dispose() {
if (formToolkit != null) {
formToolkit.dispose();
}
super.dispose();
}
}

AbstractModelObject which provides methods required by JFace Binding (it’s not checked on compilation level):

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
 
/**
* Provides minimal JavaBeans support for model objects
*
*/
public abstract class AbstractModelObject {
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(
this);
 
/**
* @param listener
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
 
/**
* @param propertyName
* @param listener
*/
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
 
/**
* @param listener
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
 
/**
* @param propertyName
* @param listener
*/
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(propertyName,
listener);
}
 
/**
*
* @param propertyName
* @param oldValue
* @param newValue
*/
protected void firePropertyChange(String propertyName, Object oldValue,
Object newValue) {
propertyChangeSupport.firePropertyChange(propertyName, oldValue,
newValue);
}
}

4 responses so far

Jun 28 2008

Eclipse Ganymede

Published by under Eclipse,IT,Java

Finally Eclipse 3.4 Ganymede has been officially released! While I’m currently working on Eclipse based product I was monitoring the progress of the platform beginning with Milestone 3. It looks like release 3.4 is moving Eclipse into the right direction. Provisioning mechanism was included into standard distribution, it is called p2. We probably have to wait some time to get more mature version of it – but it’s great that it is in a “main stream” now.

I really enjoy some enhancements that make working with Eclipse IDE more efficient:

  • Automatic updates done in background;
  • Option for determining network proxy settings from system instead of configuring them in preferences;
  • Mylyn extension for search plugin;

Small but annoying issue: Delta Pack is not included into standard distribution for RCP/Plugin development (bugzilla)! Fortunately there is now at least a message in editor for *.product configuration explaining that Delta Pack has to be installed separately (in Eclipse 3.3 you could spent several hours investigating the issue of missing Delta Pack).

No responses yet

Jun 28 2008

Eclipse (anti)patterns (1).

Published by under Eclipse,IT,Java

Activator is a class in a Eclipse plugin which controls the plug-in life cycle. It contains methods like start(BundleContext context), stop(BundleContext context) and a static method Activator getDefault() – which returns static field plugin. What is interesting the the static field plugin is set in the non-static public method start(BundleContext context) or in a public constructor.
Such code is generated by Eclipse wizard for creating new plug-in. And this is Eclipse pattern for accessing the shared instance

Actually there are more places where this pattern is used in Eclipse framework and very often it is the only way for obtaining a reference to particular object. Let me discuss those later.

No responses yet

May 22 2008

Eclipse DemoCamp is coming to town

Published by under Eclipse,IT,Java

Eclipe 3.4 Ganymede It looks like Eclipse DemoCamp will come to Krakow sometime in June. The agenda is not available now, but I hope it will be interesting. There is a lot of exciting stuff coming with Eclipse 3.4 (I’m currently working with Eclipse 3.4 M7 platform and looking forward for final release that is coming in end of June).

Agenda, specific date and place should be announced here

No responses yet

Mar 15 2008

Eclipse – a workspace and its resources. Problem with case-insensitive file systems.

Published by under Eclipse,IT,Java

All the resources in Eclipse workspace are case-sensitive. Name of the file inside a project in Eclipse workspace is case-sensitive. On Eclipse API level two resources called somefile.TXT and somefile.txt are different resources. The problem starts while such resources are stored in the file system. Method org.eclipse.core.resources.IResource.exists() will return false for somefile.TXT if there is already somefile.txt in the workbench. This cause problem if you are for example implementing wizard for creating new file resource – basing on the Eclipse API you cannot check if such file already exists. My workaround for this was using java.io classes directly for this. Another problem is if in you wizard you want to overwrite existing file with new one e.g. somefile.TXT with somefile.txt. If you try to use org.eclipse.ui.ide.IDE.openEditor(IWorkbenchPage page, IFile input, String editorId, boolean activate) for this overwritten file – it will fail opening it. In Eclipse 3.3 there was introduced method openEditor(IWorkbenchPage page, URI uri, String editorId, boolean activate) – which doesn’t have problem with case-sensitivity. Unfortunately it opens the file in read-only mode while the new resource is out of the workbench! I haven’t found any nice programmatic way to “refresh” workbench in order to reflect the changes that were made on file system behind the scene (as user can do manually by pressing F5). May workaround for this is opening the editor twice – first time using openEditor(IWorkbenchPage page, IFile input, String editorId, boolean activate) and closing it immediately in order to “refresh” workbench and after that using openEditor(IWorkbenchPage page, URI uri, String editorId, boolean activate) – now the new file is already in the workbench and the it’s not opened in read-only mode.

This is one of the problems I encountered while developing Eclipse plugins on Windows platform. I’m missing possibility for configuring all the resources related code for dealing with OS-dependent stuff like mentioned above problem with case-sensitivity.

Eclipse 3.3 API reference can be found here.

No responses yet

« Prev