UFace – Update

I recognized today that I haven’t blogged about one of my favorite OSS-project (UFace/UFacekit) lately.

For those of you who have never heard of this project let me introduce it in a few sentences.

UFace or UFacekit has the following targets:

  • Add a highlevel API above Eclipse-Databinding
  • Helping Eclipse-Databinding to gain momentum outside Eclipse/SWT/JFace world by providing Observable-Implementation for various UI-Toolkits like Swing, GWT, …
  • Helping OSGi to be used in UI-Applications outside Eclipse-RCP e.g. in Swing Applications
  • Providing a uniform UI-API for all those widget-systems including builders for common form layouts (e.g. 2 column label/field list)

We have been fairly busy lately and added the following things into UFace:

  • Validation and Decoration Support (contributed by Kenneth Westelinck) for Swing and SWT
  • Worked heavily on the MyGWT integration
  • Maven-Build-System

Validation and Decoration

Adding decorations to a UIForms (our abstraction above the databindingContext providing a uniform API for different Databinding-Implementations JavaBean/EMF/UBean/…) is not more than adding these 2 lines to your sources:

StatusDecoratingInterceptor interceptor = new StatusDecoratingInterceptor(detailComposite);
detailForm_1.setAfterBindInterceptor(interceptor);

Darn cool, isn’t it?

The resulting UI with validation error looks like this:

SWT on Win32:

Swing on Win32:

UFacekit implementation for MyGWT

Beside providing a higherlevel API above Eclipse-Databinding the other idea of UFace is to provide a uniform API to deploy your applications in different ways (Desktop, Web, Mobile-Devices, …). In Web-Space we decided to go the GWT way which means your application is running completely in the browser and only business data is fetched from the server.

This concept is different from the one of RAP who, as far as I have understood the framework, does most of the work on the server-side and uses the browser “only” for rendering purposes (RAP devs please correct if I’m wrong here).

The hardest thing to bring to browsers are SWT-Layouts and that’s where I’m currently progressing slowly but steadily at the moment. This is how the the same form looks like in the browser rendered with MyGWT:

It’s not 100% right and Combo and List aren’t working either but it was quite an achievement to get that far.

Current status / Release plans

My first draft plan was to have an M1-Milestone for JFace, Swing and MyGWT implementation ready for EclipseCon but I had to delay this because my current work load hasn’t give me enough time to work on UFacekit too many hours. Today JFace and Swing are complete (as complete a first Milestone can be) and only MyGWT is missing so I hope we could have a first Milestone by April.

What’s in the queue

We already have a queue for features we’d like to integrate (an incomplete list is this):

  • Support for more Widgets Tree/TreeTable, TabFolders, …
  • Implementation ontop of Eclipse-Forms
  • Better looking decorations on Swing
  • Support for CSS to style your widgets
  • Extensible converts
Posted in UFaceKit | 2 Comments

EMF + Databinding – I’m adicted to this stuff

Ed blogged somedays ago about the progress he made makeing EMF available to RAP and J2ME and there are more and more people requesting a simple example project where some EMF-Databinding-Features are shown.

I’ve already send some code to the EMF-newsgroup and today I’ve added some more bits showing how to bind a Detail-List.

I’m going to add some more interesting stuff (e.g. field-dependencies, validation, …) when I have time and will restart working on my article on EMF+Databinding+RCP+iBatis.

If you want to take a look at source code you can grab it from here.

There are some issues you need to be aware of when it comes to
e.g. Master-Detail + Field-Dependencies.

This is where UFace comes into play which handles this kind of thing for you (and even more).

Because I’m talking about UFace. We are making progress since the last blog entry the following things have happend:

  • refactored Factory-API to get extensible and not cluttered with overloaded methods
  • started to think how UForm can be used by native implementators (UForm is an abstraction level above Databinding and your Model-Implementation-Technology)
  • we added a new committer just today (Angelo Zerr) who develops some cool XML-UI things (See Akrogen) and is enhancing our Swing-Binding and SWT-Bindings. Welcome Angelo.
  • Set up a Committer and Contributor policy. I hate this legal stuff and we want to keep it at minimum but this has to be the foundation of every project
  • Received a code donation (SWT GridLayout for Swing) from Daniel Spiewak (See Daniels Code contribution)
Posted in EMF | 8 Comments

One month of UFacekit-Development

A month ago James Strachan and I started hacking on a project we named UFacekit.

We both faced the need to write datacentric applications for different deployment environments (Desktop (Swing/SWT), GWT (MyGWT/GWT-Ext), …) and we thought there must be an easy and fast way to come up with something that makes our day job easier. At this very moment UFacekit was born.

There are different things we are targeting with the project.

  1. Provide a uniform Facade above widget implementations (SWT,Swing,GWT,…)
  2. Promote the use of Eclipse-Databinding (and other related technologies e.g. EMF) outside Eclipse-World (Swing,GWT, …) and provide a highlevel API above the low-level databinding API
  3. Provide reuseable Bundles which can be used independently
    • you are only interested in Swing-Databinding but still want to use the native Swing-API? – UFacekit provides an indepented Swing-Observable bundle for you
    • you want to use an alternative Bean-like implementation not relying on reflection and EMF is too heavy for you? – UFacekit provides an independent implementation for you named UBean

Instead of writing an SWT-Port for GWT/Swing (I know for Swing there’s already an SWT port) we decided to go the Facade/Factory way and started hacking and the progress we made in this very short period of time (we are only working on it in the evening) is more than amazing.

Take a look at the following Screenshots they show what’s already possible with the current sources.

They look fairly identical (the only reason they not look completely the same is that I haven’t ported the GridLayout from SWT to Swing but relying on Mig-Layout).

They are full of features you need many lines code without a framework doing the nifity bits for you (e.g. MasterDetail + Field-Dependencies):

  • Master-Detail support
  • Model-UI-Binding
  • Field-Dependencies (Country/Federalstate)

Setting up this UI needs:

  • ~ 80 Lines of Widget-Toolkit-Independent code
  • ~ 20 Lines of Widget-Dependent code (= the start of the application which is currently not abstracted)

The amazing thing is that both UIs are made up by the same source code:

public void createFormUI(UIComposite root) {
  UIFactory ui = root.getFactory();

  UBeanForm listForm = new UBeanForm();
  final UBeanForm detailForm_1 = new UBeanForm();

  UIComposite containerComposite = ui.newComposite(root, null, ui.newGridLayout(2));

  TableColumn[] columns = { new TableColumn("People", new NameLabelProvider()) };

  UITable table = ui.newTable(
    listForm, 
    containerComposite, 
    new GridLayoutData(200, GridLayoutData.DEFAULT, GridLayoutData.ALIGN_BEGINNING, GridLayoutData.ALIGN_FILL, false, true),  
    listForm.detailList(AddressBook.PEOPLE, Collection.class), 
    columns);

  // ---------------------
  UIComposite detailComposite = ui.newComposite(
    containerComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, true), 
    ui.newGridLayout(2));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "ID");
  ui.newTextField(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.ID, int.class));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "Name");
  ui.newTextField(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.NAME, String.class));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "Location");
  ui.newTextArea(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.LOCATION, String.class));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "Country");
  UICombo combo = ui.newCombo(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.COUNTRY, Country.class), 
    ModelHelper.createWritableList(getModel().getCountries(), Country.class), 
    new CountryLabelProvider());

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_BEGINNING), "Federalstate");
  ui.newDependentListBox(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.DEFAULT,120,GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.FEDERAL_STATE, FederalState.class), 
    (IObservableList) detailForm_1.detailList(Country.FEDERAL_STATES, Collection.class).createObservable(combo.getSelectionObservable()),
    new FederalStateLabelProvider());

  WritableValue value = ModelHelper.createWritableValue(getModel());
  listForm.bind(value);

  IObservableValue detailObservable = table.getSelectionObservable();
  detailForm_1.bind(detailObservable);

  UBeanForm detailForm_2 = new UBeanForm();
  columns = new TableColumn[] {
    new TableColumn("ID", new IDLabelProvider()),
    new TableColumn("Name", new NameLabelProvider()),
    new TableColumn("Location", new LocationLabelProvider())
  };

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "");
  ui.newTable(
    detailForm_2, 
    detailComposite, new GridLayoutData(GridLayoutData.ALIGN_FILL,GridLayoutData.ALIGN_FILL,true,true), 
    detailForm_2.detailList(Person.FRIENDS, Collection.class), columns);
  detailForm_2.bind(detailObservable);
}

public void run(final String uiMethod) {
  Display display = new Display();
  Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
    public void run() {
      Shell shell = createUI(uiMethod);
      shell.setSize(650, 500);
      shell.setText("UFacekit - JFace-Demo ");

      Display display = Display.getCurrent();
      while (!shell.isDisposed()) {
        if (!display.readAndDispatch()) {
          display.sleep();
        }
      }
    }
  });
}

private Shell createUI(String uiMethod) {
  final Shell shell = new Shell();
  SWTComposite composite = new SWTComposite(shell,new JFaceFactory().newFillLayout());
  // generic code as shown above

You can even more reduce the size and complexity of the source by using FormBuilder-classes we are going to provide to make creating standard-forms like this as simple as possible.

Before we are publishing a first cut we need to finish the GWT-implementation (GWT/MyGWT/GWT-Ext) but we (in this case James) are on a good way and we should have a release fairly soon. Naturally there are some gaps (e.g. missing widgets, API inconsistencies) but hey the project just got 1 month so I hope you don’t mind.

Did this spot your interest? Come and join our google group and share your ideas with us.

Posted in UFaceKit | 1 Comment

EclipseCon: I’ll be there

News 1:

Just booked my flight and my room at the Hyatt. I’m excited to meet you all.

There are so many interesting talks like Steve’s talk about the future of SWT which I’m very interested in because recently the Web-2.0 movement hit me hard and I’ve started to make Eclipse-Core-Technologies available in Web-Env.

News 2:

The other news I’d like to share with we you is that together with James Strachan I started a fairly interesting “experiment” called UFaceKit.

In short the project aims to provide a facade above widget implementations to use a uniform API above various Java-Widget implementations to create Datacentric-Applications.

Beside providing this generic API the project is split into many individual plugins/bundles which can be used out of the uface-scope:

  • A light weight JavaBean like implementation useable without any reflection-API the implementation is called UBean
  • Observables for UBean like Eclipse provides an implementation for JavaBeans
  • UI-Observables for GWT/MyGWT/GWT-EXT
  • UI-Observables for Swing

As you see one of the “waste products” of this project is that Eclipse-Databinding is can be used by Swing/GWT/… developers.

If you are interested in the project take a look at our project page and join the google-group. We are in pre-alpha stage and code changes a lot but we appreciate your help e.g. to provide an implementation for other Java-UI toolkits (QT-Jambi, Android, …), help us with the Swing, GWT implementations of course all code is released under EPL.

Primary targets currently are:

  • SWT/JFace
  • GWT-implementations
Posted in Eclipse, Talks & Conferences | Leave a comment

ed4g – Eclipse Databinding for GWT-Widgets 0.0.1

I finally did it. Based upon the plugins I’ve ported over from Eclipse to compile under GWT I setup a project that provides Observable implementations for GWT and MyGWT widgets but it is open for any other GWT-compatible widget-lib.

A missing thing currently is a 2nd light weight Model-Implementation that works on GWT, I thought about simply providing an Observable implemented ontop of a HashMap. EMF is available and working but I’d like to have a second very light weight implementation which can be used by people not familiar with EMF and only need some GWT related binding.

You can find the project here.

Posted in Databinding, GWT | 3 Comments

EMF + Databinding + GWT 1.5 – it works

Since the last time I blogged about the on going work to provide Eclipse-Core-Features for users of GWT some time has elapsed so I thought I should give you an update.

Ed and Boris jumped on the train and try to help me with their indepth knowledge of EMF and Databinding. It’s great to have them on board.

Today I managed the first time to use EMF-Core-Modules (EMF-Common und EMF-Ecore) in a GWT-context. There are some rough edges and not everything is working but it’s amazing that the newly developed EMF-Databinding-Integration developed in Bug 75625 works nearly out-of-the box.

My GWT-Code looks like this now:

EMFDataBindingContext ctx = new EMFDataBindingContext();
targetObservableValue = GWTObservables.observeText(textBox, GWTObservables.Change);
modelObservableValue = EMFObservables.observeDetailValue(Realm.getDefault(), value, BrojectPackage.Literals.PROJECT__NAME);

IConstants.BINDING_BUILDER.bindTextValue(ctx, targetObservableValue, modelObservableValue);

I’ve started an example project you can look at Broject and get the sources from my svn-repository, it’s in a very very early stage but you should get the idea.

If you are interested in the work then you should subscribe to the following bugs EMF-Common, EMF-Ecore, Extension to GWT-JRE-Emulation, Core-Databinding.

Posted in EMF, GWT | 9 Comments

More details about Databinding and GWT

I promised in the morning that I’ll blog more details about giving GWT-Developers access to concepts provided by Eclipse.

Currently my port provides:
– Core-Databinding + PEMF-Observables (for standard values (no lists at the moment))
– Support for Perspectives (untested but available in code)
– ViewPart-Implementation
– Access to the low-level-bits of the Command-framework (AbstractHandler and friends)
– A first draft implementation of ExtensionPointRegistry

This is currently not a straight port and the API is in some situations different but I’ll resolve this later on.

Maybe some code example help you to understand the idea behind my work.

Starting up the application:

public class DemoApplication extends Plugin {
  /**
    * This is the entry point method.
    */
  public void start() {
    super.start();
    Workbench.createAndRunWorkbench(new WorkbenchAdvisor());
  }

  public String getPluginXML() {
    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
      "<?eclipse version=\"3.2\"?>\n"+
      "<plugin>\n"+
      "    <extension\n"+
      "          point=\"org.eclipse.ui.views\">\n"+
      "       <view\n"+
      "             name=\"Range of Product\"\n"+
      "             allowMultiple=\"false\"\n"+
      "             class=\"at.bestsolution.gwt.demo.client.ui.views.ProductRangeViewPart\"\n"+
      "             id=\""+IConstants.PRODUCT_RANGE_VIEW_PART+"\">\n"+
      "       </view>\n"+
      "       <view\n"+
      "             name=\"Product\"\n"+
      "             allowMultiple=\"true\"\n"+
      "             class=\"at.bestsolution.gwt.demo.client.ui.views.ProductEditingViewPart\"\n"+
      "             id=\""+IConstants.PRODUCT_EDITING_VIEW_PART+"\">\n"+
      "       </view>\n"+
      "    </extension>\n"+
      "</plugin>\n"<br />;
  }

  public String getPluginName() {
    return "at.bestsolution.gwt.demo";
  }

Setting up a TreeViewer:

public Widget createPartControl() {
  VerticalPanel panel = new VerticalPanel();
  panel.setSize("100%", "100%");
  Tree tree = new Tree();
  tree.setSize("100%", "100%");
  panel.add(tree);
  panel.setCellHeight(tree, "100%");
  panel.setCellWidth(tree, "100%");

  final TreeViewer viewer = new TreeViewer(tree);
  viewer.setContentProvider(new TreeContentProvider());
  viewer.setLabelProvider(new LabelProvider());
  viewer.setInput(Datasource.getDatasource().getProductRange());
  viewer.addSelectionChangedListener(new SelectionChangedListener());
  getSite().setSelectionProvider(viewer);
  // ...

And finally binding a control to a model element:

TextBox box = new TextBox();
box.setEnabled(false);
table.setWidget(0, 1, box);

IObservableValue targetObservableValue = GWTObservables.observeText(box, GWTObservables.Change);
IObservableValue modelObservableValue = PEMFObservablesFactory.observeValue(Realm.getDefault(), product, Product.ID);
UpdateValueStrategy targetToModel = new UpdateValueStrategy();
UpdateValueStrategy modelToTarget = new UpdateValueStrategy();
modelToTarget.setConverter(new IntegerToStringConverter());
ctx.bindValue(targetObservableValue, modelObservableValue, targetToModel, modelToTarget);

The final result looks like this:

Posted in Databinding, GWT | 3 Comments

Doing RCP-Like programming with GWT

After having spent some time on GWT + Databinding I can now report success on porting over the Core-Databinding framework to GWT with fairly no changes from what is found in the Eclipse-CVS-Repository.

But to do real programming in GWT there’s more you need (Views, Editors, Commands, Actions, …) so I’ve also taken over the other core ideas from Eclipse into a GWT-Lib I called gjface (it isn’t a straight port of the Eclipse-API currently because of the lack of time but it’s fairly usebable already).

I’ve also created a Demo-Application you can find here and if you are interested how this Application is created you can get the source from here. I have only tested it on Firefox so it might be that it’s not working on IE currently.

I’ll blog later today how this all works together but if you want to take an in depth look I’m at ESE!

Posted in GWT | 4 Comments

The marriage of GWT with Eclipse-Technologies

I’m currently on the track to explore GWT and started just this morning with it. The first thing I found missing is something like the Viewers-Concept from JFace.

I don’t want to learn new things if the one I’m familiar with would make my life much easier. JFace-Viewers is one of my main working areas in Eclipse-land. So I sat down and took a closer look and after 1 hour of work my GWT-code looks like this:

package at.bestsolution.eclipse.jface.example.client;

import java.util.ArrayList;

import org.gwtwidgets.client.util.SimpleDateParser;

import at.bestsolution.eclipse.jface.client.viewers.TreeViewer;
import at.bestsolution.eclipse.jface.example.client.model.Family;
import at.bestsolution.eclipse.jface.example.client.model.Person;
import at.bestsolution.eclipse.jface.example.client.ui.MyContentProvider;
import at.bestsolution.eclipse.jface.example.client.ui.MyLabelProvider;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Tree;

/**
  * Entry point classes define <code>onModuleLoad()</code>.
  */
public class JFaceExampleApp implements EntryPoint {
  /**
    * This is the entry point method.
    */
  public void onModuleLoad() {
    Tree tree = new Tree();
    TreeViewer viewer = new TreeViewer(tree);
    viewer.setLabelProvider(new MyLabelProvider());
    viewer.setContentProvider(new MyContentProvider());
    viewer.setInput(createInput());

    RootPanel.get().add(tree);
  }

  private ArrayList createInput() {
    SimpleDateParser parser = new SimpleDateParser("yyyy-MM-dd");
    ArrayList list = new ArrayList();
    Family fam = new Family("Schindl");
    Person p = new Person("Tom",parser.parse("1979-05-01"),fam);
    p = new Person("Tina",parser.parse("1980-10-14"),fam);
    p = new Person("Laura",parser.parse("1991-08-07"),fam);
    list.add(fam);

    fam = new Family("Hoppichler");
    p = new Person("Andreas",parser.parse("1977-11-06"),fam);
    p = new Person("Franzi",parser.parse("1978-11-02"),fam);

    list.add(fam);
    return list;
  }
}

And the respective Viewer-classes like this:

package at.bestsolution.eclipse.jface.example.client.ui;

import java.util.ArrayList;

import at.bestsolution.eclipse.jface.client.viewers.ITreeContentProvider;
import at.bestsolution.eclipse.jface.client.viewers.Viewer;
import at.bestsolution.eclipse.jface.example.client.model.Family;
import at.bestsolution.eclipse.jface.example.client.model.Person;

public class MyContentProvider implements ITreeContentProvider {
  public Object[] getChildren(Object parentElement) {
    if( parentElement instanceof Family ) {
      return ((Family)parentElement).getList().toArray();
    }
    return new Object[0];
  }

  public Object getParent(Object element) {
    if( element instanceof Person ) {
      return ((Person)element).getFamily();
    }

    return null;
  }

  public boolean hasChildren(Object element) {
    return getChildren(element).length > 0;
  }

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

  public void dispose() {}

  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
package at.bestsolution.eclipse.jface.example.client.ui;

import org.gwtwidgets.client.util.SimpleDateFormat;

import at.bestsolution.eclipse.jface.client.viewers.ILabelProvider;
import at.bestsolution.eclipse.jface.example.client.model.Family;
import at.bestsolution.eclipse.jface.example.client.model.Person;

public class MyLabelProvider implements ILabelProvider {
  private SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");

  public String getText(Object element) {
    if( element instanceof Family ) {
      return ((Family)element).getName();
    } else if( element instanceof Person ) {
      return ((Person)element).getName() + " ("+format.format(((Person)element).getBirthday())+")";
    }

    return "";
  }
}

Now you think this is cool? Because this was to trivial I thought I’ll have to go further and after ~ 6h I had ported the the core-parts from the JFace-Databinding-Framework to GWT! So my UI-Binding-Code looks like this now:

// ....
TextBox box = new TextBox();

TextBoxObservableValue targetValue = new TextBoxObservableValue(box,TextBoxObservableValue.Change);
IObservableValue modelValue = PEMFObservablesFactory.observeDetailValue(Realm.getDefault(), value, "id", String.class);

DataBindingContext ctx = new DataBindingContext();
UpdateValueStrategy targetToModel = new UpdateValueStrategy();
targetToModel.setConverter(new IConverter() {
  public Object convert(Object fromObject) {
    return fromObject.toString();
  }

  public Object getFromType() {
    return null;
  }

  public Object getToType() {
    return null;
  }
});

UpdateValueStrategy modelToTarget = new UpdateValueStrategy();
modelToTarget.setConverter(new IConverter() {
  public Object convert(Object fromObject) {
    return fromObject.toString();
  }

  public Object getFromType() {
    return null;
  }

  public Object getToType() {
    return null;
  }
});
ctx.bindValue(targetValue, modelValue, targetToModel, modelToTarget);

The GWT-Compiler translates all into JS-Code and because there’s no Reflection-API available in this space I had to invent my own concept which I lend from EMF hence the name PEMF (for PoorEMF). Without question much of the Databinding-Framework is not working but at this stage I don’t mind. The good thing is that all those low-level modules use fairly only classes already available from GWT so porting the whole framework is only a matter of time.

Posted in GWT | 10 Comments

Branding for Windows (How to create .ico files automatically)

After some time not having developed for Win32. I today had to brand a small RCP-application and once more completely forgot how to create this “Programm Launcher icon” using opensource tools.

So I thought I have to restore this information somewhere I can find it later on:

1. Get nice icons:
The starting point for me is one of the open-source icon-collections (www.icon-king.com/) or oxygen.

2. Boot you favorit Linux Distro (Sorry Win-Users for you this story ends here (or you grab CygWin)):
Install the following tools:

  • convert: Chances are high it’s already installed
  • icotool: if not installed and not available for your distro (icoutils)

3. Copy the images:
Copy images the images the with the various sizes we need to a directory and given them eaually starting names. In my case these are:

  • icon_16_16.png
  • icon_32_32.png
  • icon_48_48.png

4. Create .ico-File:
The ico-File needed by RCP has to hold 6 images (32bit and 8bit).
So we need to convert the images to 8bit ones:

tom@vinea:icons>mkdir target
# Workaround because image magick doesn't seem to reduce colors when
# converting from png to png
convert -colors 256 icon_16_16.png target/tmp.gif
convert -colors 256 target/tmp.gif target/icon_16_16_8bit.png
convert -colors 256 icon_32_32.png target/tmp.gif
convert -colors 256 target/tmp.gif target/icon_32_32_8bit.png
convert -colors 256 icon_48_48.png target/tmp.gif
convert -colors 256 target/tmp.gif target/icon_48_48_8bit.png

Copy the original icons over to target-dir:

tom@vinea:icons>
cp -f icon_16_16.png target
cp -f icon_32_32.png target
cp -f icon_48_48.png target

Create the .ico-File using icotool:

tom@vinea:icons>
icotool -c target/icon_16_16_8bit.png target/icon_16_16.png \
target/icon_32_32_8bit.png target/icon_32_32.png \
target/icon_48_48_8bit.png target/icon_48_48.png \
> target/icon.ico

Here’s the full script for reference:

#!/bin/sh
rm -rf target
mkdir target

# Workaround because image magick doesn't seem to reduce colors when
# converting from png to png
convert -colors 256 icon_16_16.png target/tmp.gif
convert -colors 256 target/tmp.gif target/icon_16_16_8bit.png

convert -colors 256 icon_32_32.png target/tmp.gif
convert -colors 256 target/tmp.gif target/icon_32_32_8bit.png

convert -colors 256 icon_48_48.png target/tmp.gif
convert -colors 256 target/tmp.gif target/icon_48_48_8bit.png

# Copy images
cp -f icon_16_16.png target
cp -f icon_32_32.png target
cp -f icon_48_48.png target

icotool -c target/icon_16_16_8bit.png target/icon_16_16.png \
target/icon_32_32_8bit.png target/icon_32_32.png \
target/icon_48_48_8bit.png target/icon_48_48.png \
> target/icon.ico
Posted in 3.x | 4 Comments