<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hexapixel &#187; JFace</title>
	<atom:link href="http://hexapixel.com/tag/jface/feed" rel="self" type="application/rss+xml" />
	<link>http://hexapixel.com</link>
	<description>Programming, Eclipse, SWT and everything inbetween</description>
	<lastBuildDate>Tue, 06 Sep 2011 13:21:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>The Secondary ID</title>
		<link>http://hexapixel.com/2009/06/16/the-secondary-id</link>
		<comments>http://hexapixel.com/2009/06/16/the-secondary-id#comments</comments>
		<pubDate>Tue, 16 Jun 2009 13:36:25 +0000</pubDate>
		<dc:creator>Emil</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Eclipse Articles]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JFace]]></category>

		<guid isPermaLink="false">http://hexapixel.com/?p=739</guid>
		<description><![CDATA[In many RCP applications your views (ViewParts) will not be singletons. Perhaps you have a tree or project view which is probably a &#8220;show only once&#8221; view, but for others it&#8217;s more likely you have them flagged in the plugin xml to say allowMultiple="true" in the &#60;view /&#62; tag. For multiple views sharing the same [...]]]></description>
			<content:encoded><![CDATA[<p>In many RCP applications your views (ViewParts) will not be singletons. Perhaps you have a tree or project view which is probably a &#8220;show only once&#8221; view, but for others it&#8217;s more likely you have them flagged in the <code>plugin xml</code> to say <code>allowMultiple="true"</code> in the <code>&lt;view /&gt;</code> tag. For multiple views sharing the same primary ID you are probably already aware that you can (and have to) set a secondary id on them to make them unique. This secondary id will stay with the view as long as that view is open (even if you restart your application as the secondary id is saved in the Eclipse metadata and then re-set when your RCP application starts up again &#8211; assuming the view is set to be restorable). </p>
<p>But there&#8217;s some things that can be a bit frustrating, which is the point of writing this article. First, as your view has to be defined in the <code>plugin.xml</code> and [should you want to] Eclipse/RCP has currently no way of hiding views in &#8220;Show View&#8221; (see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=249451">Bug 249451</a> for details and possible workaround to hiding views from &#8220;show view&#8221;). Any view opened with Show View won&#8217;t have a secondary id. </p>
<p>Second, you may want to control what that secondary id looks like, as you may want to use it as an &#8220;ID&#8221; for saving custom view-specific settings (for example, grid-specific data such as column widths, column orders etc). </p>
<p>Third, you want a central place where the creation of those multi-views are handled where you know that the ID set on them will be of the format you defined. </p>
<p>And lastly, you probably want some of them to be automatically opened in your &#8220;default&#8221; perspective with proper secondary ids. So let&#8217;s get to it and see how we can make all this work for us with the goal of us not having to think about it any more once we&#8217;ve created the necessary code.</p>
<p><span id="more-739"></span><br />
<h2><b>The ActionNewView Action</b></h2>
<p>As we will continuously reference &#8220;the place&#8221; where the secondary id is set on the view, lets start with the &#8220;view creator&#8221;. This could be considered a Factory, but as it&#8217;s kind of nice to tie it in with <code>Actions</code> lets make this factory an Action which also allows us to use it in menus, toolbars, etc.</p>
<p>The action will take the [primary] ID of the view that should be opened as a parameter in the constructor (the same ID you specify in <code>plugin.xml</code>) and in the <code>run()</code> method it will create the view with a secondary id of our choice. This is all quite easy and we don&#8217;t have to write much code to accomplish it, in fact, you&#8217;ve undoubtedly done something like this already. In this article we will use a <a href="http://en.wikipedia.org/wiki/UUID" target="_new">UUID</a> as our secondary ID as it&#8217;s unique and the structure of it is good as it&#8217;s a long string without strange characters (except the &#8216;-&#8217; character) and it&#8217;s more or less guaranteed to be unique. You may of course use whatever you prefer as a unique ID.</p>
<p>Our action class will look like this:</p>
<pre class="java" name="code">
<pre class="syntax-highlight:java">
public class ActionNewView extends Action {

    private String _viewIdToOpen = null;

    public ActionNewView(String viewIdToOpen) {
        _viewIdToOpen = viewIdToOpen;
    }

    @Override
    public void run() {
        try {
            // this will become the secondary ID used in the view
            String secondaryId = UUID.randomUUID().toString();

            IWorkbenchWindow window = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow();
            if (window != null) {
                IWorkbenchPage page = window.getActivePage();
                if (page != null) {
                    // these two lines open (create) and focus on the view
                    page.showView(_viewIdToOpen, secondaryId, IWorkbenchPage.VIEW_CREATE);
                    IViewPart justActivated = page.showView(_viewIdToOpen, secondaryId, IWorkbenchPage.VIEW_ACTIVATE);

                    // ... do something with justActivated if needed
                }
            }

        }
        catch (Exception err) {
            //TODO: deal with exception
        }
    }
}
</pre>
</pre>
<p>I don&#8217;t think it needs much explanation as it&#8217;s a pretty straight forward &#8220;view creation&#8221; call with a secondary id, as specified in the Eclipse manual etc. </p>
<h2><b>Dealing With &#8220;Show View&#8221;</b></h2>
<p>Now that we have our &#8220;view opener class&#8221; we&#8217;re ready to deal with some of the aspects mentioned in the beginning. The next stop is to get secondary id&#8217;s onto views opened via &#8220;Show View&#8221; as they don&#8217;t get one by default. If you don&#8217;t already have an abstract parent class for all of your multi views, perhaps now is the time to create one as it will make it easier, but you can of course put the same snippet of code elsewhere. </p>
<p>One method is always called upon view creation, and that&#8217;s where we want to check if the view being created has a secondary id. If it doesn&#8217;t, we want to dispose (hide) that view right away and call our ActionNewView instead and open the same view again but <b>with</b> a secondary id. The method we check in is the <code>createPartControl(Composite parent)</code> method which is an implementation of the <a href="http://help.eclipse.org/ganymede/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/IWorkbenchPart.html#createPartControl(org.eclipse.swt.widgets.Composite)" target="_new">IWorkbenchPart</a> interface. Here&#8217;s what our code will look like:</p>
<pre class="java" name="code">
<pre class="syntax-highlight:java">
@Override
public void createPartControl(final Composite parent) {
    try {
        // get the secondary id that the view was created with
        String secondaryId = getViewSite().getSecondaryId();

        // If the secondary id was null that means that Eclipse opened the view, and not us. That&#039;s bad because it
        // creates a view without a secondary ID and causes the view to be &quot;different&quot; from one that we opened ourselves.
        // Thus, if we see a view opened without an ID, we quickly close it and tell the &quot;open new action&quot; to open
        // the same view right away. The result may be a very slight flicker as the old view comes to existance and is
        // destroyed right away, but it&#039;s mostly not noticeable by the end user.
        if (secondaryId == null) {
            // we need to do it asynchronously as we can&#039;t close the view until the create code has finished
            Display.getDefault().asyncExec(new Runnable() {
                @Override
                public void run() {
                    // destroy ourselves
                    getViewSite().getPage().hideView(ThisAbstractClass.this);
                    // open the same view our way
                    ActionNewView anv = new ActionNewView(getViewSite().getId());
                    anv.run();
                }
            });

            // return now as we&#039;re done with the non-secondary-id view
            return;
        }

        // do normal view creation stuff here...
    }
    catch (Exception err) {
        //TODO: deal with exception
    }
}
</pre>
</pre>
<p><code>ThisAbstractClass</code> is of course whatever class you put this code in, but most likely it&#8217;s your abstract multi-view parent class.</p>
<p>So, as the comment states, when a view is created and it doesn&#8217;t have a secondary id, that view is discarded as soon as it finished being created and the same view is opened again but this time via our action, which in turn ensures it gets a secondary id to our standards. </p>
<h2><b>Dealing With Perspectives</b></h2>
<p>We&#8217;re almost done, but there&#8217;s one more place where views may get secondary id&#8217;s that aren&#8217;t what we want, and that&#8217;s the views that are opened when the <code>Perspective</code> is new or reset. In our <code>DefaultPerspective</code> class (or whatever perspective class you want) we define the layout in the <code>createInitialLayout(IPageLayout layout)</code> and we also set whatever views are open at the start and where non-opened views go (placeholders). In here we need to change a few things so that whatever views are opened from the start get opened with a secondary id like above.</p>
<p>The API documentation for <a href="http://help.eclipse.org/ganymede/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/IPageLayout.html" target="_new">IPageLayout</a> states:</p>
<p><i>In some cases, multiple instances of a particular view may need to be added to the same layout. These are disambiguated using a secondary id. In layout methods taking a view id, the id can have the compound form: primaryId [':' secondaryId]. If a secondary id is given, the view must allow multiple instances by having specified <code>allowMultiple="true"</code> in its extension. View placeholders may also have a secondary id.</i></p>
<p>So we can either create the secondary id on the fly and call <code>layout.showView("primaryId:secondaryId")</code> or we can just add placeholders and asynchronously call our Action to create the views. It&#8217;s really up to you how you want to do it, if your ID generator is a simple static call, you may just want to put the secondary ID&#8217;s in there and be done. But for the sake of the article, lets have everything go through our action. </p>
<p>Presume we have a perspective layout of 1 folder on the left, and 3 folders on the right, each taking up 33% of the space vertically. Something like this:</p>
<pre>
+-----------+--------+
|           |folder 1|
|           +--------+
| folder 0  |folder 2|
|           +--------+
|           |folder 3|
+-----------+--------+
</pre>
<p>The &#8220;folder 0&#8243; will get a non-multi view, and folder 1,2,3 will get multi-views, 1 each for this example. We will tell the folder 1,2,3 that they contain view placeholders, and folder 0 will get a view right away. Our code will look like this:</p>
<pre class="java" name="code">
<pre class="syntax-highlight:java">
public class DefaultPerspective implements IPerspectiveFactory {

    // Marker for saying &quot;any id following the primary id&quot; (which is the secondary id)
    private static final String MULTI_VIEW = &quot;:*&quot;;

    @Override
    public void createInitialLayout(IPageLayout layout) {
        String editorArea = layout.getEditorArea();
        layout.setEditorAreaVisible(false);

        // list of ID&#039;s that will be created at &quot;reset perspective&quot; / first startup
        final String[] ids = new String[] { ViewForFolder1.ID, ViewForFolder2.ID, ViewForFolder3.ID };

        layout.addShowViewShortcut(OurWorkspaceView.ID);
        layout.addShowViewShortcut(ViewForFolder1.ID);
        layout.addShowViewShortcut(ViewForFolder2.ID);
        layout.addShowViewShortcut(ViewForFolder3.ID);

        // left side
        IFolderLayout workspace = layout.createFolder(&quot;Folder0&quot;, IPageLayout.LEFT, 0.2f, editorArea);
        workspace.addView(OurWorkspaceView.ID);

        // right side
        IFolderLayout f1 = layout.createFolder(&quot;Folder1&quot;, IPageLayout.RIGHT, 0.25f, editorArea);
        f1.addPlaceholder(ViewForFolder1.ID + MULTI_VIEW);

        IFolderLayout f2 = layout.createFolder(&quot;Folder2&quot;, IPageLayout.BOTTOM, 0.33f, &quot;Folder1&quot;);
        f2.addPlaceholder(ViewForFolder2.ID + MULTI_VIEW);

        IFolderLayout f3 = layout.createFolder(&quot;Folder3&quot;, IPageLayout.BOTTOM, 0.5f, &quot;Folder2&quot;);
        f3.addPlaceholder(ViewForFolder3.ID + MULTI_VIEW);

        // create all views asynchronously as they need to be created after the folders etc
        // have been laid-out. This ensures they have a secondary id according to our standards.
        Display.getDefault().asyncExec(new Runnable() {

            @Override
            public void run() {
                for (String id : ids) {
                    ActionNewView anv = new ActionNewView(id);
                    anv.run();
                }
            }

        });

        // rest of your code...
    }
}
</pre>
</pre>
<p>So when the Perspective is opened for the first time (or reset) we create the layout, set multi-view placeholders and then asynchronously call our action to create the views. As we told them where to go, they will show up in each respective folder in the order specified by the string array. As mentioned previously you can of course call <code>addView</code> directly with a secondary id, but I&#8217;m showing the &#8220;route it through our ActionNewView class&#8221; way here.</p>
<h2><b>Done!</b></h2>
<p>This concludes the article on harnessing the Secondary ID in your RCP (or Eclipse) applications. This is by no means the only way to do it as everyone seem to find their own way of doing similar things. This is simply &#8220;one way&#8221;, but the above way works well. Hopefully the article gave you an insight into how the Secondary ID is used in a multi-view environment and the places you may need to &#8220;catch it&#8221; as views can be created from the Eclipse framework without your direct interaction.</p>
]]></content:encoded>
			<wfw:commentRss>http://hexapixel.com/2009/06/16/the-secondary-id/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>MenuManagers and You</title>
		<link>http://hexapixel.com/2009/05/22/menumanagers-and-you</link>
		<comments>http://hexapixel.com/2009/05/22/menumanagers-and-you#comments</comments>
		<pubDate>Fri, 22 May 2009 10:23:13 +0000</pubDate>
		<dc:creator>Emil</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Eclipse Articles]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[JFace]]></category>
		<category><![CDATA[SWT]]></category>

		<guid isPermaLink="false">http://hexapixel.com/?p=689</guid>
		<description><![CDATA[If you&#8217;re using Eclipse RCP (or even standalone SWT with JFace) you are most likely using MenuManagers in various places, for popup menus, toolbar menus, etc. You might be happily using them without much of a thought or care of where they end up after they have been shown or how their internal workings actually [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re using Eclipse RCP (or even standalone SWT with JFace) you are most likely using MenuManagers in various places, for popup menus, toolbar menus, etc. You might be happily using them without much of a thought or care of where they end up after they have been shown or how their internal workings actually &#8220;work&#8221;. Danger lies down that happy path. </p>
<p>You probably never paid much attention to the disposal of widgets except that &#8220;master widget&#8221; you call <code>dispose()</code> on (usually a shell).. and just because of this, it&#8217;s time to dig into the &#8220;why&#8221;, &#8220;what&#8221; and &#8220;no kidding&#8221; of MenuManagers as there are undoubtedly a few of the &#8220;no kidding&#8221; unless you are already fully familiar with them.</p>
<p><span id="more-689"></span>If you look at the MenuManager API, you&#8217;ll see an often overlooked <a href="http://help.eclipse.org/ganymede/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/action/MenuManager.html#dispose()" target="_new">dispose()</a> method. MenuManagers need disposal?! Yep, they sure do. Here&#8217;s a seemingly harmless sample snippet. We create a Shell, a Toolbar, on which we create a MenuManager, and then we dispose the toolbar. You&#8217;d think that the MenuManager would get disposed also wouldn&#8217;t you? It doesn&#8217;t. Where is it? In memory.</p>
<pre>
<pre class="syntax-highlight:java">
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;

public class MenuManagerTest1 {

    public MenuManagerTest1() {
        Display display = new Display();
        Shell shell = new Shell(display, SWT.SHELL_TRIM);
        shell.setLayout(new FillLayout());

        ToolBarManager tbm = new ToolBarManager(SWT.FLAT | SWT.RIGHT);
        tbm.add(new OneAction());
        ToolBar tb = tbm.createControl(shell);

        MenuManager mm = new MenuManager(&quot;Test Menu&quot;);
        mm.add(new OneAction());
        tbm.setContextMenuManager(mm);

        // dispose shell, this will dispose all sub-widgets as well
        shell.dispose();

        // check status of our stuff
        System.out.println(&quot;Toolbar is disposed? - &quot; + tb.isDisposed());
        System.out.println(&quot;Menu is disposed? - &quot; + mm.getMenu().isDisposed());
        System.out.println(&quot;ToolbarManager contains what? &quot; + tbm.getItems());
        System.out.println(&quot;MenuManager contains what? &quot; + mm.getItems());
    }

    class OneAction extends Action {
        public OneAction() {
            super(&quot;Test Action&quot;);
        }

        @Override
        public void run() {
            System.out.println(&quot;Action was run&quot;);
        }
    }

    public static void main(String[] args) {
        new MenuManagerTest1();
    }

}
</pre>
</pre>
<p>The printout when running this will look like;
<pre><font color="green"><b>
Toolbar is disposed? - true
Menu is disposed? - true
ToolbarManager contains what? [Lorg.eclipse.jface.action.IContributionItem;@16fe0f4
MenuManager contains what? [Lorg.eclipse.jface.action.IContributionItem;@19d0a1
</b></font></pre>
<p>Ok, so that's not the most intriguing printout ever, but it's mostly to show that the items are still there. The reason a manager doesn't get disposed should be pretty obvious: It's not a widget, it has no disposable parent (which would also have to be a widget), thus, it exists as long as you let it exist. There is of course a reference to the actual Menu inside the MenuManager, which is disposed as you can see above.</p>
<p>So why aren't MenuManagers auto-disposed in some other fashion, like when the menu is disposed? For good reason. You can create them without a parent widget which means you can keep them around and re-use them like a Factory and because of this, there is no auto-dispose when the menu is hidden. It's actually to make life easier for you even if it sometimes doesn't feel that way.</p>
<h2><b>Disposing MenuManagers</b></h2>
<p>There's two ways you can go about dealing with disposing your MenuManagers. Here's the first one (which might be obvious);</p>
<p>Assume you have a few MenuManagers in your ViewParts or EditParts. If you are creating them inside methods, you will want to refactor them out and create them only once for your class. They should be accessible and re-used throughout the life of the ViewPart and disposed when the ViewPart is disposed. This is very important! If you do not dispose it, it will not be gone, and you will most likely end up with a memory leak (as the above snippet showed). Here's a typical ViewPart dispose() override:</p>
<pre>
<pre class="syntax-highlight:java">
@Override
public void dispose() {
        try {
            if (_toolbarMenu != null) {
                _toolbarMenu.dispose();
                _toolbarMenu = null;
            }

        }
        catch (Exception err) {
            // do something with exception
        }

	    // remember to keep it going!
        super.dispose();
}
</pre>
</pre>
<p>The second option is for the "show once" menus that you may have. How do you dispose those? Ideally the same as #1 but if you really have to dispose them differently, the easiest way to do it is to "auto dispose" them once the user has seen the menu and closed it or selected something from it. You will most likely create your <code>Menu</code> object from a call to <code>menuManager.createContextMenu(...)</code>, so after this when you have the Menu object available, you do something like this;</p>
<pre>
<pre class="syntax-highlight:java">
final MenuManager mm = new MenuManager(&quot;Menu&quot;);

// ... various manager-related code here

// create menu object on widget
Menu menu = mm.createContextMenu(parentWidget);

// add a listener that disposes the MenuManager once user has seen the menu
menu.addMenuListener(new MenuListener() {

	 @Override
	 public void menuHidden(MenuEvent e) {
	     // dispose asynchronously or it&#039;ll dispose too fast and menu item clicked won&#039;t be run
	     Display.getDefault().asyncExec(new Runnable() {

		 @Override
		 public void run() {
		     mm.dispose();
		 }

	     });
	 }

	 @Override
	 public void menuShown(MenuEvent e) {
	 }

});
</pre>
</pre>
<p>It's not the prettiest solution, but it works. Ok, so the disposal is covered now, no more leaks. Yay for us!</p>
<p>There is one more thing to bring up that you may/may not encounter, but if you do, it would probably be a head-scratcher. </p>
<h2><b>Dynamic Menu Items</b></h2>
<p>Here's a scenario that happened to me and at first seemed to be a bug:</p>
<p>We have a lot of tables in our application. We also have a section where users can create their own custom filters. These filters show up in our menus when you right click a table or open a menu on the toolbar. When a filter is in use, the corresponding menu item for that filter is checked. Each filter is wrapped in an IAction that overrides <code>equals()</code> and <code>hashCode()</code> that both check to see if the wrapped Filter object is the same. Thus, any action using the same filter object will return true in the <code>equals()</code> check. </p>
<p>We have an <a href="http://help.eclipse.org/ganymede/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/action/IMenuListener.html" target="_new">IMenuListener</a> on the menu, so whenever the user opens the menu, just as it's being shown, we remove all old menu items in the "Filters" menu and re-create them (as filters may have changed by the user without our knowledge). We then "check" (checkbox) them according to what filters are active in the table. All this works fine, and here's where the issue arose;</p>
<p>We also have a MenuManager on our toolbar (ToolbarManager) associated with the table. This toolbar menu shows the exact same filter menu when popped up, through the same methods. The issue is easiest described through this chain of events...</p>
<ol>
<li>User opens right click filter menu, selects a filter, item is checked, filter is applied to table.</li>
<li>User looks at toolbar menu, sees filter checked (do note this is the first time the toolbar menu was opened). Closes menu without selecting anything.</li>
<li>User opens right click filter menu again, selects same filter as before (the now checked one). Item is no longer checked, filter is removed from table.</li>
<li>User opens toolbar menu again, <b>sees the recently cleared filter still checked</b>(!). At this point it will always stay checked. Had we looked at the menu when stuff was unchecked, it would forever be unchecked.</li>
</ol>
<p>I debugged this for a long time until I to my horror realized that despite me calling <code>removeAll()</code> and re-creating all MenuManager items in the "Filters" menu on each popup, internally, in the Menu widget itself, the <code>removeAll()</code> on the MenuManager removed nothing on the Menu widget. All MenuItems were still there! Hmm, what was going on? what was I missing? Why didn't <code>removeAll()</code> remove all MenuItems as well? </p>
<p>I debugged some more and noticed some code inside the MenuManager source code that looks like this:</p>
<pre>
<pre class="syntax-highlight:java">
for (int i = 0; i &lt; mi.length; i++) {
    Object data = mi[i].getData();

    if (data == null || !clean.contains(data)) {
	mi[i].dispose();
    } else if (data instanceof IContributionItem
	    &amp;amp;&amp;amp; ((IContributionItem) data).isDynamic()
	    &amp;amp;&amp;amp; ((IContributionItem) data).isDirty()) {
	mi[i].dispose();
    }
}
</pre>
</pre>
<p>This loop first of all removes all items that are not the same as before (that are in the <code>clean</code> array), that's good. But as I checked what got disposed, our filter items were never removed... as they are the same as before! Aha! So the second part of the if-statement checks to see if the item is Dirty or Dynamic. This was the first I had heard of Dynamic menu items and it felt like I had read the API through and through many times. The API for <code>isDynamic()</code> says:</p>
<p><i>Returns whether this contribution item is dynamic. A dynamic contribution item contributes items conditionally, dependent on some internal state.</i></p>
<p>Cryptic to say the least, and easily overlooked as it's very non-descriptive, but with the above looping code and how we deal with these special actions - it kind of fits. We depend on the items having checkmarks which depend on an internal state (which is; if the table filter is active or not). The MenuManager can't figure that out by itself of course, so we need to help it. The solution to this problem is obvious at this point. If <code>isDynamic()</code> returns true it will be disposed for us, so we need to implement that and return <code>true</code>.</p>
<p>In our code more or less everything is an IAction, for our FilterAction we create a DynamicFilterAction class that extends <code>ActionContributionItem</code> and then we override <code>isDynamic()</code> and return <code>true</code>. </p>
<p>This ensures that there is no "old" items in the menu (as now our Dynamic menu items get disposed) when we create the new one, and as such, the "checkbox issue" goes away and everything works as intended. The final code looks something like this;</p>
<pre>
<pre class="syntax-highlight:java">
class DynamicFilterAction extends ActionContributionItem {

        private FilterAction _action;

        public DynamicFilterAction(DataFilter df) {
            super(new FilterAction(df));
            _action = (FilterAction)super.getAction();
        }

        public void setChecked(boolean checked) {
            _action.setChecked(checked);
        }

        @Override
        public boolean isDynamic() {
            return true;
        }
}
</pre>
</pre>
<h2><b>Final Words</b></h2>
<p>Hopefully this gives you a better insight into the rather simple but tricky world of MenuManagers and how they work. Taking good care of them will ensure that you at least don't have to worry about them sticking around in memory or doing things you didn't expect.</p>
<p>Happy menu managing!</p>
]]></content:encoded>
			<wfw:commentRss>http://hexapixel.com/2009/05/22/menumanagers-and-you/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>RCP Workspaces</title>
		<link>http://hexapixel.com/2009/01/12/rcp-workspaces</link>
		<comments>http://hexapixel.com/2009/01/12/rcp-workspaces#comments</comments>
		<pubDate>Mon, 12 Jan 2009 20:37:42 +0000</pubDate>
		<dc:creator>Emil</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Eclipse Articles]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[JFace]]></category>

		<guid isPermaLink="false">http://hexapixel.com/?p=483</guid>
		<description><![CDATA[An &#8220;Eclipse workspace&#8221; is basically a directory where all your metadata preference files are stored (Eclipse specific files, there&#8217;s a lot of them). It&#8217;s also where your projects are stored, your source files, jars, and so on. It&#8217;s useful to have all of this one one place, and Eclipse itself requires it or your workspace [...]]]></description>
			<content:encoded><![CDATA[<p>An &#8220;Eclipse workspace&#8221; is basically a directory where all your metadata preference files are stored (Eclipse specific files, there&#8217;s a lot of them). It&#8217;s also where your projects are stored, your source files, jars, and so on. It&#8217;s useful to have all of this one one place, and Eclipse itself requires it or your workspace probably won&#8217;t load. As it&#8217;s such a useful feature, I know a lot of people have tried to implement the existing &#8220;Switch Workspace&#8221; and the rest of the &#8220;Workspace&#8221; logic into their RCP applications, but I have yet to see many successes. The issue is that it&#8217;s most likely a feature you will want to customize (and in some aspects, you have to, as the &#8220;Workspace&#8221; implementation in Eclipse is not that open), and that&#8217;s where it gets tricky and possibly messy.</p>
<p>In our case, we wanted the normal Eclipse workspace logic so that users could create multiple &#8220;RCP Workspaces&#8221; and load whichever they wanted at startup, but we also wanted all of our custom RCP application specific data in the same directory (along with any other files we felt like creating), and we wanted to customize the dialog where the user picks a workspace. In the end, as you have probably guessed by now, we used nearly none of the default Eclipse workspace implementation, but managed to get RCP to believe that we were, and we got all the features we required in there as well.</p>
<p>This article will explain how we went about doing this, and will show you (with full source code of course) how you can implement exactly the same thing. And it&#8217;s much easier than it may sound.</p>
<p><span id="more-483"></span></p>
<h2><strong>The Magic Parameter</strong></h2>
<p>Everything starts with one little command line parameter that tells Eclipse we will be in charge of specifying where the workspace goes. Obviously we need to do this very early in the application or else by the time we have a UI, Eclipse has no place to put preferences. And if we do it too late, Eclipse will exit with an exception saying that it has no workspace. The &#8220;Program Argument&#8221; that makes it possible for us to define a workspace at runtime looks like this: <code>-data @noDefault</code>.</p>
<p>If you look at your &#8220;Run Configurations&#8221; in Eclipse (&#8220;Run&#8221; menu, then &#8220;Run Configurations&#8230;&#8221;) and click the &#8220;Arguments&#8221; tab, you will probably see a few cryptic entries that Eclipse has created for you, they look like this: <code>-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}</code>. By appending our @noDefault argument, we end up with this: <code>-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -data @noDefault</code>.</p>
<p>Here is a screenshot of how it would look when appended:<br />
<img title="Arguments Tab" src="http://hexapixel.com/wp-content/uploads/2009/01/args_tab.gif" alt="Arguments Tab" width="522" height="131" /></p>
<p>So what does that parameter do? It simply tells Eclipse not to use any default workspace location (or &#8220;OSGI instance area&#8221; as it&#8217;s called in the API) when it starts up and expects us to provide it instead. Here&#8217;s an API link to the document explaining the different <a href="http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/misc/runtime-options.html" target="_new">Eclipse runtime options</a> you can set (including the ones mentioned here).</p>
<h4><strong>Telling Eclipse The Location Manually</strong></h4>
<p>So, where and how do we tell Eclipse that we have a &#8220;workspace home&#8221; that we want it to use? As I mentioned before, we need to do it early. That means we need to do it in <code>Application.java</code> and more specifically in the <code>public Object start(IApplicationContext context) throws Exception {</code> method. By default this method will mostly be empty except for some Eclipse specific code (undoubtedly generated by Eclipse when you created the RCP project), but we&#8217;ll soon change that. Eclipse will expect us to set the necessary location by modifying the &#8220;InstanceLocation&#8221; on the Platform. We can get the <code>Location</code> by doing a one-line call like this: <code>Location instanceLoc = Platform.getInstanceLocation();</code>. Assuming we already have a specific workspace location in mind, we could do the following:</p>
<pre>
<pre class="syntax-highlight:java">
try {
	// fetch the Location that we will be modifying
	Location instanceLoc = Platform.getInstanceLocation();

	// set location to c:\temp
	instanceLoc.set(new URL(&quot;file&quot;, null, &quot;c:\\temp&quot;), false);
}
catch (Exception err) {
	...
}
</pre>
</pre>
<p>When we create the URL we tell it that the protocol to use is a file. We also tell it that the host is null and that the file in question is <code>c:\temp</code> (which is actually a directory of course). The last <code>false</code> that we pass to the set method is whether we want to lock the workspace location (which we don&#8217;t).</p>
<p>We have now satisfied Eclipse&#8217;s needs for custom-defining a workspace, and when you start your product or RCP application, you should see that Eclipse has created a <code>.metadata</code> directory underneath it. But as we hardcoded the path to <code>c:\temp</code>, this doesn&#8217;t let us &#8220;customize&#8221; it much does it? What about &#8220;Switch Workspace&#8221; functionality and asking the user what workspace they would like to pick? (or create)</p>
<h2><strong>Asking The User</strong></h2>
<p>In our case, we ask users at startup what workspace we should use (Just like Eclipse does). We do various checks to see if the directory they pick is already a workspace, if it&#8217;s writable/readable, and so on. If everything is OK, we return the selected directory to the previous code exmple and put it where we used <code>c:\temp</code> before.</p>
<p>To make it easy, you could re-use code from the &#8220;Select workspace dialog&#8221; from Eclipse, but we want ours custom, so I&#8217;ll explain how that&#8217;s done. </p>
<p>Let&#8217;s create a class called <code>PickWorkspaceDialog</code>, as we&#8217;ll re-use this for the Switch Workspace action later, we&#8217;ll make it with a constructor that takes a boolean that defines whether it&#8217;s the normal &#8220;startup pick workspace&#8221; dialog or if it&#8217;s the &#8220;switch workspace&#8221; dialog. As Eclipse already has a pretty nice dialog that we can re-use that lets us put an image and a message at the top, we&#8217;ll be extending <code>TitleAreaDialog</code>.</p>
<p>While we&#8217;re at it, lets create features for cloning a workspace and a combo that remembers our last selected ones as well.</p>
<p>As it&#8217;s a lot of code to paste into an article &#8211; and I think a lot of it is straight forward &#8211; I will simply link to the entire java class and show some selective snippets below. For starters, this class was created using layouts with the <a href="/files/layout.jar" target="_new">LatticeLayout</a> layout manager (Update: Site is down, old lik was <a href="http://www.quirk.biz/quirkdownloads/index.html" target="_new">here</a>, I&#8217;ve changed link to the direct jar download which contains javadoc and sources as well), so if you don&#8217;t want to re-code those sections, go grab it. (This is a simpler <a href="http://www.miglayout.com" target="_new">MigLayout</a> layout manager) similar to Swing&#8217;s TableLayout. Should you not wish to use either, it should be easy to change the layouts to anything you want (GridLayout for example).</p>
<p>You can download the Java file <a href="/files/posts/PickWorkspaceDialog.java">here</a> (and at the bottom of the article). I suggest you browse through it quickly before we continue as it will make it much easier to follow. Do note that this class has been optimized to &#8220;fit in one class&#8221;, as normally some of the methods found in there would undoubtedly be split up into other places. But for the making this article it was combined into one file.</p>
<h4><strong>Using Preferences</strong></h4>
<p>Normally in a RCP application we would be using an <code>IPreferenceStore</code> to save/load our preferences. But as we need to save the location of what workspace we used last &#8211; before we have access our preference store (which is saved in our not-yet-selected workspace location), we need to save/load from somewhere else. The most logical solution is to use the <a href="http://java.sun.com/j2se/1.4.2/docs/guide/lang/preferences.html" target="_new">java Preferences API</a>. By defining a preference location along the lines of;</p>
<pre>
<pre class="syntax-highlight:java">
// create/get our preferences location based on the class
private static Preferences _preferences = Preferences.userNodeForPackage(PickWorkspaceDialog.class);

// lets define the keys we will be saving
private static final String _KeyWorkspaceRootDir   = &quot;wsRootDir&quot;;
private static final String _KeyRememberWorkspace  = &quot;wsRemember&quot;;
private static final String _KeyLastUsedWorkspaces = &quot;wsLastUsedWorkspaces&quot;;
</pre>
</pre>
<p>we can now save/load those preferences as early or late as we want. Do note that any user launching the application on the same computer will be seeing the same saved preferences, so if you need a more secure or private solution this may not be ideal for you. But for 99% of us this is fine. If you do not know how the Java Preferences API works, take a quick look at the <a href="http://java.sun.com/j2se/1.4.2/docs/guide/lang/preferences.html" target="_new">API</a> or the <a href="/files/posts/PickWorkspaceDialog.java">PickWorkspaceDialog.java</a> file.</p>
<h4><strong>Identifying Our Workspace</strong></h4>
<p>When a user selects a directory, we want to check if that directory is a &#8220;Our Application&#8221; workspace directory or some other plain directory. We do this by creating an empty file when the workspace is created, so that later, if they select an existing directory, we can say if it&#8217;s a valid &#8220;Our Application&#8221; workspace directory or not. In the <code>PickWorkspaceDialog.java</code> class you will see a method named <code>checkWorkspaceDirectory</code> that deals with both checking if a directory already exists or not (to ask if the user wants to create a new workspace there), and it also deals with checking any existing directory to ensure it&#8217;s a workspace directory for our application. The filename is defined at the top of the class, just look for <code>public static final String  WS_IDENTIFIER = ".our_rcp_workspace";</code></p>
<p>You will also see code that checks to ensure the user doesn&#8217;t select a subdirectory of an existing workspace directory, as that could cause an infinite recursive directory-creating loop, which is obviously bad.</p>
<p>Running the code from within RCP will give you a dialog that looks like this (assuming you gave it a nice image to display &#8211; the wizard image used in the screenshot is part of the Eclipse platform, so you can find most of them inside the eclipse jars):</p>
<p><img title="Select Workspace Dialog" src="http://hexapixel.com/wp-content/uploads/2009/01/sel_workspace.gif" alt="Select Workspace Dialog" width="457" height="244" /></p>
<p>As we need to hook it up to actual code, showing the screenshot before we do so makes it easier when I mention things as the &#8220;remember&#8221; checkbox.</p>
<h4><strong>Hooking It Up</strong></h4>
<p>Back in <code>Application.java</code> we now want to change our previous code to use the dialog to ask the user for a workspace. We also need to check if the user selected the &#8220;remember&#8221; checkbox as then we don&#8217;t show the dialog at all (unless the previously selected workspace directory can&#8217;t be found). We also want to check that the old workspace directory is still OK in terms of reading/writing etc. All in all, we want something like this (excuse the formatting, the sourcecode formatter doesn&#8217;t like large deeply nested blocks):</p>
<pre>
<pre class="syntax-highlight:java">
public Object start(IApplicationContext context) throws Exception {
	try {
		// the old Eclipse generated code
		Display display = PlatformUI.createDisplay();
		// and so on..

		// get what the user last said about remembering the workspace location
		boolean remember = PickWorkspaceDialog.isRememberWorkspace();

		// get the last used workspace location
		String lastUsedWs = PickWorkspaceDialog.getLastSetWorkspaceDirectory();

		// if we have a &quot;remember&quot; but no last used workspace, it&#039;s not much to remember
		if (remember &amp;&amp; (lastUsedWs == null || lastUsedWs.length() == 0)) {
		    remember = false;
		}

		// check to ensure the workspace location is still OK
		if (remember) {
		    // if there&#039;s any problem whatsoever with the workspace, force a dialog which in its turn will tell them what&#039;s bad
		    String ret = PickWorkspaceDialog.checkWorkspaceDirectory(Display.getDefault().getActiveShell(), lastUsedWs, false, false);
		    if (ret != null) {
			remember = false;
		    }

		}

		// if we don&#039;t remember the workspace, show the dialog
		if (!remember) {
		    PickWorkspaceDialog pwd = new PickWorkspaceDialog(false);
		    int pick = pwd.open();

		    // if the user cancelled, we can&#039;t do anything as we need a workspace, so in this case, we tell them and exit
		    if (pick == Window.CANCEL) {
			if (pwd.getSelectedWorkspaceLocation()  == null) {
			    MessageDialog.openError(display.getActiveShell(), &quot;Error&quot;,
				    &quot;The application can not start without a workspace root and will now exit.&quot;);
			    try {
				PlatformUI.getWorkbench().close();
			    } catch (Exception err) {

			    }
			    System.exit(0);
			    return IApplication.EXIT_OK;
			}
		    }
		    else {
			// tell Eclipse what the selected location was and continue
			instanceLoc.set(new URL(&quot;file&quot;, null, pwd.getSelectedWorkspaceLocation()), false);
		    }
		}
		else {
		    // set the last used location and continue
		    instanceLoc.set(new URL(&quot;file&quot;, null, lastUsedWs), false);
		}	

		// this is the normal default code from here on out
		int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
		if (returnCode == PlatformUI.RETURN_RESTART) { return IApplication.EXIT_RESTART; }
		return IApplication.EXIT_OK;

	}
	catch (Exception err) {
		...
	}
	finally {
	    display.dispose();
	}
}
</pre>
</pre>
<p>And that&#8217;s it. We now have a fully working and modifiable &#8220;Select Workspace&#8221; dialog that tells Eclipse where to put the metadata and we can modify any of it to our hearts content. With that all out of the way, the only thing remaining is the &#8220;Switch Workspace&#8221; action.</p>
<h2><strong>Switch Workspace</strong></h2>
<p>Eclipse has a built-in Switch Workspace action that you could access from the <code>ActionFactory</code>, but as we custom implemented our workspace picker, this wouldn&#8217;t help us much. Our dialog is already set up to handle a workspace switch (pretty much all it does is show a different message after all).</p>
<p>So, lets create an Action that will be our Switch Workspace action. It will be surprisingly short, and look like this:</p>
<pre>
<pre class="syntax-highlight:java">
public class ActionSwitchWorkspace extends Action {

    private Image _titleImage;

    public ActionSwitchWorkspace(Image titleImage) {
        super(&quot;Switch Workspace&quot;);
        _titleImage = titleImage;
    }

    @Override
    public void run() {
        PickWorkspaceDialog pwd = new PickWorkspaceDialog(true, _titleImage);
        int pick = pwd.open();
        if (pick == Dialog.CANCEL)
            return;

        MessageDialog.openInformation(Display.getDefault().getActiveShell(), &quot;Switch Workspace&quot;, &quot;The client will now restart with the new workspace&quot;);

        // restart client
        PlatformUI.getWorkbench().restart();
    }
}
</pre>
</pre>
<p>As all necessary variables and workspace locations are handled in the <code>PickWorkspaceDialog</code> class we don&#8217;t need to do anything else than tell the picked that it is now a &#8220;Switch Workspace&#8221; dialog, and then restart the RCP application if the user pressed &#8220;OK&#8221;.</p>
<p>Ideally we&#8217;d add this action in our <code>ActionBarAdvisor</code> class (default name is <code>ApplicationActionBarAdvisor</code>) under the File menu somewhere.</p>
<p>The result when run will look like this:</p>
<p><img title="Switch Workspace Dialog" src="http://hexapixel.com/wp-content/uploads/2009/01/sw_workspace.gif" alt="Switch Workspace Dialog" width="457" height="244" /></p>
<h2><strong>That&#8217;s It</strong></h2>
<p>With the code mentioned in this article you now have full &#8220;workspace&#8221; functionality for your Eclipse RCP application without having to dig in to extension points or other XML-based overrides, and you have the ability to customize any of it as much as you want. As you see it doesn&#8217;t take that much code as most of the big code is methods for copying files and checking directories.</p>
<h2><strong>All Code</strong></h2>
<p>Here are download links to all code referenced in this article:</p>
<div id="bulletlist">
<ol>
<li><a href="/files/posts/PickWorkspaceDialog.java">PickWorkspaceDialog.java</a></li>
</ol>
</div>
<p>(For the <code>Application.java</code> code please copy the big block in the article as it shows all code related to that class.)</p>
]]></content:encoded>
			<wfw:commentRss>http://hexapixel.com/2009/01/12/rcp-workspaces/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Glazed Lists + SWT Tables == True</title>
		<link>http://hexapixel.com/2009/01/02/glazed-lists-swt-tables-true</link>
		<comments>http://hexapixel.com/2009/01/02/glazed-lists-swt-tables-true#comments</comments>
		<pubDate>Fri, 02 Jan 2009 18:01:19 +0000</pubDate>
		<dc:creator>Emil</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Eclipse Articles]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JFace]]></category>
		<category><![CDATA[SWT]]></category>

		<guid isPermaLink="false">http://hexapixel.com/?p=387</guid>
		<description><![CDATA[If you haven&#8217;t heard about Glazed Lists until now, it&#8217;s about time you do, because it&#8217;s probably the last tables and grid sorting/filtering API you will ever need. It will also be the last time you rip your hair out when someone asks you for a multi-sort-multi-thread-asynchronously-updated-filtered-unique-table (which happens all the time, right?). From here [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t heard about <a href="http://www.publicobject.com/glazedlists/">Glazed Lists</a> until now, it&#8217;s about time you do, because it&#8217;s probably the last tables and grid sorting/filtering API you will ever need. It will also be the last time you rip your hair out when someone asks you for a multi-sort-multi-thread-asynchronously-updated-filtered-unique-table (which happens all the time, right?). From here on out you&#8217;ll just be saying &#8220;oh, sure, give me 30 minutes&#8221; when you need to implement something along those lines. Sounds too good to be true doesn&#8217;t it? It is! So, what are Glazed Lists?</p>
<p>Glazed Lists is an API built on top of <code>java.util.List</code> which adds a notification framework and allows you to &#8220;stack&#8221; or &#8220;chain&#8221; lists together. This in and by itself may not sound so exciting. What this gives you though is the ability to take a Sorted list, stack it with a Filtered list, stack it with a Unique list, stack it with a asynchronously updated Unique list (and keep stacking), and whenever you modify the source list, it automatically tells the other lists in the chain to update so that their lists are always up to date. Last but not least, the list reports back to you and tells you to update your view with a specific list of changes. So imagine this &#8220;chained list&#8221; is the input for your TableViewer and perhaps you&#8217;re starting to see the potential.</p>
<p>I&#8217;ve been using Glazed Lists continuously for the last year, and it&#8217;s no short of astounding how powerful it is. I&#8217;ve used them on JFace TableViewers, The <a href="http://www.eclipse.org/nebula/widgets/grid/grid.php" target="_blank">Nebula Grid</a> widget, and the great rising-star <a href="http://nattable.org/drupal/" target="_blank">NatTable</a> which deserves it&#8217;s own article down the road (the only table widget I&#8217;ve found that can handle huge amounts of data without choking). On each of those widgets it was only a matter of creating a couple of smaller classes, a few lines of code, and I had the most powerful sorting and filtering API at my fingertips, ready for anything upper management could throw at me in terms of features. So often I see posts on the Eclipse Newsgroups asking about multi column sorting, and usually few concrete replies. &#8220;Glazed Lists&#8221; would be my reply.  To give an idea of what kind of sorting/filtering you can do, here&#8217;s a snapshot of  some of the available list types:</p>
<p><i>Sorted List. Filtered List. Unique List. Transformed List. Range List. Threshold List. Collection List. Freezable List. Popularity List. Separator List. Sequence List. Transaction List. Observable Lists</i>.. and the list goes on.</p>
<p>So instead of talking about how great they are in an entire post, how about some example implementations and actual code? Alright, let&#8217;s get to it!</p>
<p><span id="more-387"></span></p>
<p>To make this article &#8220;worth it&#8221; for everyone, I will cover implementing Glazed Lists on no less than 3 table/grid widgets. The standard JFace TableViewer (which is the least feature rich table component out there as it uses the SWT Table). The Nebula Grid widget (which is feature rich and very good, but has a big memory footprint on large tables) and the NatTable widget (as it will undoubtedly rise to fame soon with the next few versions (once some of the bigger bugs are ironed out)). Before you start copying and pasting code, all code is downloadable in each respective section and at the bottom of the article.</p>
<p>If you prefer to follow along or want to get a head start on downloading required jars, here are links to all the third party packages you might need:</p>
<div id="bulletlist">
<ol>
<li><a href="http://www.publicobject.com/glazedlists/glazedlists-1.7.0/" target="_new">Glazed Lists v1.7</a> (you do need this one)</li>
<li><a href="http://www.eclipse.org/nebula/widgets/grid/grid.php" target="_new">Nebula Grid (and Grid Viewer, required for the Nebula framework)</a></li>
<li><a href="http://sourceforge.net/project/showfiles.php?group_id=207809" target="_new">Nat Table v1.6.3 (grab both jars)</a></li>
<li><a href="http://logging.apache.org/log4j/1.2/download.html" target="_new">Apache Log4J</a> (Nat table needs this)</li>
<li><a href="http://commons.apache.org/downloads/download_lang.cgi" target="_new">Apache Commons Lang</a> (Nat table uses this internally for some odd reason)</li>
<li><a href="http://www.eclipse.org/downloads/" target="_new">Eclipse IDE / SWT</a></li>
</ol>
</div>
<p>Let&#8217;s start with the basics of Glazed Lists, as everything starts there.</p>
<h2><strong>Glazed Lists In a Nutshell</strong></h2>
<p>I could send you to the <a href="http://sites.google.com/site/glazedlists/documentation/tutorial" target="_new">Glazed Lists Tutorials</a> and tell you to follow those and come back, but I hate that kind of &#8220;teaching&#8221;, and the small &#8220;problem&#8221; with the tutorials is that they are all Java Swing based which is of little use to us (but by all means read them, they&#8217;re good). You might also want to check out the very good screen casts located <a href="http://publicobject.com/glazedlistsdeveloper/" target="_new">here</a> as they will give you a good idea of the different types of lists that can be used in Glazed Lists. In any case, everything in Glazed Lists starts with one thing, the root list. The root list contains all your items that you want to display before they are filtered or sorted. This list is probably in some random you-don&#8217;t-care order  which is perfectly fine. This list will serve as the input for all other chained lists. Think of it as layers, where the bottom layer is the raw list, and the higher up you go, the more refined and specific each layer is. So you have a sorting layer, a filter layer, etc. They can be active or not active, a bit like Photoshop. As we are using Glazed Lists, we need to take our root list and turn it into a Glazed Lists &#8220;EventList&#8221;, which is the Glazed Lists root-list equivalent. Here&#8217;s how that&#8217;s done:</p>
<pre>
<pre class="syntax-highlight:java">
List&lt;?&gt; rootList = .... // this comes from you
EventList&lt;?&gt; eventList = GlazedLists.eventList(rootList);
</pre>
</pre>
<p>As you can see everything uses Generics, just like normal Lists in Java 5+.</p>
<p>Any &#8220;normal&#8221; table in the UI-world will undoubtedly have Sorting and Filtering. With the code above we&#8217;re currently no different from any other plain old table implementation as we haven&#8217;t done sorting/filtering yet. So lets create the sorting/filtering layers that will be on top of the event list. We should think about order when it comes to our layers, as if we create a sorted list on top of a filtered list that&#8217;s not the same as creating a filtered list on top of a sorted list. Logically, we sort first, then apply a filter. To create our new lists we continue the code:</p>
<pre>
<pre class="syntax-highlight:java">
List&lt;?&gt; rootList = .... // this comes from you
EventList&lt;?&gt; eventList = GlazedLists.eventList(rootList);
SortedList sortedList = new SortedList(eventList, null);
FilterList(sortedList, new OurFilterMatcher());
</pre>
</pre>
<p>As you can see we keep using the last list as the input for the new list, as that&#8217;s our &#8220;chain&#8221;. The second parameter for the SortedList is the <code>Comparator</code> we want to use when sorting. I&#8217;m passing in <code>null</code> here to point out that it can be created when constructing the list (and not passing in null may actually throw an exception). Normally you don&#8217;t want the table sorted unless the user sorts it, so <code>null</code> makes sense. The <code>OurFilterMatcher</code> will be explained when we do the actual implementation, but just remember that it&#8217;s the &#8220;Matcher&#8221; that is used to filter a table (which is very much like a <code>ViewerFilter</code>).</p>
<p>There&#8217;s one more important aspect of Glazed Lists &#8211; locking. As lists can be updated on multiple threads (if you so wish) you need to tell the list when to &#8220;lock&#8221; and &#8220;unlock&#8221; so that only 1 thread is actively writing to the list at the same time. As such, it&#8217;s important we always do this when reading and writing to the list (and even if we don&#8217;t plan on multithread updates, it&#8217;s still good practice and takes little time to do). We could lock the lists when creating them even, but that&#8217;s a bit overkill, so keep en eye out for the locking code in the implementation part and in the framework code available for download. Glazed Lists even supports reading while writing, and their homepage has an example of an asynchronously updated list. Do check it out if you need advanced implementations. To give a quick example of locking/unlocking a list, here&#8217;s how it&#8217;s done:</p>
<pre>
<pre class="syntax-highlight:java">
_eventList.getReadWriteLock().writeLock().lock();
// ... modify list here ...
_eventList.getReadWriteLock().writeLock().unlock();
</pre>
</pre>
<h4><strong>The Callbacks</strong></h4>
<p>The whole idea of Glazed Lists is that when you modify the event list (and this is important: <strong>you <span style="text-decoration: underline;">always</span> modify the EventList</strong>!), it fires events to tell you what you need to change in your table implementation. Glazed has a lot of pre-built hooks for Swing, so there you don&#8217;t have to do much work, but as we use SWT we have to do pretty much all the work ourselves (great huh?). It&#8217;s not as bad as it sounds however. The callback interface that we care about here is <code>ListEventListener</code> which contains a method callback called <code>public void listChanged(ListEvent&lt;?&gt; listChanges)</code>. This list of changes <code>listChanges</code> tells us, <strong>in the correct order</strong>, what indexes and objects to update, delete and insert. It&#8217;s as easy as looping through that list, checking what the change is, and performing it. Here&#8217;s a barebones example of how it would look implemented:<a name="nutshell_code"></a></p>
<pre>
<pre class="syntax-highlight:java">
_filterList.addListEventListener(new ListEventListener&lt;?&gt;() {

	@Override
	public void listChanged(ListEvent&lt;?&gt; listChanges) {
		// get the list of changes (prior to looping, very important as it&#039;ll change as it&#039;s read)
		final List&lt;?&gt; changeList = listChanges.getSourceList();

		// go through all changes
		while (listChanges.next()) {
			// get the table index location of the change
			int sourceIndex = listChanges.getIndex();
			// get the change type
			int changeType = listChanges.getType();

			// update the table depending on the change type
			switch (changeType) {
				case ListEvent.DELETE:
					// delete row
					break;
				case ListEvent.INSERT:
					// insert row
					break;
				case ListEvent.UPDATE:
					// refresh row labels etc
					break;

			}
		}
	}

});
</pre>
</pre>
<p>That&#8217;s actually the most complex code we&#8217;ll be adding to make all of this work, and we can re-use that section of code for all our table widget implementations. </p>
<p>You might ask &#8220;why is the listener on the filter list if we were told to only modify the event list?&#8221;, which is a good and valid question. The answer is that if you were to listen on the event list instead, only base-level adds and deletes would be reported to you. As we also care about when stuff is re-ordered or moved in the list (which is what happens when users sort and filter) we want any list-changes to notify us. As our filtered list is the &#8220;topmost&#8221; or &#8220;last&#8221; list in the chain, it will get all notifications from all previous lists in the chain. Remember, all lists in the chain tell the next list down the line what changed (think of it as one-way gossip). By listening on the Filtered list we get all events, regardless on what list they happened. With that information we&#8217;re well on our way to putting Glazed into real use.</p>
<h2><strong>SWT TableViewer</strong></h2>
<p>Personally I was never a big fan of the SWT Table. A good thing about it is that it renders column headers natively, but it can be quite slow, sometimes buggy (first-column image support) and not very intuitive. It doesn&#8217;t support much customization and the second you need a table that can do a little more than a plain x/y grid, you soon hit those limitations head on. <a href="http://www.eclipse.org/articles/article.php?file=Article-CustomDrawingTableAndTreeItems/index.html" target="_new">Owner Draw</a> does help, but there&#8217;s still a lot of customization that is not possible. That said, as a &#8220;basic table&#8221; it does just fine and it&#8217;s getting better for each new SWT version. And of course, it&#8217;s native.</p>
<p>Normally when someone asks &#8220;can I sort a <code>SWT.VIRTUAL</code> table?&#8221; the answer is no or &#8220;not really&#8221;. The reason is that a virtual table only really knows what it shows in the current viewport (the visual area of the table), and how many items it has. Anything that you can&#8217;t see is not really &#8220;there&#8221;, except in memory. This obviously makes such a useful feature as <code>SWT.VIRTUAL</code> fairly useless in a sort scenario. The workaround in that case is to custom implement a sorter and replace the entire table content whenever the user sorts or filters. As we use Glazed Lists we don&#8217;t really care about this limitation, we&#8217;re working around it as we update the table with our changes whenever they occur thanks to the callback from Glazed Lists.</p>
<p>There&#8217;s a few special things we need apart from a &#8220;normal&#8221; Virtual TableViewer implementation. First, we&#8217;ll be using the <code>IStructuredContentProvider</code> for the Content provider. The <code>ILazyContentProvider</code> exists as well, but I had some odd issues with it in testing. If you want an example on how to create a virtual TableViewer, there&#8217;s a good snippet here: <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jface.snippets/Eclipse%20JFace%20Snippets/org/eclipse/jface/snippets/viewers/Snippet029VirtualTableViewer.java?revision=1.1&amp;view=markup" target="_new">Snippet029VirtualTableViewer</a>. In the <code>IStructuredContentProvider</code> we simply return the topmost layer (which is the FilterList) as follows;</p>
<pre>
<pre class="syntax-highlight:java">
class GlazedContentProvider implements IStructuredContentProvider {

	@Override
	public Object[] getElements(Object inputElement) {
		return _filterList.toArray();
	}

	@Override
	public void dispose() {
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
	}

}
</pre>
</pre>
<p>We also need to implement a Comparator which will be used by the SortedList, as well as a Matcher for the FilterList. The Comparator is a normal java Comparator whereas the Matcher is a Glazed Lists implementation. However, these are <a href="http://en.wikipedia.org/wiki/Immutable_object" target="_new">immutable</a> so they need to be new every time they are set on the respective lists. For the sake of simplicity, lets create an object called RowObject that represents one row in our table. All it does is keep track of the row number and it has a <code>getColumnText</code> method.</p>
<pre>
<pre class="syntax-highlight:java">
class RowObject {
	private int	_row;

	public RowObject(int row) {
		_row = row;
	}

	public int getRow() {
		return _row;
	}

	public String getColumnText(int col) {
		return &quot;&quot; + (_row + col);
	}
}
</pre>
</pre>
<p>With this all set up, we can now create the Comparator and Matcher. Lets start with the Comparator. As we&#8217;re basically returning an integer as display value for each cell in <code>getColumnText</code> we&#8217;ll use this as the basis for our comparison. Thus, our Comparator looks as follows;</p>
<pre>
<pre class="syntax-highlight:java">
class GlazedSortComparator implements Comparator&lt;RowObject&gt; {

	private int	_col;
	private int	_direction;

	public GlazedSortComparator(int col, int direction) {
		_col = col;
		_direction = direction;
	}

	@Override
	public int compare(RowObject o1, RowObject o2) {
		int ret = Integer.valueOf(o1.getColumnText(_col)).compareTo(Integer.valueOf(o2.getColumnText(_col)));

		if (_direction == SWT.DOWN)
			ret = -ret;

		return ret;
	}

}
</pre>
</pre>
<p>And now we create the Matcher which is used by the FilterList. The Matcher implementation in Glazed Lists asks us if a row object &#8220;matches&#8221; and not much more. This may seem confusing at first, but it&#8217;s quite similar to the <a href="http://help.eclipse.org/stable/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/viewers/ViewerFilter.html" target="_new">ViewerFilter</a>. In our code we will have a textbox and a button that represents a &#8220;search&#8221; box. When the user presses the button we set a String field called &#8220;_filterText&#8221; to whatever the user entered, and then we set a new matcher on the FilterList. As such, our code implementation looks like this:</p>
<pre>
<pre class="syntax-highlight:java">
class GlazedMatcher implements Matcher&lt;RowObject&gt; {
	@Override
	public boolean matches(RowObject row) {
		for (int i = 0; i &lt; _table.getColumnCount(); i++) {
			if (row.getColumnText(i).indexOf(_filterText) &gt; -1)
				return true;
		}

		return false;
	}
}
</pre>
</pre>
<p>Now we can add two methods that actually do the updating when we filter and when we sort. Like this:</p>
<pre>
<pre class="syntax-highlight:java">
// update the table filter
private void updateFilter() {
	// if the search text is blank, remove the matcher
	if (_filterText == null || _filterText.length() == 0) {
		_filterList.setMatcher(null);
	}
	else {
		_filterList.setMatcher(new GlazedMatcher());
	}
}

// sorts a table on the given column
private void sortColumn(int col) {
	// do some normal UP/DOWN checking and updating
	int dir = SWT.UP;
	int current = _table.getSortDirection();

	TableColumn tc = _table.getColumn(col);
	if (_table.getSortColumn() == tc) {
		dir = (current == SWT.UP ? SWT.DOWN : SWT.UP);
	}

	_table.setSortColumn(tc);
	_table.setSortDirection(dir);

	// now tell the sorted list we&#039;ve updated
	_sortedList.setComparator(new GlazedSortComparator(col, dir));
}
</pre>
</pre>
<p>At this point we&#8217;re basically there. All that&#8217;s missing is a proper <code>listChanged</code> that reflects how we update a TableViewer. So with a few modifications to the code I posted in the <a href="#nutshell_code">nutshell section</a>, we get code that looks like this:</p>
<pre>
<pre class="syntax-highlight:java">
_filterList.addListEventListener(new ListEventListener&lt;RowObject&gt;() {

	@Override
	public void listChanged(ListEvent&lt;RowObject&gt; listChanges) {
		try {
			_table.setRedraw(false);

			// get the list PRIOR to looping, otherwise it won&#039;t be the same list as it&#039;s modified continuously
			final List&lt;RowObject&gt; changeList = listChanges.getSourceList();

			while (listChanges.next()) {
				int sourceIndex = listChanges.getIndex();
				int changeType = listChanges.getType();

				switch (changeType) {
					case ListEvent.DELETE:
						// note the remove of the object fetched from the event list here, we need to remove by index which the viewer does not support
						// and we&#039;re removing the object index location from the event list, not the filtered list
						_viewer.remove(_eventList.get(sourceIndex));
						break;
					case ListEvent.INSERT:
						final RowObject obj = changeList.get(sourceIndex);
						_viewer.insert(obj, sourceIndex);
						_viewer.replace(_filterList.get(sourceIndex), sourceIndex);
						break;
					case ListEvent.UPDATE:
						_viewer.replace(_filterList.get(sourceIndex), sourceIndex);
						break;
				}
			}

			// most important, we update the table size after the update
			_viewer.setItemCount(_filterList.size());
		}
		catch (Exception err) {
			err.printStackTrace();
		}
		finally {
			_table.setRedraw(true);
		}
	}

});
</pre>
</pre>
<p>The result, when combined with the rest of the necessary boilerplate code, looks like this:</p>
<p><img title="TableViewer using Glazed Lists" src="http://hexapixel.com/wp-content/uploads/2009/01/tv_glazed.gif" alt="tv_glazed" width="646" height="400" /></p>
<h4><strong>Download Code</strong></h4>
<p><a href="/files/posts/TableViewerGlazedExample.java">TableViewerGlazedExample.java</a></p>
<h2><strong>Nebula Grid</strong></h2>
<p>Whereas the normal SWT table only supports single column sort (unless you <a href="http://www.eclipse.org/articles/article.php?file=Article-CustomDrawingTableAndTreeItems/index.html" target="_new">owner draw</a>) the Nebula grid can do more. It can do multiple column sorting (visually), grouped columns, and other custom features not available in the default grid. The Nebula Grid has a Viewer implementation, but unfortunately at the time of writing this article, it does not support <code>SWT.VIRTUAL</code> mode. As Nebula sticks very much to the SWT API in terms of naming conventions and implementation, it should be little trouble to convert it over when it does.</p>
<p>Depending on how you look at it, you are about to get quite lucky. For my job I wrote an entire framework implementation wrapping Glazed Lists in a Nebula Grid. It&#8217;s much more generically implemented (with interfaces etc) than our TableViewer example which was written purely for this article. Because of this I don&#8217;t feel like actually ripping it apart into something smaller, so I will use this Framework as the basis for the examples. Thus, this implementation comes with the option to use both the GridViewer implementation (which might be good if you are doing smaller tables that don&#8217;t need Virtual mode) or the grid in <code>SWT.VIRTUAL</code> mode.</p>
<p>One of the bigger differences when we&#8217;re not in viewer mode, is that on the <code>DELETE, INSERT</code> and <code>UPDATE</code> we need to create <code>GridItems</code> instead of just telling the viewer that it&#8217;s changed. It&#8217;s a bit more clunky and object-heavy of course, but it&#8217;s not as bad as it sounds. The switch statement that we used in the previous example becomes this:</p>
<pre>
<pre class="syntax-highlight:java">
switch (changeType) {
    case ListEvent.DELETE:
        removeItem(sourceIndex);
        break;
    case ListEvent.INSERT:
        final IDataObject insert = list.get(sourceIndex);
        addItem(insert, sourceIndex);
        break;
    case ListEvent.UPDATE:
        final IDataObject update = list.get(sourceIndex);
        removeItem(sourceIndex);
        addItem(update, sourceIndex);
        break;
}
</pre>
</pre>
<p>As you can see each one calls a sub-method of the class, and those methods look like this:</p>
<pre>
<pre class="syntax-highlight:java">
private void removeItem(int index) {
	_parent.getTableViewer().remove(_parent.getTableViewer().getElementAt(index));
}

private void addItem(IDataObject msg, int index) {
	GridItem gi = new GridItem(_parent.getGrid(), SWT.NONE, index);
	gi.setData(msg);

	try {
		for (int i = 0; i &lt; _parent.getGrid().getColumnCount(); i++) {
			Color fg = msg.getForeground(i, index % 2 == 0);
			Color bg = msg.getBackground(i, index % 2 == 0);
			Font f = msg.getFont(i);
			String txt = msg.getColumnText(i);
			Image image = msg.getColumnImage(i);

			if (fg != null) {
				gi.setForeground(i, fg);
			}
			if (bg != null) {
				gi.setBackground(i, bg);
			}
			if (f != null) {
				gi.setFont(i, f);
			}
			if (txt != null) {
				gi.setText(i, txt);
			}
			if (image != null) {
				gi.setImage(i, image);
			}
		}
	}
	catch (Exception err) {
		err.printStackTrace();
	}
}
</pre>
</pre>
<p>In this code we use an interface <code>IDataObject</code> that is basically our <code>RowObject</code> code from before. This object has various getter methods for returning column texts, images, fonts and so on.</p>
<p>So how do we go about creating a Nebula Grid based grid with this framework? Mostly it&#8217;s the same way it&#8217;s done with pretty much any SWT widget, along the lines of:</p>
<pre>
<pre class="syntax-highlight:java">
GlazedGridViewer viewer = new GlazedGridViewer(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.VIRTUAL, this, true, null, null, false);
viewer.setAllowMultiColumnSort(true);
viewer.getGrid().setCellSelectionEnabled(true);
</pre>
</pre>
<p>Some pointers: The <code>this</code> parameter is an interface implementation of <code>IGenericGridTable</code> which forces the implementor of the code to include methods for returning a Comparator and a Matcher, like we created before in the previous example. <code>true</code> is the option to create the grid as a plain grid, or to false to create a viewer. The last 3 parameters are a String id used for saving/loading the table state (column order, sizes etc), an <code>IPreferenceStore</code> where it would be saved on, and lastly a <code>true</code>/<code>false</code> whether the table should be saving the state at all.</p>
<p>The framework comes with a default implementation of a Label provider and a Content provider which hooks into the <code>IDataObject</code>. They are created automatically depending on the table type you picked. Column creation is also handled by the framework as the column wrapping implementation allows for individual setting of if a column is sortable, movable, hide-able etc. The API looks like:</p>
<pre>
<pre class="syntax-highlight:java">
public GridViewerColumn(IGlazedGridViewer parentTable, String name, boolean frozen, boolean moveable, boolean sortable, boolean hideable) {
     ...
}
</pre>
</pre>
<p>But when you create a column you do it via the framework as:</p>
<pre>
<pre class="syntax-highlight:java">
GridViewerColumn col = viewer.addColumn(str, false, true, true, true);
col.getGridColumn().setWidth(100);
</pre>
</pre>
<p>And finally, to add objects and set the table input, it&#8217;s again much like the TableViewer, for example:</p>
<pre>
<pre class="syntax-highlight:java">
List&lt;IDataObject&gt; input = new ArrayList&lt;IDataObject&gt;();
for (int i = 0; i &lt; 1000; i++) {
	input.add(new OurIDataObjectClass(i));
}
viewer.setInput(input);
</pre>
</pre>
<p>I don&#8217;t think much more needs to be said about the framework. It has a lot of API in it already and a test class as well. I suggest you download it if you want to give it a go. </p>
<p><strong>Important:</strong> as I currently am not using the framework due to the fact that the Nebula Grid was too slow and memory hungry for what we needed it for (40,000+ rows) I converted the entire framework over to use a NatTable and kept the work going from there. It should be fine, but there may be some minor issues here and there as it was never fully tested. If you find problems and fix them, do send me the code so that everyone can benefit. For the NatTable implementation of the framework, that&#8217;s the next section of this article.</p>
<p>All put together, the test code looks like this when run (with shameless self-promo selection):</p>
<p><img title="Glazed Nebula Grid" src="http://hexapixel.com/wp-content/uploads/2009/01/tv_nebula.gif" alt="tv_nebula" width="681" height="382" /></p>
<p>No filter box in this example, but I think the TableViewer one shows how it works so it&#8217;s not necessary. A point worth making though is that all filters are <code>DataFilter</code> based (framework class). That class extends <code>ViewerFilter</code> so that if you need more than one table implementation, you can re-use your filters should you so wish. That filter also comes with &#8220;whole word&#8221;, &#8220;regular expression&#8221; and &#8220;case sensitive&#8221; filter/search options in the filter itself.</p>
<h4><strong>Download Code</strong></h4>
<p><a href="/files/glazed_nebula_framework.zip">Glazed Lists &#8211; Nebula Grid Framework</a></p>
<h2><strong>Nat Table</strong></h2>
<p>The <a href="http://nattable.org/drupal/" target="_blank">NatTable</a> Widget (Nat stands for Natalie, the girlfriend of the original widget author) is a fairly new Grid widget and one that I personally was quite impressed with after having researched pretty much all SWT grid widgets out there. It&#8217;s still in active development, and not everything is working 100% yet (grouped columns are problematic, some random drawing issues, frozen columns behave oddly, listeners are quite messy), but overall it&#8217;s in a good enough shape that we decided to use it in production. The reason I decided we should use it was simple; We needed a table that could deal with 40,000+ rows in 20+ columns without any lag or any drawing slowdowns whatsoever. It needed to be customizable and I wanted Glazed Lists on it. NatTable is inherently virtual, so you don&#8217;t tell it that it&#8217;s virtual, it just is. It only draws what you see in the viewport which makes redraws near instant and the overall feel is &#8220;snappy&#8221;.</p>
<p>The NatTable API is also quite different from most SWT widgets. Pretty much every part of the table can be extended or implemented in a custom way, and there&#8217;s a lot of classes and places to do this in. At the same time, the API feels sometimes half-finished as simple methods such as <code>selectAll()</code> are nowhere to be found, and trying to figure out how to do it can be a bit of a head-scratcher.  So, It takes a while to wrap your head around the API, but with help from a few examples on their homepage it shouldn&#8217;t be too much of a deal (and most of those kinds of methods are in the framework). The table is model driven, which I suppose is the third type of table model I see used in tables (first being no model and row-item based, second being a viewer on top of a row-item based grid).</p>
<p>All that said, I truly hope the current development team keeps this widget going (and from the looks of it it&#8217;s very active), because it just might be the best SWT grid-table currently out there. The Nebula Grid had huge potential, but development on it is slow going. I know Tom Shindl is doing work on it, but I don&#8217;t know what the roadmap is.</p>
<p>Ok, lets get going with the framework I&#8217;ve built for NatTable. It&#8217;s not complete, just like the Nebula Grid framework which it is based on, but it will get you a very long way. As this framework has gotten further it has more utility methods and automation than it&#8217;s predecessor. It will even mimic the Windows column headers through a custom header drawer if so desired. It also has full color-customization support via interfaces and so on. It would be a long list if I wrote it all here, so I suggest you check out the API.</p>
<p>To create a table using the framework, you can use various constructors, of which the biggest is:</p>
<pre>
<pre class="syntax-highlight:java">
public GlazedNatGridViewer(Composite parent, int style, IGenericNatGridTable generic, String tableId, IPreferenceStore store, boolean allowStateSaving, AbstractGlazedNatVisualConfig config) {
       ...
}
</pre>
</pre>
<p>You will notice the <code>IGenericNatGridTable</code> is the same interface as in the Nebula Grid framework and works the same way (just different name). The last parameter, <code>AbstractGlazedNatVisualConfig</code> is if you want to pass in custom settings for colors, fonts, widths, heights etc. A whole load of things can be customized, or you can stick to the defaults (<code>DefaultGlazedNatVisualConfig</code>).</p>
<p>In our test class we will do the same as we&#8217;ve done in the previous examples, we&#8217;ll create some columns, some row data and do a sort. Using the framework we create a new table as follows:</p>
<pre>
<pre class="syntax-highlight:java">
GlazedNatGridViewer viewer = new GlazedNatGridViewer(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FULL_SELECTION, this, new DefaultGlazedNatVisualConfig());
viewer.setAllowMultiColumnSort(true);

for (int i = 0; i &lt; 10; i++) {
	NatGridViewerColumn col = viewer.addColumn(&quot;Column &quot;+i, false, true, true, true);
	col.setDefaultWidth(100);
}

List&lt;OneRow&gt; input = new ArrayList&lt;OneRow&gt;();
for (int i = 0; i &lt; 1000; i++) {
	input.add(new OneRow(i));
}

viewer.setInput(input);
</pre>
</pre>
<p>Our <code>OneRow</code> class implements <code>IDataObject</code> which contains getters for all things table related (column text etc). It also contains a getter specifically for returning a value that should be used when comparing column data when sorting. By default we simply return the same column text as the visible-to-user text:</p>
<pre>
<pre class="syntax-highlight:java">
class OneRow implements IDataObject {

	private int _row;

	public OneRow(int row) {
		_row = row;
	}

	@Override
	public String getColumnText(int column) {
		return &quot;&quot;+(_row+column);
	}

	@Override
	public String getSearchMatchText(int column) {
		return getColumnText(column);
	}

	...
}
</pre>
</pre>
<p>The multi column sort feature is already built in, and uses Glazed Lists ability to chain comparators. So whenever you sort more than one column, it will ask for a Comparator for each sorted column, and combine them in the order that you sorted the columns. You multi-sort by holding down the shift key to add more columns, and I&#8217;ve also added so it draws a number on the column header for displaying which order it was sorted in. The sort happens as soon as you let go of the shift key (and you can modify the columns by pressing the shift key again before clicking the column header).</p>
<p>Running the test class we get a table that looks like this:</p>
<p><img title="Glazed Nat Table Viewer" src="http://hexapixel.com/wp-content/uploads/2009/01/tv_nat.gif" alt="Glazed Nat Table Viewer" width="625" height="342" /></p>
<p>That pretty much sums it up for the Nat Table. Regardless of what table implementation you are going with or decide to go with, I&#8217;m sure you will agree that the power and simplicity of Glazed Lists is amazing. And we&#8217;ve only scratched the surface on it here. For much more information and examples with deeper complexity I suggest visiting the homepage and checking the Glazed Lists API. They have some built-in support for SWT as well (such as putting your updates on the UI thread), so they&#8217;re not 100% Swing-based even though most of their pre-implemented table-realted items are for Swing components. </p>
<h4><strong>Download Code</strong></h4>
<p><a href="/files/glazed_nat_framework.zip">Glazed Lists &#8211; Nat Table Framework</a></p>
<h2><strong>Closing words</strong></h2>
<p>This was a long article. It took me 2 full days to write and much longer if you count the hours put into creating both frameworks. My hopes is that you will find the article and Glazed Lists useful in your future table and grid implementations, and that this wonderful package becomes as part of your projects as <a href="http://www.miglayout.com/">MigLayout</a> or other &#8220;must have&#8221; API&#8217;s that make our lives coding UI&#8217;s much easier. Personally I cannot live without Glazed Lists, and I only wish I had found out about them sooner. </p>
<p>And again, I highly recommend the <a href="http://publicobject.com/glazedlistsdeveloper/">screen casts</a> for more information on each type of list you can create.</p>
<p>Do let me know if you spot errors in the article, it&#8217;s hard to cover everything on the first try. I will put these files + a link to this post into the Projects section later as well.</p>
<h2><strong>All Code</strong></h2>
<p>Here are download links to all code referenced in this article:</p>
<div id="bulletlist">
<ol>
<li><a href="/files/posts/TableViewerGlazedExample.java">TableViewer code</a></li>
<li><a href="/files/glazed_nebula_framework.zip">Glazed Lists &#8211; Nebula Grid Framework</a></li>
<li><a href="/files/glazed_nat_framework.zip">Glazed Lists &#8211; Nat Table Framework</a></li>
<li><a href="/files/glazed_nebula_and_nat_frameworks.zip">Glazed Lists &#8211; Both Frameworks Combined</a></li>
</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://hexapixel.com/2009/01/02/glazed-lists-swt-tables-true/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
	</channel>
</rss>

