<?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>Thoughts On Eclipse UI &#187; TokenViewer</title>
	<atom:link href="http://eclipseblog.ostroukhovs.com/category/tokenviewer/feed/" rel="self" type="application/rss+xml" />
	<link>http://eclipseblog.ostroukhovs.com</link>
	<description>Useful bits of code</description>
	<lastBuildDate>Tue, 02 Nov 2010 19:39:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>TokenViewer &#8211; Databindings</title>
		<link>http://eclipseblog.ostroukhovs.com/2009/02/01/tokenviewer-databindings/</link>
		<comments>http://eclipseblog.ostroukhovs.com/2009/02/01/tokenviewer-databindings/#comments</comments>
		<pubDate>Sat, 31 Jan 2009 23:05:19 +0000</pubDate>
		<dc:creator>Eugene Ostroukhov</dc:creator>
				<category><![CDATA[TokenViewer]]></category>
		<category><![CDATA[JFace]]></category>
		<category><![CDATA[New Code]]></category>
		<category><![CDATA[SWT]]></category>

		<guid isPermaLink="false">http://eclipseblog.ostroukhovs.com/?p=33</guid>
		<description><![CDATA[TokenViewer was submitted to Eclipse.org as Bug#262846 I remember in one past project (financial application) there was a special control &#8211; &#8220;Lookup&#8221;. Basically, it was a label, text entry and a button. User entered some ID (say, employee SSN) the system will look up the employee, show employee first &#38; last names in non-editable entries [...]]]></description>
			<content:encoded><![CDATA[<p>TokenViewer was submitted to Eclipse.org as <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=262846">Bug#262846</a></p>
<p>I remember in one past project (financial application) there was a special control &#8211; &#8220;Lookup&#8221;. Basically, it was a label, text entry and a button. User entered some ID (say, employee SSN) the system will look up the employee, show employee first &amp; last names in non-editable entries (to confirm that correct employee was found) and user may enter other values as he needs. The button would open a selection dialog so the user can select the employee by name.</p>
<p>I tried to implement similar functionality (excluding label and button) using token viewer &amp; JFace bindings. I created a new TitleAreaDialog with following createDialogArea method:</p>
<pre class="brush: java; ">

		getShell().setText(&quot;Databings Test&quot;);
		setTitle(&quot;Some Dull Data Entry&quot;);
		setMessage(&quot;Enter all the needed data&quot;);
		Composite root = (Composite) super.createDialogArea(parent);

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

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

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

		createBindings(tokenViewer, firstNameDisplay, lastNameDisplay);

		return root;
</pre>
<p>This method adds TokenViewer and two read-only text entries. Afterwards it calls &#8220;createBindings&#8221; to bind TokenViewer selection to those fields.</p>
<pre class="brush: java; ">
private DataBindingContext createBindings(TokenViewer tokenViewer,
			Text firstNameDisplay, Text lastNameDisplay) {
		DataBindingContext bindingContext = new DataBindingContext();

		ISWTObservableValue firstNameObservable = SWTObservables
				.observeText(firstNameDisplay);
		ISWTObservableValue lastNameObservable = SWTObservables
				.observeText(lastNameDisplay);

		IViewerObservableValue selected = ViewersObservables
				.observeSingleSelection(tokenViewer);

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

		bindingContext
				.bindValue(firstNameObservable, fname, new UpdateValueStrategy(
						false, UpdateValueStrategy.POLICY_NEVER), null);
		bindingContext
				.bindValue(lastNameObservable, lname, new UpdateValueStrategy(
						false, UpdateValueStrategy.POLICY_NEVER), null);
		return bindingContext;
	}
</pre>
<p>As you can see, this method uses JFace bindings to bind TokenViewer selection first and last name to corresponding text fields.</p>
<p>When the user opens dialog the fields are empty. When the user begins typing the &#8220;wrong&#8221; SSN entry will be underlined until correct value is entered:</p>
<p><img class="aligncenter size-full wp-image-41" title="typing" src="http://eclipseblog.ostroukhovs.com/wp-content/uploads/2009/02/typing.png" alt="typing" width="693" height="380" />Read-only text fields will get populated once proper SSN is entered:</p>
<p><img class="aligncenter size-full wp-image-42" title="entered" src="http://eclipseblog.ostroukhovs.com/wp-content/uploads/2009/02/entered.png" alt="entered" width="693" height="380" />User may also use content assist to select employee from list:</p>
<p><img class="aligncenter size-full wp-image-43" title="ca-popup" src="http://eclipseblog.ostroukhovs.com/wp-content/uploads/2009/02/ca-popup.png" alt="ca-popup" width="613" height="238" /></p>
<p> </p>
<p>Implementation details:</p>
<p>1. <strong>Employee</strong> - POJO class that supports property change listeners to conform JFace bindings requirements.<br />
2. <strong>EmployeeDAO</strong> - DAO class that fetches Employee objects from database or any other source. In this example it returns a list.<br />
3. <strong>EmployeeLabelProvider</strong> &#8211; returns labels for content assist pop-up. Labels are &#8220;<first name> <last name>&#8220;. It can also return icons and/or descriptions if needed.<br />
4. <strong>EmployeeSSNContentProvider</strong> &#8211; an instance of the ITokenContentProvider. It&#8217;s main responsibility is to transform text to/from object and to fetch instances from DAO. Notable methods:</p>
<pre class="brush: java; ">

	public Object[] getElements(Object inputElement) {
		return null;
	}
</pre>
<p>This method will get called when content assist is invoked for empty field. It may return all elements but I chose to return none since it is common in real-world applications that the system will chose not to query the whole database at once</p>
<pre class="brush: java; ">
	public String toString(Object object) {
		return ((Employee) object).getSsn();
	}
</pre>
<p>This method returns the string that corresponds to given model object. I.e. when entering the classname this string would be fully qualified name &#8211; not the short name. CA will automatically convert short name to fully qualified one.</p>
<pre class="brush: java; ">
	public Object[] getChildren(Object object, String prefix) {
		Object[] elements = ((EmployeeDAO) object).getAllEmployees().toArray();

		Collection&lt;Object&gt; selected = new LinkedList&lt;Object&gt;();
		for (Object employee : elements) {
			if (((Employee) employee).getSsn().startsWith(prefix)) {
				selected.add(employee);
			}
		}
		return selected.toArray();
	}
</pre>
<p>Returns the elements that match given pattern. In real-world application this method would be smarter and more tightly integrated with DAO object so it only queries entries it needs.</p>
<pre class="brush: java; ">
	public Object fromString(Object parent, String value) {
		Object[] children = getChildren(parent, value);
		for (Object child : children) {
			if (((Employee) child).getSsn().equals(value)) {
				return child;
			}
		}
		return null;
	}
</pre>
<p>This method decodes a string to exact object. If this method returns not-null then selection event will be updated.</p>
<p>You can download sample project (that contains updated TokenViewer) <a href="http://eclipseblog.ostroukhovs.com/wp-content/uploads/2009/02/databindings-sample.zip">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://eclipseblog.ostroukhovs.com/2009/02/01/tokenviewer-databindings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TokenViewer &#8211; Basics</title>
		<link>http://eclipseblog.ostroukhovs.com/2009/01/29/tokenviewer-basics/</link>
		<comments>http://eclipseblog.ostroukhovs.com/2009/01/29/tokenviewer-basics/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 22:41:20 +0000</pubDate>
		<dc:creator>Eugene Ostroukhov</dc:creator>
				<category><![CDATA[TokenViewer]]></category>
		<category><![CDATA[JFace]]></category>
		<category><![CDATA[New Code]]></category>
		<category><![CDATA[SWT]]></category>

		<guid isPermaLink="false">http://eclipseblog.ostroukhovs.com/?p=22</guid>
		<description><![CDATA[I created a new viewer that I think may be really useful. I&#8217;m writing this post to provide a high-level description. You can use it as follows: final TokenViewer tokenViewer = new TokenViewer(root); tokenViewer.getControl().setLayoutData( new GridData(GridData.FILL_HORIZONTAL)); tokenViewer.setContentProvider(new BaseWorkbenchContentProvider()); tokenViewer.setLabelProvider(new WorkbenchLabelProvider()); tokenViewer.setInput(workspaceRoot); The result is a simple text field with following services: Content assist. Object-oriented IStructuredSelection [...]]]></description>
			<content:encoded><![CDATA[<p>I created a new viewer that I think may be really useful. I&#8217;m writing this post to provide a high-level description. You can use it as follows:</p>
<pre class="brush: java; ">

final TokenViewer tokenViewer = new TokenViewer(root);

tokenViewer.getControl().setLayoutData(

new GridData(GridData.FILL_HORIZONTAL));

tokenViewer.setContentProvider(new BaseWorkbenchContentProvider());

tokenViewer.setLabelProvider(new WorkbenchLabelProvider());

tokenViewer.setInput(workspaceRoot);
</pre>
<p>The result is a simple text field with following services:</p>
<ol>
<li>Content assist.</li>
<li>Object-oriented IStructuredSelection support &#8211; if the user enters proper string the selection event is thrown. If user sets selection &#8211; string will appear in the text entry.</li>
<li>Easy and familiar programming model &#8211; I guess any JFace/Eclipse plugin developer wrote dozens of those label/content providers.</li>
</ol>
<p> </p>
<div id="attachment_25" class="wp-caption aligncenter" style="width: 285px"><img class="size-medium wp-image-25" title="tokenviewer-simple" src="http://eclipseblog.ostroukhovs.com/wp-content/uploads/2009/01/tokenviewer-simple.png" alt="TokenViewer working with workspace" width="275" height="153" /><p class="wp-caption-text">TokenViewer working with workspace</p></div>
<p>This simple API works for the case when text in the text field is the same as a label in the content assist pop-up. But once you want to have different text (i.e. SSN entry may show employee name in the pop-up) you will need something more specific for this task and that is why I defined special content provider (I still hope it is easier to use then regular JFace content assist API):</p>
<pre class="brush: java; ">

public interface ITokenContentProvider extends IStructuredContentProvider {

Object fromString(Object parent, String value);

String toString(Object object);

Object[] getChildren(Object object, String prefix);

}
</pre>
<ul>
<li><em>fromString</em> method will return a child of the given parent node that corresponds to a specific string. It may return null.</li>
<li><em>toString</em> will convert given object to its string representation.</li>
<li><em>getChildren</em> tries to find all the elements that correspond to given string.</li>
</ul>
<p>If the viewer is provided with IStructuredContentProvider (or ITreeContentProvider) it will wrap it with a custom adapter so you can use your existing code.</p>
<p>The label provider is used to decorate the content assist pop-up. I also have a slightly extended label provider interface:</p>
<pre class="brush: java; ">

public interface IDescriptionProvider extends ILabelProvider {

public String getDescription(Object element);

}
</pre>
<p>This optional extension provides the way to provide extended object descriptions that are shown along the content assist pop-up:</p>
<div id="attachment_30" class="wp-caption aligncenter" style="width: 415px"><img class="size-full wp-image-30" title="tokenviewer-classes2" src="http://eclipseblog.ostroukhovs.com/wp-content/uploads/2009/01/tokenviewer-classes2.png" alt="This is also a tokenviewer" width="405" height="249" /><p class="wp-caption-text">This is also a tokenviewer</p></div>
<p>Note &#8211; red squiggles are automatically shown when there is no object that corresponds to a text.</p>
<p>What I&#8217;m going to implement next is:</p>
<ol>
<li>Multiple selection support when token list is separated with some delimeter.</li>
<li>Rich text (HTML?) support both for content assist pop-up and description pop-up.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://eclipseblog.ostroukhovs.com/2009/01/29/tokenviewer-basics/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

