(Re-)Binding SWT forms with WindowBuilder

(Re-)Binding SWT forms with WindowBuilder

A very common case in UI applications are forms which are bound to exchangeable model objects. For example, one might want to bind this address form in such a way that you can set a new Address object at any time with the UI reflecting that change:

Example: Address Form

The plain old binding can be created easily using WindowBuilder:

Create Binding in WindowBuilder

The resulting code might look like this:

public class AddressViewPart extends ViewPart {
   private DataBindingContext bindingContext;
   private Address address;
   private Text textName;
   @Override
   public void createPartControl(Composite parent) {
      parent.setLayout(new GridLayout(3, false));
      Label lblName = new Label(parent, SWT.NONE);
      lblName.setText(Messages.YetAnotherViewPart_lblName_text);
      textName = new Text(parent, SWT.BORDER);
      textName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));  // ...
      bindingContext = initDataBindings();
   }
   protected DataBindingContext initDataBindings() {
      DataBindingContext bindingContext = new DataBindingContext(); //
      IObservableValue textNameValue = WidgetProperties.text(SWT.Modify).observe(textName);
      IObservableValue addressNameValue = PojoProperties.value("name").observe(address);
      bindingContext.bindValue(textNameValue, addressNameValue, null, null); //
      return bindingContext;
   }
}

The tricky part is to bind this in such a way that the model object can be exchanged at any time. There are three possible ways:

1) Dispose bindings

The easiest way is to dispose all bindings and just re-bind whenever a new model object appears:

public class AddressViewPart extends ViewPart {  // ...  protected void setAddress(Address address) { this.address = address; if (bindingContext != null) bindingContext.dispose(); bindingContext = initDataBindings(); }  // ... }

Unfortunately, WindowBuilder insists on putting the initDataBindings call in createPartControl. Also, if you are using ControlDecorationSupport you will stumble upon Bug 341713 – DataBinding ControlDecorationSupport not disposed when DataBindingContext is disposed.

2) Binding to a WritableValue

Another way is to use a detail binding to a WritableValue which can be changed at any time:

public class AddressViewPart extends ViewPart {  private WritableValue addressValue = new WritableValue();  protected void setAddress(Address address) { this.addressValue.setValue(address); }  protected DataBindingContext initDataBindings() { // ... IObservableValue addressNameValue = PojoProperties.value("name").observeDetail(addressValue); // ... } }

Such a Binding can be created in WindowBuilder:

Detail binding in WindowBuilder

3) Bean binding

Yet another way is to make the ViewPart itself a Bean with PropertyChangeSupport:

public class AddressViewPart extends ViewPart {  private PropertyChangeSupport changes = new PropertyChangeSupport(this);  private Address address;  public Address getAddress() { return address; }  public void setAddress(Address address) { changes.firePropertyChange("address", this.address, this.address = address); }  public void addPropertyChangeListener(PropertyChangeListener l) { changes.addPropertyChangeListener(l); }  public void removePropertyChangeListener(PropertyChangeListener l) { changes.removePropertyChangeListener(l); }  protected DataBindingContext initDataBindings() { //... IObservableValue addressNameValue = BeanProperties.value("address.name").observe(this); //... }  }

While I like this way conceptionally, in practice it has the problems of Java’s PropertyChangeSupport being cumbersome. Also, JFace Data Binding doesn’t allow to mix Beans and Pojos, so if the Address object in the example is a Pojo, one will get NoSuchMethodException: Address.addPropertyChangeListener(java.beans.PropertyChangeListener). And there seems to be no way to generate such a binding in WindowBuilder.

It’s 6 am and I missed them already

Cute Kenneth, Sleepy Nathan

This picture was taken during my family’s visit at Nathan’s birthday. It was a great moment though i was having a bad flu. I love my family.

Tired Brain, Distractions, and Dehydration

“Man, I’m tired!”. That was probably what my brain try to tell me this afternoon. But it was stil 3 pm and I have a list of to-do’s waiting on my TiddlyWiki. So I took a little break and fired up the browser to visit my favourite blogs. I even watched an episode of my favourite anime at the break hour, though I know it’s a bad idea. All what I get was an even more tired brain plus a pair of heavy eyes.

Then I started to think about what was wrong with my brain. After a short walk I realized several things that might cause exhausting to my brain:
1. Bad diet. I woke late this morning and missed the breakfast. Even worse, I had instant noodles for lunch.
2. Dehydration. Long running, extense task swollen me away made me forget to drink water that was even at my desk already.
3. Distractions. Several chores distracted me, some even drove me away far enough, left me wondering “What was that?!”.

So tomorrow I’ll try to revive my pomodoro timers to help me keep focused, though it costs 5 mins on every pmds.

Load Photosop Pattern (.pat) in GIMP

Saya bukanlah seorang graphic designer, tapi memang kadang suka iseng ngutak-ngatik image dengan tools favorit saya, GIMP dan Inkscape. Ketika saya sedang browsing di deviantart, saya menemukan beberapa patterns yang bagus. Akhirnya saya pun men-download patterns tersebut dan dengan yakinnya saya menjalankan GIMP untuk me-load file pattern tersebut.

Wah, ternyata tidak bisa ya :) GIMP hanya dapat membuka file .pat format GIMP saja. Tidak lama setelah googling saya pun menemukan jalan keluarnya. Ternyata ada user GIMP yang membuat plugin untuk supaya GIMP dapat membuka file .pat milik Photoshop. Plugin yang disediakan masih dalam bentuk source code C yang harus di-compile terlebih dahulu. Untungnya di halaman download plugin tersebut ada keterangan cara compile-nya.

Berikut saya kutip cara compile di Ubuntu Linux (sudah saya test di Ubuntu Jaunty (9.04)):
1. install libgimp2.0-dev: sudo apt-get install libgimp2.0-dev
2. compile source code plugin: gimptool-2.0 –build ps-pat-load_1.c
3. akan dihasilkan file binary ps-pat-load_1. Copy file tersebut ke ~/.gimp-2.6/plug-ins
4. restart gimp

Setelah itu saya coba buka kembali file .pat tadi, dan voila! File pattern berhasil dibuka. Hanya saja kebetulan file .pat yang saya download berisi beberapa pattern sehingga GIMP membukanya dalam satu dokumen dan patterns-nya dipisah menjadi beberapa layer. Tapi mudah saja. Saya tinggal meng-copy paste layer tersebut satu per satu menjadi dokumen masing-masing.

Untuk anda yang menggunakan GIMP di MS Windows, download tools yang sudah di-compile untuk bekerja di MS Windows di link ini.

Ruby, FXRuby, Ubuntu 9.04

Bulan ini saya mencoba 3 hal yang baru, Ruby, FXRuby, dan Ubuntu 9.04. Setelah instalasi Ubuntu 9.04 selesai, saya langsung mencoba meng-install Ruby dan FXRuby. Setelah sekitar 1 jam mencari paket yang tepat dan men-download-nya, berikut saya rangkum paket-paket apa saja yang perlu di-install:

1. ruby1.8
2. ruby1.8-dev
3. ruby1.8-examples
4. rdoc1.8
5. ri1.8
6. rubygems
7. irb
8. libzlib-ruby
9. build-essential (last but the most! :) )

Untuk FXRuby:
1. Install paket:
a. libfox-1.6-0
b. libfox-1.6-dev
c. g++
d. libxrandr-dev
2. Install FXRuby dengan gem:
sudo gem install fxruby –remote

Nah, kalau sudah install semua paket tersebut, tinggal test contoh dari situs FXRuby. Horee… Ups! Kok error? Tenang, jangan panik, ada solusinya. Kalau di Window$ anda cukup require ‘fox16′ dan include Fox, maka sekarang anda harus menambahkan require ‘rubygems’ sebelum require ‘fox16′.

Ok, Ruby, here I come….

Ikuti

Get every new post delivered to your Inbox.