Eclipse Search

Loading

Feb 25, 2009

WireframeSketcher - Review and free licenses

A picture is worth of 1000 words. That is why I have a habit of creating mockups/prototypes of UI before creating the real ones. There are umpteen number of tools available in the market, but I'm comfortable with plain old paper & pencil. Mostly because I don't need complex tools and partly because if I convert the price from Dollars to Rupees it would leave a bug hole in my wallet. Add to that I use Mac (my personal laptop), Windows (my official laptop) and Linux (my spare desktop). It is hard for me to find a simple tool that would work on all OS and still available for a cheaper price. To end my worries, here is WireframeSketcher.

Its an Eclipse plugin, so it works perfectly on all the platforms. Lets talk about simplicity.
The tool is as simple as it gets. The editor works on a .screen file, which can be kept under any project. In the editor, you have a drawing canvas and a palette with the most commonly used UI widgets. Drag and drop the elements you need from the palette to the canvas. You can group elements, adjust the Z-Order, move or resize them. Sounds like a perfect fit for me. Here is a screen shot of the product in action:

WireframeSketcher
I usually create the mockup and then create the actual UI. For a change, I tried creating a mockup of the existing UI. The mimicked picture:
WireframeSketcher

Thats a pretty rough sketch. But creating the above took me less than 5 mins! I can spend a little more time and make it look more like the original picture, but I think this conveys the message. I wish it supports more options like generating SWT/Swing code from the mock up. How cool that would be? Awesome, but that would would deviate from its mail goal - creating mockups. I think it will compromise on the simplicity as well.

I wish I could write more about this tool, but honestly there is nothing like you working on this. You don't have to go thru a a big manual. Just create a new .screen file and start using it. Period.

Overall, its a neat and simple tool that helps you to create mockups. If you are looking for a such a tool to prototype the UI and explain it to the customer/boss and willing to live with minor nuances, then this tool is for you. If you are looking for more advanced one with complete control over the UI, you have to look elsewhere.

Now lets come to the last part - cost of it. Right now there is no commercial version available. Evaluation licenses are available to play around with the tool. If you want a full free license, here is a chance exclusively for the readers of this blog.

All you have to do is to post a comment answering this simple question: "What are the pros of UI prototyping?". Remember to enter your comment on or before March 3rd, 2009 and your comment should have your name and email id. Peter will be selecting 5 random answers and will be giving out licenses to them.

(In case you don't want to expose your email id in public, just leave the comment and send your name & email id to my email id: grprakash@gmail.com)

Feb 23, 2009

Commands Part 5: Authentication in RCP applications

One of the frequently asked questions on Command Framework is 'how to dynamically update a command?' I thought I'll couple the answer with implementing ISourceProvider and explain it with a usecase: Authentication in RCP applications. Most of the RCP applications I've seen, needs authentication. Obviously it would need a Login/Logout menu items and other user related options. This can be accomplished in many ways, and I'm going to show you how to do it with Command Framework.
Lets do it in step by step.

Defining the session state thru ISourceProvider:

First, we need to store the session state in a variable. When we say variable in Command Framework, its not a public final static String. It is something that you can use it in the visibleWhen, activeWhen and enabledWhen expressions. The variable has to be provided thru a ISourceProvider:
<extension
      point="org.eclipse.ui.services">
   <sourceProvider
         provider="com.eclipse_tips.rcp.app.SessionSourceProvider">
      <variable
            name="com.eclipse-tips.rcp.app.sessionState"
            priorityLevel="workbench">
      </variable>
   </sourceProvider>
</extension>

A ISourceProvider can provide the state of multiple variables. However, our source provider will give the value of only one variable - 'com.eclipse-tips.rcp.app.sessionState'. The values of this variable would be either 'loggedIn' or 'loggedOut'. The list of values cannot be defined thru the extension, so this is up to you to define it, publish it and use it.
In the extension, you can see the priorityLevel attribute. This is used by the IHandlerService to determine which handler is active for a given command and its defined in the org.eclipse.ui.ISources interface. See my earlier tip on Command Framework for more explanation on this priority attribute.
The class should either implement ISourceProvider or extend AbstractSourceProvider. The preferred way is extending, so we'll do it that way:
public class SessionSourceProvider extends AbstractSourceProvider {
    public final static String SESSION_STATE = "com.eclipse-tips.rcp.app.sessionState";
    private final static String LOGGED_IN = "loggedIn";
    private final static String LOGGED_OUT = "loggedOut";
    boolean loggedIn;

    @Override
    public String[] getProvidedSourceNames() {
        return new String[] {SESSION_STATE};
    }

    @Override
    public Map<String, String> getCurrentState() {
        Map<String, String> currentState = new HashMap<String, String>(1);
        String currentState =  loggedIn?LOGGED_IN:LOGGED_OUT;
        currentState.put(SESSION_STATE, currentState);
        return currentState;
    }

     @Override
    public void dispose() {}

    public void setLoggedIn(boolean loggedIn) {
        if(this.loggedIn == loggedIn)
            return; // no change

        this.loggedIn = loggedIn; 
        String currentState =  loggedIn?LOGGED_IN:LOGGED_OUT;
        fireSourceChanged(ISources.WORKBENCH, SESSION_STATE, currentState);
    }
}

The first method is simple. As I mentioned earlier, a source provider can provider the state of multiple variables. The list of the variables (source names) is returned in the call. The second method is called to get the current state. The variable:value pairs are put in a map and returned back to the caller. The third method dispose is a no-op method for us. These three methods completes the API contract, but we have added one more method, where the value is updated to the source provider itself. So whenever a Login/Logout happens we need to call this method. This method fires the sourceChanged event, so that all the listeners can update accordingly.
When the sourceChanged event is fired, the status of the Command Handlers which has activeWhen or enabledWhen expressions with this variable re-evaluated with the new value of the variable. This holds good for visibleWhen expressions of the Commands as well. So if you want to show/enable a contribution item only when the user has logged in, you can use this variable like:
<extension
      point="org.eclipse.ui.menus">
   <menuContribution
         locationURI="menu:file?after=additions">
      <command
            commandId="org.eclipse.ui.window.preferences">
         <visibleWhen>
            <with
                  variable="com.eclipse-tips.rcp.app.sessionState">
               <equals
                     value="loggedIn">
               </equals>
            </with>
         </visibleWhen>
      </command>
   </menuContribution>
</extension>

Now the File->Preferences will be visible only when the user has logged in.

Updating the state:

Now that we have the source provider and the menu items that are dynamically enabled/disabled or shown/hidden according to the sessionState, the problem is how to we update the state?
Elsewhere, when a command is executed for Login/Logout, we have to make a call to SessionSourceProvider.setLoggedIn() method. But how do we get hold of the instance of the SessionSourceProvider? This is where the ISourceProviderService comes into picture. This service has a getSourceProvider() method, where if you give the variable name, it will give the corresponding source provider. The next obvious question would be where to get the implementation of this service? Not this service, for any service, you can use IServiceLocator to get the implementation and fortunately the IWorkbenchWindow implements this service. So when we execute the Login/Logout command:
// get the window (which is a IServiceLocator)
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
// get the service
ISourceProviderService service = (ISourceProviderService) window.getService(ISourceProviderService.class);
// get our source provider by querying by the variable name
SessionSourceProvider sessionSourceProvider = (SessionSourceProvider) service.getSourceProvider(SessionSourceProvider.SESSION_STATE);
// set the value
sessionSourceProvider.setLoggedIn(isSessionActive);

Dynamically updating the Login/Logout command:

The Login and Logout commands are mutually exclusive. When one appears the other won't. So you can have two different commands and use the visibleWhen with our sessionState variable to show/hide them. The other way is to have one command and update the text of the command according to the state. The first way is very similar to the Preference command that is explained above, so let me explain the second way here:
The idea is to define a single command and two handlers:
<extension
      point="org.eclipse.ui.commands">
   <command
         id="com.eclipse-tips.rcp.app.sessionCommand"
         name="Session Command">
   </command>
</extension>

<extension
      point="org.eclipse.ui.handlers">
   <handler
         class="com.eclipse_tips.rcp.app.handlers.LoginHandler"
         commandId="com.eclipse-tips.rcp.app.sessionCommand">
      <activeWhen>
         <with
               variable="com.eclipse-tips.rcp.app.sessionState">
            <equals
                  value="loggedOut">
            </equals>
         </with>
      </activeWhen>
   </handler>
   <handler
         class="com.eclipse_tips.rcp.app.handlers.LogoutHandler"
         commandId="com.eclipse-tips.rcp.app.sessionCommand">
      <activeWhen>
         <with
               variable="com.eclipse-tips.rcp.app.sessionState">
            <equals
                  value="loggedIn">
            </equals>
         </with>
      </activeWhen>
   </handler>
</extension>

<extension
      point="org.eclipse.ui.menus">
   <menuContribution
         locationURI="menu:file?before=quit">
      <command
            commandId="com.eclipse-tips.rcp.app.sessionCommand"
            style="push">
      </command>
   </menuContribution>
</extension>  

So the first handler, LoginHandler will be active when the user is logged out and the LogoutHandler will be active when the user is logged in. Both the handlers after performing their respective actions will notify the SessionSourceProvider, but how do we change the menu text? This happens thru IElementUpdater. When a handler implements this interface, it can update the associated contributions. When I say update, it means the text, tooltip, image etc. So the LoginHandler would look like:
public class LoginHandler extends AbstractHandler implements IElementUpdater {
    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {

        // perform login here ...

        IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
        ISourceProviderService service = (ISourceProviderService) window.getService(ISourceProviderService.class);
        SessionSourceProvider sessionSourceProvider = (SessionSourceProvider) service.getSourceProvider(SessionSourceProvider.SESSION_STATE);

        // update the source provider
        sessionSourceProvider.setLoggedIn(true);

        return null;
    }

    @Override
    public void updateElement(UIElement element, Map parameters) {
        element.setText("Login");
    }

}
The LogoutHandler also will have a similar code. Remember its not a mandatory thing to have multiple handlers to update the command dynamically. You can do it even with single handler as well.
One last piece, the Command Framework will call the updateElement() method only when the value of the variables in the *when expression is changed. So in other places where you want to update a command when no variable change has occurred, you need to use the ICommandService:
ICommandService commandService = (ICommandService.class)serviceLocator.getService(ICommandService.class);
commandService.refreshElements(commandId, null);

See also:

Part 1: Actions Vs Commands
Part 2: Selection and Enablement of Handlers
Part 3: Parameters for Commands
Part 4: Misc items ...
Part 6: 'toggle' & 'radio' style menu contribution

Feb 18, 2009

Customizing the About Dialog

In the About Dialog, the image, text etc, can be customized by the extension point org.eclipse.core.runtime.products (or PDE's product editor). But with few changes into the nightly build of 3.5, the About Dialog sports a new look and is much more customizable. In this tip, lets see how to extend it.

The new Eclipse About Dialog (for the RCP mail sample) looks like this:
image


If you click the "Installation Details" button, you will get this Dialog:
image

How about adding our own tab here? You need to extend the new org.eclipse.ui.installationPages extension point.
<extension
      point="org.eclipse.ui.installationPages">
   <page
         class="com.eclipse_tips.rcp.mail.MailInstallationpage"
         id="com.eclipse-tips.rcp.mail.Installationpage"
         name="RCP Mail">
   </page>
</extension>

The class should extend org.eclipse.ui.about.InstallationPage, which has the createControl() method. Create all the UI you want there:
image
If you see the Plug-ins tab or Configuration tab, there are few buttons. How to add a new button in our RCP Mail Tab? I was looking for a createButtons() method to override, but its not that way. The buttons are contributed thru Command Framework:

<extension
      point="org.eclipse.ui.commands">
   <command
         defaultHandler="com.eclipse_tips.rcp.mail.ShowRegistrationHandler"
         id="com.eclipse-tips.rcp.mail.showRegistrationCommand"
         name="Registration Details">
   </command>
</extension>
<extension
      point="org.eclipse.ui.menus">
   <menuContribution
         locationURI="toolbar:org.eclipse.ui.installationDialog.buttonbar">
      <command
            commandId="com.eclipse-tips.rcp.mail.showRegistrationCommand"
            style="push">
         <visibleWhen>
            <with
                  variable="org.eclipse.ui.installationPage.activePage.id">
               <equals
                     value="com.eclipse-tips.rcp.mail.InstallationPage">
               </equals>
            </with>
         </visibleWhen>
      </command>
   </menuContribution>
</extension>
If you don't understand the above extension, you need to refer to my earlier tips on Command Framework :-P
Result:
image

Why can't it be as simple as extending a createButtons() method? Well, flexibility for other plugins to extend. Say if we want to add a button to the existing Plug-ins tab, all we have to do is add a menuContribution:

<extension
      point="org.eclipse.ui.menus">
   <menuContribution
         locationURI="toolbar:org.eclipse.ui.installationDialog.buttonbar">
      <command
            commandId="com.eclipse-tips.rcp.mail.showRegistrationCommand"
            style="push">
         <visibleWhen>
            <with
                  variable="org.eclipse.ui.installationPage.activePage.id">
               <equals
                     value="30.PluginPage">
               </equals>
            </with>
         </visibleWhen>
      </command>
   </menuContribution>
</extension>

See. Extending it is now simple!
image

The id of the Plug-ins tab is "30.PluginPage" and the id of the Configuration tab is "31.SystemPage". Did you notice something odd there? The ids are prefixed with some numbers. These numbers decide the order of the tabs appearing in the dialog. This is not a documented behaviour, so don't expect to work the same in future versions, but for now it works. So if we prefix our ids with a lower number like "10.com.eclipse-tips.rcp.mail.InstallationPage", our tab will be shown first:
image 

The Configuration lists out all the configuration details, so if you want to add your own configuration to it, you need to extend org.eclipse.ui.systemSummarySections:
<extension
      point="org.eclipse.ui.systemSummarySections">
   <section
         class="com.eclipse_tips.rcp.mail.MailSummarySection"
         id="com.eclipse_tips.rcp.mail.mailSummarySection"
         sectionTitle="RCP Mail Details">
   </section>
</extension>

The class should implement org.eclipse.ui.about.ISystemSummarySection, which has a single method write(PrintWriter writer). You can add all the configuration details to the writer:
public class MailSummarySection implements ISystemSummarySection {
    @Override
    public void write(PrintWriter writer) {
        writer.println("User Name=Prakash G.R.");
        writer.println("Mail Server=GMail");
        writer.println("Protocol=POP3");
    }
}
image
This has been there for a while, thought I'll add it for completeness :-)


Update [24-Feb-2009]: In the recent nightly, the Command Contribution story has been completely removed and createButtons() method have been added. Now the framework is not flexible enough, so you can't contribute to existing pages, but the code gets much simpler now. Trade offs :-)

Feb 12, 2009

Using progress bars ...

In the last tip, I said the top most mistake done by Eclipse plug-in developers is running long running operations in the UI thread. Assuming that you are running it in a non-UI thread, how to show the progress of the execution? Obviously thru progress monitors. But how many different ways are there to show a progress monitor? Lets see them in this tip.
The first option is ProgressMonitorDialog. You have to create a IRunnableWithProgress and use the run method:
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
dialog.run(true, true, new IRunnableWithProgress(){
    public void run(IProgressMonitor monitor) {
        monitor.beginTask("Some nice progress message here ...", 100);
        // execute the task ...
        monitor.done();
    }
});
Result:
 ProgressMonitorDialog
As you can see, the dialog is kind-of blocking the user. This dialog is advisable only in the rare cases where the user have to wait till the operation is completed. In most other cases, you should prefer running a Job. A Job is not blocking to the user and can still show the progress. The progress is available in the Progress View.

Job job = new Job("My new job") {
    @Override
    protected IStatus run(IProgressMonitor monitor) {
        monitor.beginTask("Some nice progress message here ...", 100);
        // execute the task ...
        monitor.done();
        return Status.OK_STATUS;
    }
};
job.schedule();

Result:
 Job in Progress View

If you make the job as a user job by calling setUser(true), the progress dialog will be opened, where the user can chose to run the job as a background job. If the user doesn't want to see this dialog again, he can select to 'Always run in background':



When the job is initiated by the user interacting with a workbench part (like clicking a button in a view), a better way to schedule the job is thru the site's IWorkbencSiteProgressService.schedule. When the job begins to execute, the workbench part can show it visually. The default behaviour is to italize the part name:
WorkbenchPart.showBusy
But you can customize it by overriding the showBusy() method in your WorkbenchPart:
public void showBusy(boolean busy) {
    super.showBusy(busy);
    if(busy)
        setPartName("I'm doing a job right now...");
    else
        setPartName("Sample View");
}
Result:
WorkbenchPart.showBusy

In case your action doesn't have any WorkbenchPart associated with it, you can use the IWorkbenchWindow.run(...) to show the progress:

IWorkbenchWindow.run

If you are running a long running operation in a wizard/wizardPage you should consider running it thru getContainer().run(). This will show the progressBar right there in the wizard dialog itself:

progressbar in wizard

If you are updating the UI elements in the wizardPage during the execution, you have to note that if you do a setEnabled() on any widget, it won't reflect. Its because the container registers the enabled state of the widgets before execution; disables the widgets; executes the task and restores the widget's enabled state to the saved value. So if you have changed the state during the operation, it will be overwritten by the container.

In case, you can't display a progressbar, you should at least use BusyIndicator.showWhile() and display the busy cursor to show that some operation is being executed. Else the user might be wondering why the UI is frozen.