SIDEBAR
»
S
I
D
E
B
A
R
«
Open Web Development Tools for Mobile
Mar 18th, 2010 by Eugene Ostroukhov

Here at Symbian Foundation we believe that one of the best way to attract users to a mobile platform is to have more/better applications. The best way to have more/better applications is to attract more developers. And one of the best ways to attract more developers is to provide better tools. And one of the best ways to provide better IDE is to build on top of Eclipse.

And that is exactly what we are aiming to do.

We took (in no particular order):

  1. Contributions from our member company (Nokia)
  2. Eclipse Platform from Eclipse Foundation
  3. JavaScript Developer Tools from Eclipse Foundation
  4. JS debugger from Google Chrome Developer Tools

and glued them together to produce a new IDE that will make web development experience for Symbian platform much more pleasant.

This is what you can do with our IDE:

  1. Create a new WRT (Web Runtime) application project from one of the predefined templates or using existing packaged WRT application (WGZ file) as a template.
  2. Edit HTML, JS and other files. This featureset is coming from WTP and JSDT in particular. We added validation for project metadata files and CSS files.
  3. Debug the application. Chrome browser is used as a runtime and Chrome Developer Tools are used for debugger UI.
  4. Package your application for distribution or deploy it directly to a device.

You can find the builds for different platforms on our downloads site. We plan to release the first version on March 31st.

Everybody is invited to:

  • Visit the project page to obtain the sources. Use “Eclipse for JEE Developers” bundle with installed XULRunner as a target platform. Target platform can also be downloaded here (single downloads for all platforms).
  • Try the IDE (there is a quickstart document)
  • Comment on our forums or mailing list.
  • Submit bugs to our bugtracker (like if there are any…).
  • Participate in the project.

At this point this project is very much focused on Symbian platform and WRT in particular. But we are planning to expand the scope – both to encompass increasing scope of web support in Symbian platform (cWRT is one example) and to supporting more libraries and runtimes that are not platform-specific.

I hope to share some development experience in this blog so feel free to ask any questions on implementation.

I would really like to thank developers from Eclipse.org project and Google Chrome Developer Tools for making available all the great frameworks and tools.

“Participate in community!” they said…
Dec 11th, 2009 by Eugene Ostroukhov

I see a lot of discussion in the blogs on how to invite new developers to participate. They all are talking about people being reluctant to do development, making the eclipse.org site interface more inviting – but really, is this the biggest problem? I wonder, does anybody think obscure location of the CVS URL would really stop anybody from trying to enhance the favorite framework?

Consider this (the ones that I remember):

Bug 287887 – I haven’t seen response like “why would anybody want this” or else. The patch was submitted 3 months ago.

Bug 155479 – several commercial projects would like to see it. Patch was submitted in April.

Bug 166906 – pretty irritating bug. The patch was submitted four years ago.

Note – these are patches to make Eclipse better from the end-user POV. It’s not the patches to make Eclipse frameworks more open for extension so we can build better products on top of it – I’m pretty sure that most commercial developers know that there is next to no chance to get such change into Eclipse.org.

The result is quite simple. I joined a new company recently and from the start I say – do not expect the Eclipse.org to cooperate. We need to consider a way to branch projects we use – before we reach the point it is not possible to deliver proper product to our customers because the framework was not designed to support something.

I believe there should be a strict policy in Eclipse.org for handling patches – i.e. the projects should commit to responding for the patch in 2 weeks or one month – and either describe what’s wrong or to incorporate the patch into main repository. Otherwise there will be many Eclipses – Git makes it really simple.

And I’m not mentioning this: 262846 – pure enhancement to make simple API for the popular feature. I submitted this one in February – and I missed some Eclipse.org deadline. The result? Even in the best-case scenario I won’t be able to use this in my commercial product till Summer 2010 – 1.5 years. That’s if we don’t consider that the chances of this bug being committed are still slim. So why bother? 1.5 years is a long time.

Release names
Nov 17th, 2009 by Eugene Ostroukhov

I wonder if I’m the only one who can’t remember fancy names for Eclipse releases – Europa, Ganymede, Galileo, Helios. I think it’s not really good that there’s no easy way to memorize them (I wonder if they were meant to be in alphabetical order – if not for “Ganymede” and “Galileo”). Eclipse releases annually – so why doesn’t it has name like “Eclipse 2007”?

So:

Name Platform/JDT/PDE CDT WTP BIRT Site
Callisto 3.2 3.1 1.5 2.1 link
Europa 3.3 4.0 2.0 2.2 link
Ganymede 3.4 5.0 3.0 2.3 link
Galileo 3.5 6.0 3.1 2.5 link
Helios 3.6 link
WTP Frameworks Not Only For Web
Oct 15th, 2009 by Eugene Ostroukhov

WTP is a huge codebase with a lot of ready solutions for the problems that many Eclipse plug-in developers face. Unfortunately to me it looks like these solutions are not picked up as the people consider WTP only to concern with web site authoring. I would like to list some frameworks I believe are useful in all areas where Eclipse is adopted:

1. Faceted Project Framework

(Link to tutorial)

facetsEssentialy Facets are project natures – only on steroids. Project natures can easily be added to a project and you can test if the project has specific nature – but the facets framework provides so much more:

  1. Well defined facet lifecycle. Facet can be added, removed, upgraded you can define interdependence between facets. All done using clean API.

  2. UI. You don’t need to implement your own menu action cramming the toolbars and confusing the user. You can contribute wizard pages that users will be able to invoke either when creating new project or when editing project properties. Sure, it is still possible to create custom action, wizard, etc.

As far as I understood this framework will be a basis for a projects framework in E4. I believe that will really streamline Eclipse user experience in many ways.

2. Structured Source Editing Framework

(Link to subproject page)

sseExtremely great source editors for XML, XSL, JSP, HTML, CSS, XSD – and other files. The editor has rich navigation & editing features JDT user would expect and is also extremely extensible. If you need to create an editor for XML-based file type you can pick the SSE XML editor and start customizing in small increments – outline view, content assistant, auto edit strategies, formatting, validation, hyperlinks. SSE editors can be embedded into multipage editors. Model management facilities can be used outside of the editor itself (i.e. from some toolbar action) and will help avoid conflicts when user did some change to the file that is already opened in the editor.

It is also possible to use custom parser to create editor for non-XML files.

I believe that SSE is long overdue in core Eclipse platform – PDE editor and ANT script would really benefit from reacher source editing capabilities (i.e. formatting).

3. Validation Framework

(Extension point description)

validation

This framework provides a clean and easy way to add build-time validation to workspace resources. This way project will have only one validation builder attached to it and it is easy to change the set of validators between product versions. The framework will handle dull tasks like markers management (i.e. there’s no need to remove the markers after the user fixed the problem) and properly call the validator on manual or auto build. There is also UI to manage validators on workspace and project levels.

CCombos are evil
Sep 5th, 2009 by Eugene Ostroukhov

org.eclipse.swt.custom.CCombo are evil and should never be used as components on dialogs and editors!

They look deceptively “fine” on Windows: ccombo_win

But on MacOS X (I would expect same on on GTK) they look completely wrong:

ccombo_macosxIt is not always possible to test on other OSes – so I believe avoiding this component is a good way to make the UI look better on other OSes.

Same Button, Different Meaning
Aug 27th, 2009 by Eugene Ostroukhov

Consider following two images: wizard

wizard_progressHere you can see what I consider as a major UI antipattern – Cancel button has two distinct roles. In the first case it works as a close button on the window title bar – if the user clicks it, the wizard dialog will close and the user input will be lost. In the bottom case the Cancel button is a “Cancel task” button – the task will be stopped but the dialog will be retained. This is pretty confusing for the users as they are not sure if they loose input in later case. I suggest we introduce a new button that will explicitly stop the task but has nothing to do with wizard dialog:

stopbuttonThis way Cancel button always mimics Close Window button – i.e. it is grayed out when the wizard dialog cannot be closed. I filed this enhancement suggestion (along with a patch) as bug 287887 in Eclipse.org bugtracker.

[Tip] JFace Wizards With Non-Lineal Flow
Aug 22nd, 2009 by Eugene Ostroukhov

Several times I needed to implement wizards that have variable flow (i.e. user input on one page defines if next page is shown and what next page(s) will be). At first I felt it is complex and pretty counter-intuitive to implement the behavior – but the problem was that I didn’t quite understand the Wizard logic.

Usually JFace wizard is a one instance of org.eclipse.jface.wizard.IWizard with one or more org.eclipse.jface.wizard.IWizardPage pages. My mistake was that I assumed that both Wizard and Pages are “Views” in MCV terms – so I was confused on how to create the logic. But actually Wizard is a controller and Pages are views. What this means is that:

  1. Wizard instance is responsible for “directing” wizard flow.
  2. Wizard instance bridges between “model” and “pages” – i.e. it initializes pages from model, interprets information from pages.
  3. Pages are responsible for information presentation, user entry interpretation, validation, etc.
  4. Wizard depends both on model and views (pages), views are self-contained.

To create wizard with non-lineal flow I do the following:

In addPages method I add all the pages – independent on wether they are always shown or not:

public void addPages() {
    firstWizardPage = new FirstWizardPage();
    addPage(firstWizardPage);
    optionalWizardPage = new OptionalWizardPage();
    addPage(optionalWizardPage);
    lastWizardPage = new LastWizardPage();
    addPage(lastWizardPage);
}

Thus all pages will be properly initialized by Wizard, all controls will be created and the wizard dialog size will be set to the biggest of the pages so no clipping will occur. Then I override getNextPage and getPreviousPage in the Wizard. Depending on user input (or model state) wizard decides what pages should be shown next. In my example first wizard page is simply a page with single checkbox – so I added “isChecked” method that returns the checkbox state:

@Override
public IWizardPage getNextPage(IWizardPage page) {
    if (page == firstWizardPage) {
        if (firstWizardPage.isChecked()) {
            return optionalWizardPage;
        } else {
            return lastWizardPage;
        }
    }
    return super.getNextPage(page);
}</p>

<p>@Override
public IWizardPage getPreviousPage(IWizardPage page) {
    if (page == lastWizardPage) {
        if (firstWizardPage.isChecked()) {
            return optionalWizardPage;
        } else {
            return lastWizardPage;
        }
    }
    return super.getPreviousPage(page);
}

In more complex scenarios I use these methods to refresh the model with user entry and propagate the changes to other pages (i.e., if user entry on one page changes the contents of the list on another.

When user input needs the wizard to refresh the workflow I add a call to getContainer().updateButtons() – i.e. in my example I added this to checkbox selection listener. This will call getNextPage, getPreviousPage and some other wizard methods in wizard-independent mode.

[Tip] Using Mac OS X DMG to keep workspaces
Jul 14th, 2009 by Eugene Ostroukhov

I’ve been using Mac OS X r/w disk images (DMG) to keep workspace for a couple months now – and I think it is great. Currently my workspace size is slightly above 2Gb:

  1. I didn’t notice any performance degrade – in both build and IDE operation.
  2. I can easily back-up/restore/clone workspace. I attempted to use Time Capsule/Time Machine for workspace backup – but they are completely unfriendly for the large amount of the small files that make up the workspace.
  3. (Luckily, haven’t tried this yet) – can be moved to another Mac in a matter of minutes.

I think it would also make sense to keep the whole dev environment (Eclipse SDK/target platform/workspace) on the DMG so it is easy to switch between older/newer versions – but I didn’t configure it that way yet.

DMG should be excluded from Time Machine back-up or TM will copy the whole image file time each time there’s some change in the workspace.

Export Limitation?
Jul 6th, 2009 by Eugene Ostroukhov

I live in Ukraine. I use Amazon for ages – but at last I found top-secret book that it seems like can’t be exported from US:

emfbook

I know no other Eclipse/Java/Cocoa/whatever book that can’t be exported from US. There should be something really big in this one – if only I find some bookstore that would smuggle it here for a decent delivery price…

TokenViewer – Databindings
Feb 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.

»  Substance:WordPress   »  Style:Ahren Ahimsa