SIDEBAR
»
S
I
D
E
B
A
R
«
Browsers in SWT
Oct 7th, 2010 by Eugene Ostroukhov

Browsers are arguably the single most important application in the modern computing. There are many reasons why all major modern UI toolkits provide an integration with one (or several). There are many reasons to use browser in Eclipse RCP or IDE application:

  1. Use it to display static information with rich formatting (i.e. API doc, query result)
  2. Use it to integrate rich web application – either by creating a site-specific browser that connects to a remote server or by serving the application from your Eclipse instance.
  3. To provide better tools for web developers – integrating browser will let you better understand application runtime state and will allow you better explain to user the result of modifications.

SWT has a browser integration for a long time. Actually it has several integrations:

  1. Default System Browser. That’s what you get when you use the org.eclipse.swt.browser.Browser class (without specifying the “MOZILLA” style). This is by far the most stable integration that would cause you the least integration problems. It will wrap OS default browser (IE on Windows, Firefox on Linux and Webkit (Safari) on Mac OS X) – not that it will wrap the OS-default browser, not the browser that the user chose as a default. The biggest issue is that on Windows it turns into pumpkin IE – and you have no control over actual IE version it would become. So you will likely need to avoid some advanced features (including HTML5) and really invest a lot to ensure cross-platform compatibility of your web app code. Another issue is that there is little control over some more advanced browser features – i.e. as an IDE developer you may need to change the security configuration and that is not possible in a unified cross-platform way. Oh, and “default browser” might not be available on some Linux setups (at least that was a case a few years ago).
  2. XULRunner (Mozilla Firefox). This support is baked into SWT (see this snippet) and is triggered by specifying SWT.MOZILLA as a browser style. This browser provides a uniform cross-platform rich web experience but it still has a few shortcomings. First of all, it requires the browser to be installed separately. It will try to use the Firefox from the user OS and that means that you would have little control over the Firefox version – and this is exaggerated by the fact that some newer Firefox versions may break compatibility with older SWT versions and thus force the users to update their SWT-based applications. There are also some pretty irritating issues around integration edges (i.e. FF may grab input focus when you try to refresh it). There is a way to bundle XULRunner with your application if you create your custom bundle or use the one Zend created for ATF project.
  3. WebKit integration. This one gets more and traction as the WebKit is probably the most designed-for-embedding browser engine. SWT uses WebKit on Mac by default and support on GTK was introduced in SWT 3.6. Support for Webkit on Windows is planned for SWT 3.7. I have not tried it yet but it looks like there still will be a problem with the distribution as WebKit has some core components licensed under LGPL, which makes it impossible to be published on Eclipse.org.
  4. WebKit4SWT from Genuitec. This integration is Windows-only. As far as I understand, it is based on Chromium Embedding Framework so there is a chance that it will be available on other platforms when the upstream project adds those platforms (Valve used same framework for their Steam client and had published Mac source code – but it is not yet integrated into the upstream project). This project is used for Genuitec MobiOne project.
Using expressions in your extension points
Sep 7th, 2010 by Eugene Ostroukhov

Originally I meant to create a reference of the Eclipse expressions and properties available in SDK but there is already such article in Eclipse Wiki. I would strongly recommend bookmarking that article – it is an excellent reference. I would like to describe how you could leverage the expressions in your extension points (when you declare extension points as opposed to providing extensions to platform extension points). There are several reasons to use expressions as a part of your extension point:

  1. Lazy initialization – expression can be tested without activating the plugin that contributed the extension.
  2. External declaration – expressions are declared in the plugin.xml and that sometimes makes it easier to maintain them.
  3. Flexible and pluggable language. Users can leverage org.eclipse.core.expressions.definitions extension point to declare reusable expressions. Users can also leverage org.eclipse.core.expressions.propertyTesters to declare property testers that contain complex logic.

To use expression in your extension point you will need to update your extension point schema file (exsd file) to declare expression language elements. The easiest way is by referencing expression language schema:

<include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>

This will import all the elements so you can use them in the extension elements editor:

Expression elmeents in the extension element editorNote that you can specify any expression element as the expression root. I would recommend to using the “enablement” element as this would let you get all changes to expression languages as they appear in the subsequent Eclipse releases. Plug-in developers will see the expressions in the PDE editor after extension point definition is updated.

To test the expression you will need to parse the expression:

IConfigurationElement[] children = configurationElement.getChildren("enablement");
if (children.length == 1) {
    expression = ExpressionConverter.getDefault().perform(children[0]);
}

Then you will have to create “evaluation context” and evaluate the expression. Evaluation context provides all the variables that are available to the expression – like “activeWorkbenchWindow” and others in the commands framework. You may spacify one object as a “default” (it is “project” variable in my snippet):

final EvaluationResult result = expression.evaluate(new EvaluationContext(null, project));

“result” will be one of FALSE, TRUE and NOTLOADED. NOTLOADED is mostly when the user references the propery tester from inactive plug-in and tells the framework to avoid plug-in activation to instantiate just the property tester.

After this point the user will be able to use the expressions with your extension point just the same way they are used in extension points declared by core Eclipse.

Using Jetty as an OSGi HTTP Service
May 19th, 2010 by Eugene Ostroukhov

I was unable to find any documentation on how to use Jetty as an OSGi HTTP service. We needed it as a part of our WRT tools effort to host a code that would serve as a runtime environment (sort of “emulator”) for the user code. I guess there are many other scenarios that could make use of the embedded server.

Basically, everything you need to know can be found in org.eclipse.wst.ws.internal.explorer.WebappManager class that is part of the WebTools project. The code is very simple:

Dictionary d = new Hashtable();
d.put("http.port", new Integer(getPortParameter())); //$NON-NLS-1$
// set the base URL
d.put("context.path", "/wse"); //$NON-NLS-1$ //$NON-NLS-2$
d.put("other.info", "org.eclipse.wst.ws.explorer"); //$NON-NLS-1$ //$NON-NLS-2$</p>

<p>// suppress Jetty INFO/DEBUG messages to stderr
Logger.getLogger("org.mortbay").setLevel(Level.WARNING); //$NON-NLS-1$</p>

<p>JettyConfigurator.startServer(webappName, d);
checkBundle();

In our code we do not specify the context path (so we have root as a context path) and specify a different ID so both our code and Web Services tools could coexist.

What is really important is that the server will run in Eclipse process and deployed servlets can have access to Eclipse APIs so you can interact with the workbench as you need – i.e. you can have all the settings stored in the preference store and configurable from the preference page, access the workspace and interact with your IDE (i.e. in our case it is possible to do AJAX call to disconnect JavaScript debugger).

There are two ways to register servlets:

  1. Programmatic (using OSGi APIs)
  2. Declarative (using org.eclipse.equinox.http.registry.servlets extension point)

In our application we use programmatic way so we don’t have to rely on singletons to integrate them with our IDE.

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.

[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.

»  Substance:WordPress   »  Style:Ahren Ahimsa