SIDEBAR
»
S
I
D
E
B
A
R
«
TokenViewer – Databindings
February 1st, 2009 by Eugene Ostroukhov

TokenViewer was submitted to Eclipse.org as Bug#262846

I remember in one past project (financial application) there was a special control – “Lookup”. Basically, it was a label, text entry and a button. User entered some ID (say, employee SSN) the system will look up the employee, show employee first & last names in non-editable entries (to confirm that correct employee was found) and user may enter other values as he needs. The button would open a selection dialog so the user can select the employee by name.

I tried to implement similar functionality (excluding label and button) using token viewer & JFace bindings. I created a new TitleAreaDialog with following createDialogArea method:


        getShell().setText("Databings Test");
        setTitle("Some Dull Data Entry");
        setMessage("Enter all the needed data");
        Composite root = (Composite) super.createDialogArea(parent);</p>

<pre><code>    Composite dataEntry = new Composite(root, SWT.NONE);
    dataEntry.setLayout(new GridLayout(3, true));
    dataEntry.setLayoutData(new GridData(GridData.FILL_BOTH));
    TokenViewer tokenViewer = new TokenViewer(dataEntry);
    tokenViewer.getControl().setLayoutData(
            new GridData(GridData.FILL_HORIZONTAL));
    tokenViewer.setContentProvider(new EmployeeSSNContentProvider());
    tokenViewer.setLabelProvider(new EmployeeLabelProvider());
    tokenViewer.setInput(new EmployeeDAO());

    Text firstNameDisplay = new Text(dataEntry, SWT.READ_ONLY | SWT.BORDER);
    firstNameDisplay.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    Text lastNameDisplay = new Text(dataEntry, SWT.READ_ONLY | SWT.BORDER);
    lastNameDisplay.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    createBindings(tokenViewer, firstNameDisplay, lastNameDisplay);

    return root;

This method adds TokenViewer and two read-only text entries. Afterwards it calls “createBindings” to bind TokenViewer selection to those fields.

private DataBindingContext createBindings(TokenViewer tokenViewer,
            Text firstNameDisplay, Text lastNameDisplay) {
        DataBindingContext bindingContext = new DataBindingContext();</p>

<pre><code>    ISWTObservableValue firstNameObservable = SWTObservables
            .observeText(firstNameDisplay);
    ISWTObservableValue lastNameObservable = SWTObservables
            .observeText(lastNameDisplay);

    IViewerObservableValue selected = ViewersObservables
            .observeSingleSelection(tokenViewer);

    IObservableValue fname = BeansObservables.observeDetailValue(selected,
            "firstName", String.class);
    IObservableValue lname = BeansObservables.observeDetailValue(selected,
            "lastName", String.class);

    bindingContext
            .bindValue(firstNameObservable, fname, new UpdateValueStrategy(
                    false, UpdateValueStrategy.POLICY_NEVER), null);
    bindingContext
            .bindValue(lastNameObservable, lname, new UpdateValueStrategy(
                    false, UpdateValueStrategy.POLICY_NEVER), null);
    return bindingContext;
}
</code></pre>

<p>

As you can see, this method uses JFace bindings to bind TokenViewer selection first and last name to corresponding text fields.

When the user opens dialog the fields are empty. When the user begins typing the “wrong” SSN entry will be underlined until correct value is entered:

typingRead-only text fields will get populated once proper SSN is entered:

enteredUser may also use content assist to select employee from list:

ca-popup

 

Implementation details:

  1. Employee – POJO class that supports property change listeners to conform JFace bindings requirements.
  2. EmployeeDAO – DAO class that fetches Employee objects from database or any other source. In this example it returns a list.
  3. EmployeeLabelProvider – returns labels for content assist pop-up. Labels are “ “. It can also return icons and/or descriptions if needed.
  4. EmployeeSSNContentProvider – an instance of the ITokenContentProvider. It’s main responsibility is to transform text to/from object and to fetch instances from DAO. Notable methods:
    
    public Object[] getElements(Object inputElement) {
        return null;
    }
    
    This method will get called when content assist is invoked for empty field. It may return all elements but I chose to return none since it is common in real-world applications that the system will chose not to query the whole database at once

    public String toString(Object object) {
        return ((Employee) object).getSsn();
    }
This method returns the string that corresponds to given model object. I.e. when entering the classname this string would be fully qualified name – not the short name. CA will automatically convert short name to fully qualified one.

    public Object[] getChildren(Object object, String prefix) {
        Object[] elements = ((EmployeeDAO) object).getAllEmployees().toArray();</p>

<pre><code>    Collection&lt;Object&gt; selected = new LinkedList&lt;Object&gt;();
    for (Object employee : elements) {
        if (((Employee) employee).getSsn().startsWith(prefix)) {
            selected.add(employee);
        }
    }
    return selected.toArray();
}

Returns the elements that match given pattern. In real-world application this method would be smarter and more tightly integrated with DAO object so it only queries entries it needs.

    public Object fromString(Object parent, String value) {
        Object[] children = getChildren(parent, value);
        for (Object child : children) {
            if (((Employee) child).getSsn().equals(value)) {
                return child;
            }
        }
        return null;
    }
This method decodes a string to exact object. If this method returns not-null then selection event will be updated.

You can download sample project (that contains updated TokenViewer) here.


Comments are closed

»  Substance:WordPress   »  Style:Ahren Ahimsa