Repainting a JTree

I've run into this issue a number of times due to all my various JTree hacking in projects like CogZ, ZoomableJTrees, and now again in my Change Analysis plugin.
Typically to force a JTree to repaint, you might do something like this:
myTree.invalidate();This code will force a re-rendering of the JTree object, but if the node sizes needed to be re-calculated, the tree will end up displaying as in my screenshot above. So, my trick to get around this issue is to actually change the JTree row size before I call the repaint, this will force the JTree to recalculate all the node size bounds.
myTree.validate();
myTree.repaint();
// call setRowHeight to force the sizes to recalculateIt's a bit weird, but it works :-).
myTree.setRowHeight(DEFAULT_ROW_HEIGHT);
// repaint this puppy
myTree.repaint();
Digging into ontology change sets
For the programmers possibly reading this, you can think of the ontology as a software project. The artifacts of interest would be individual files.
So far, in the three projects I've looked at, two of the three have very few multiple editors making changes to a single term. Unfortunately, I don't really have enough data to say anything conclusive yet about this observation. Once I have a longer history for a project, I'd like to see if is the general case. Also, I'd like to investigate what kind of roles people take on as editors. It would also be interesting to see what terms stabilize, with regard to their edits, over time, while I suspect others will perhaps be in constant evolution.
During my initial analysis, I did come up with another feature for my plugin. While using the concept change analysis view that I talked about in my last post, I found sometimes I wished I could see the global impact that a single author or a set of authors had.
To support this, I added a filter configuration dialog, which allows the user to filter the concept change tree to display only changes by certain authors or between certain date ranges. The date range feature will be very nice down the road when I have a longer history of changes. I'll be able to see where edits are taking place for specific time periods. I think, like software development, there will most likely be "hot spots" for changes over short periods of time.
Below is an example of applying the author filter. The first image shows the filter dialog where I've chosen two authors to be filtered. Once I apply the filter, all changes by these authors will be hidden and the change counts in the tree will update. The two side by side images show the before and after screenshots of the concept change view. As you can see when you compare the change counts in the tree between the two views, the two authors that are filtered are responsible for HUGE amount of changes in comparison to the others.



p2 and Agile Software Development
One of the key aspects of Agile Software Development — or any iterative software development process — is keeping your customer in-the-loop. In order for customers to have a voice in the software development process they must continually consume your software, provide feedback, and witness the results of that feedback. In a small setting this might not be to hard. But when you mix in a variety of different configurations, distributed development teams, and distributed customers — delivering and updating software can become a challenge.
Not only do your customers need to acquire the proper configurations, and stay up-to-date as the software is developed, your development team must also be developing against the latest code base. Again, in small teams it might be practical to checkout the entire codebase from your SCM system, but does this scale to multi-million line systems?
The Equinox/p2 project provides a powerful provisioning platform that can be used to help deliver software in number of different forms. At EclipseCon this year, Kim Moir and I will be exploring how you can use p2 as a platform to help enable agile software development. While the tutorial will focus on how p2 can facilitate agile software development, the tutorial will also provide a good overview for anyone getting started with p2 and PDE/Build.
In particular, we will discuss how to:
- Create, publish and provision a variety of product configurations
- Enable automatic updates within your products
- Craft and manage target platforms
The hands on exercises will explore the new p2 API, PDE/Build and many of the headless p2 applications. The exercises will be based off the Hyperbola chat client from the new Eclipse RCP Book. (We may even have a preview of the book on display at the tutorial). If you are interested in how to streamline the deployment of your software, are looking for an update mechanism for RCP or OSGi based applications, or are just curious about p2, please feel free to attend our tutorial.
The Implications of How We Tag Software Artifacts: Exploring Different Schemata and Metadata for Tags
Social tagging has been adopted by software developers in various contexts from source code to work items and build definitions. While the success of tagging is usually attributed to the simplicity of tags, the implementation details of tagging systems vary significantly in terms of metadata, schemata and semantics. In a position paper that Peggy and I recently wrote for Web2SE, we argue that academia and industry should be aware of these differences and that we should start to examine their implications.
The idea of analyzing different dimensions of tagging systems is not new. A very detailed taxonomy is given by Marlow et al. They identify the following seven dimensions in the design of a tagging system:
- Tagging rights: Users can tag everybody’s resources vs. users can only tag their own resources.
- Tagging support: Blind tagging (users cannot see each other’s tags) vs. viewable tagging (users can see each other’s tags) vs. suggestive tagging (the system suggests tags to users).
- Aggregation: Bag model (allows duplicate tags per resource) vs. set model (no duplicates).
- Type of object: Type of the resource to be tagged.
- Source of material: Resource is supplied by the systems vs. resource is supplied by the users.
- Resource connectivity: Linked vs. grouped vs. none (possible connections between the resources).
- Social connectivity: Linked vs. grouped vs. none (possible connections between the users).
While these dimensions apply to tagging systems used by software developers, studying tagging systems used by software developers such as ICICLE, TagSEA, IBM’s Jazz, BITKit, Google Code, ConcernMapper and Concern Graphs reveals additional dimensions on top of Marlow’s taxonomy.
We identified the following additional dimensions:
- Pre-defined vs. user-defined: Most current tagging systems are based on the concept of tags as “freely-chosen keywords or terms that are associated with or assigned to a piece of information”. However, in older tagging systems such as ICICLE, possible keywords were pre-defined, and software developers were not able to add new keywords to the system. In a dynamic environment such as software development, the just-in-time addition of new tags is the more promising approach.
- Metadata: Different tagging systems store different amounts of metadata. For example, in the case of tagging work items in IBM’s Jazz, information such as the tag author and the time a tag was applied to a work item can only be identified by browsing the work item’s history. In other systems such as TagSEA, the author and time can be explicitly added to each tag instance, and tags can be searched by their authors and creation time. In order to keep the simplicity, tag authors should not be required to add metadata. However, all metadata that can be recorded automatically should be stored to provide additional context.
- Semantics: While most tagging systems treat keywords simply as terms that are associated with artifacts, some systems go beyond that and add semantics to tags. An interesting approach is taken by labels in the issue tracker of Google Code, which goes beyond basic labels to support key-value labels. Key-value labels contain one or more dashes, and the part before the first dash is considered to be a field name while the part after that dash is considered to be the value. Studying the use of key-value labels in Google Code is part of our ongoing work.
- Hierarchies: Some tagging systems explicitly support tag hierarchies, using a dot-notation (e.g., TagSEA). Keywords that have dots in them can be treated as hierarchical, and they can be displayed in tree-views. In other systems such as IBM’s Jazz, some developers use the dot-notation even though there is no explicit support for hierarchies. A flexible approach that offers additional views when needed is promising.
- Single type of resource vs. multiple types: Software developers handle many different kinds of artifacts from source code and work items to build scripts. Nevertheless, many tagging systems for software developers only support tagging a single kind of artifact. One exception is TagSEA. It allows software developers to tag locations in source code — called waypoints — and artifacts such as files, and it shows different kinds of artifacts in a single view. This allows for grouping and relating different kinds of artifacts while keeping the simplicity of tags.
- Integration: Another dimension is the extent to which the tagging mechanism is integrated with other tooling. Some systems support social tagging of source code, but require the user to post code fragments on public servers before tags can be applied to code fragments (e.g., DZone Snippets and ByteMycode). In other systems such as IBM’s Jazz or TagSEA, the tagging mechanism is part of the IDE. With the recent trend of moving the IDE into the browser, tagging artifacts online is a promising approach.

ChangeAnalysisTab Released
The original purpose of the plugin was really to help me with analyzing the changes being made to an ontology throughout the ontology's evolution. However, after showing some demos, people thought other Protégé users might be interested in also having access to this information.
One of the views I like the most is the one shown in the screenshot below. On the left it shows the normal class hierarchy for an ontology, except that I've extended the tree to show how many changes exist within a branch and for a given term. The values in bold represent changes that have been made to that term, while the values in gray represent the number of changes that have been made to all subclasses within that branch.
In the screenshot, you can see that there's been 2091 changes made within the "ICD Categories" branch (circled in red). However, what's interesting is that 73% of these changes or 1534 changes, have occurred all within the "Diseases of the skin and subcutaneous tissue" branch (also circled in red).

This is useful because it allows the managers of the project, or anyone that is interested, really see where the ontology's development is most active. In the future, I'd like to add in some controls for specifying a date range, that way you can see where the development is most active today, or say 6 months ago, or 2 years ago. I'm holding off a bit on this feature as all the sample projects I have with tracked changes are only starting their development so such fine grain control is unnecessary at the moment.
DragHandle, ResizeHandle
You can set the following properties:
- rows - sets the number of rows of dots
- columns - sets the number of columns of dots
- dotSize - sets the dot size (defaults to 2)
- dropShadowEnabled - sets whether a drop shadow is used (defaults to false)
- dropShadowColor - sets the drop shadow color
- keepOnTop - if true then the handle will be on top of the other sibling components
- positionResizeHandle - If true then the resize handle will be positioned in the bottom right corner of the parent (ResizeHandle only)
You can set the following styles too:
- backgroundColor, backgroundAlpha - sets the background color alpha for the drag/resize handle
- dragHandleColor, dragHandleAlpha - sets the color and alpha value for the drag handle
- resizeHandleColor, resizeHandleAlpha - sets the color and alpha value for the resize handle
These two components are used in all the Resizable Containers.
Mashup Environments in Software Engineering
Together with Christoph Treude and Margaret-Anne Storey, I outlined the idea how mashup technology can be leveraged to achieve this. Our 2 page position paper "Mashup Environments in Software Engineering" was accepted at Web2SE, the First Workshop on Web 2.0 for Software Engineering, co-located with ICSE 2010. Here is the abstract of our paper:
Too often, software engineering (SE) tool research is focused on
creating small, stand-alone tools that address rarely understood
developer needs. We believe that research should instead provide
developers with flexible environments and interoperable tools,
and then study how developers appropriate and tailor these tools
in practice. Although there has been some prior work on this, we
feel that flexible tool environments for SE have not yet been fully
explored. In particular, we propose adopting the Web 2.0 idea of
mashups and mashup environments to support SE practitioners in
analytic activities involving multiple information sources.
More fun with JFreeChart
In some types of charts, the library will allow you to sort the domain axis, so I'm guessing it uses the Comparable for this functionality. Unfortunately, the DefaultCategoryDataset class that I am using to create my area charts does not support this, but I want my domain axis to be sorted by ascending date.
I spent some time looking at the internal code of the library to try to figure out if there's a way I could do this. It turns out that the DefaultCategoryDataset uses a DefaultKeyedValues2D class to store it's actual data and this class supports a sort row keys option. However the DefaultCategoryDataset initiates the internal object with this always set to false. There's no public methods to access to the internal data object, so I can't modify it at runtime.
Also, it doesn't appear that the code for sorting the key values really works as I would assume it should. Here's the internal code from the DefaultKeyedValues2D class:
row = new DefaultKeyedValues();I would think that this sortRowKeys option should rely on the fact that the rowKey is Comparable, and should insert the new rowKey into the rowKeys list based on a comparison to the already existing keys. Instead all it does is insert the new rowKey at the beginning of the rowKeys list. This happens because of the line rowIndex = -rowIndex - 1. In this case, rowIndex will initially be equal to -1, the equation is -(-1) - 1, which is 1-1=0.
if (this.sortRowKeys) {
rowIndex = -rowIndex - 1;
this.rowKeys.add(rowIndex, rowKey);
this.rows.add(rowIndex, row);
}
So, even if I copied the internal code for DefaultCategoryDataset into my own class, and modified it's initiation of DefaultKeyedValues2D to set the sort key option to true, it still wouldn't actually sort the keys properly!
In the end, I went with a somewhat hacky solution that I knew would work. While I process my data to display in the chart, I store all the unique dates that I encounter in a sorted set. Then, before I add all my values to the dataset, I make sure the first entry contains all the unique dates in the proper order. This forces JFreeChart's DefaultKeyedValues2D class to actually insert the row keys into its internal list in the proper order.
Here's the hack:
// get the first entry in the listAs for the plugin, I am planning to include it in the Protégé release that is scheduled for this week.
Entry<String, Map<Date, Integer>> firstEntry =
authorToChangesByMonthMap.entrySet().iterator().next();
// total hack to get the row keys to show up in sorted order
for(Date date : allDates) {
// check to see if the key exists, if not, create it
if(firstEntry.getValue().get(date) == null) {
// dummy entry
firstEntry.getValue().put(date, 0);
}
}
Blog changes and a real update
As I mentioned in my last post, I've now been at Stanford for almost two weeks. One of the projects I am involved in is with the next revision of the International Classification of Disease (ICD-11). Researchers/developers at Stanford have been collaborating with the World Health Organization to develop software that will allow members of the medical research community to collaboratively develop ICD-11 in a somewhat open, crowd-sourcing manner.
Members of Stanford's Protégé team have extended the web-based version of Protégé to help support this effort. For those unfamiliar with Protégé, it is a freely available ontology editor. If you don't know what an ontology is, for the purposes of this post, you can think of it as a taxonomy or hierarchy of terms.
Now, one of the big issues with this project is managing this collaborative effort. There could potentially be all kinds of simultaneous editing, conflicts to resolve, and issues with simply understanding the evolution of the terminology. What I have started doing is analyzing the changes that have been made to the ontology so far.
I have a bunch of researchy-type questions I want to answer through this analysis and at first, I thought I would just write some scripts to pull out the data. However, since this is so exploratory, I thought it might be more interesting and potentially useful to develop a tool that would allow me to explore the data. I started writing a Protégé plugin that provides different analysis views based on the tracked changes of a given ontology (in this case, the ICD-11 ontology).
For one view in the plugin, I wanted to display changes made to terms over time. This way I could visually see how a term has evolved over a certain time period. I wanted this view to be similar to the NameVoyager applet. To create the area chart effect that I needed, I decided to use the JFreeChart library, which I have used a few times in past projects.
Creating the view was reasonably simple, but I did run into one annoying technical detail that took a while to resolve. With JFreeChart, chart's use dataset objects to hold the data the chart is to represent. For my area charts, I used the DefaultCategoryDataset, which takes three parameters for adding new values; the actual numeric data value, a row key and a column key.
For example, in my case, I want to show term changes over time, so my x-axis is going to be months, y-axis the number of changes, and I want to have a different data series or category for each term. Thus, in my DefaultCategoryDataset, the row key is the term name, while the column key is the month and year.
The pesky technical issue was that I wanted my month and year to display like "July, 2009", but sorted along the x-axis based on a date comparison. The row and column keys can be any Comparable class, so I created my own DateKey class that implemented the Comparable interface. For displaying, JFreeChart simply calls the toString method on the row and column key objects, so in my DateKey class, I format the data object as I want in the toString method, but in my compareTo function, I call the Date class compareTo function.
Based on the JFreeChart API, I assumed this would work, but I kept getting multiple entries for "September, 2009" for each term displayed in the visualization. I quickly realized that the compareTo function is never called. Eventually, after looking through the JFreeChart source code, I found that they store their row and column keys in a list. To determine if the key already exists, they call the list's indexOf method. This method does not use the compareTo function, it performs a linear O(n) search using the equals method.
So, in order to make my DateKey work, I had to implement an equals method and hashCode function. JFreeChart's reliance on these methods rather than the compareTo function seems like a bug in their library. If compareTo is never called, then why must the row and column key's implement Comparable?
Here's a couple of screenshots of what the view turned out to look like.


Here's the final code for my DateKey class.
public class DateKey implements Comparable<DateKey> {
private static final DateFormat formatter =
new SimpleDateFormat("MMMMM, yyyy");
private Date key;
public DateKey(Date key) {
this.key = key;
}
public Date getKey() {
return key;
}
public String toString() {
return formatter.format(key);
}
public boolean equals(Object o) {
return key.equals(((DateKey)o).getKey());
}
public int hashCode() {
return key.hashCode();
}
public int compareTo(DateKey o) {
return key.compareTo(o.getKey());
}
}
So long UVic, thanks for the memories!
I plan to stay somewhat involved with the UVic programming teams. John Hawthorn and Tyler Cadigan have taken over the weekly meetings as well as recruitment. I've been helping through e-mail whenever I'm needed. In the Fall I plan to help facilitate practice sessions between UVic, UBC, SFU, and Stanford as was done last year.
I'm not sure what my plans are for my blog right now. I'm not sure whether I'll have that many programming team related updates now. I may start mixing in some discussion about the projects I am currently work on at Stanford. The coding I am doing here is more technical, engineering and research orientated, rather than specifically problem solving. However, it may still be of some interest.
Notifying GWT when a Flex widget is initialized
1. GWT Wrapper for Flex components
2. Notifying GWT when a Flex widget is loaded (this tutorial)
This tutorial is based on the previous one, creating a GWT Wrapper for Flex components, and assumes that you have a similar project setup and that you have created the classes and files with the source code from that tutorial.
The general idea is to listen for the application complete event in Flex, to forward this event to the GWT wrapper and to notify listeners on the GWT side. For this to work, the Flex widget must include it's swfID when forwarding the event to GWT, because we need to know which Flex widget should get notified on the GWT side if we have multiple Flex widgets. For some reason, the Flex application id does not seem to work for that purpose on all browsers, so we pass it in as a Flash var:
1. Add addFlashVar call for passing the swfid into the Flex component to the SampleFlexWrapperWidget constructor:
addFlashVar("swfid", getSwfId());
The whole constructor should look like this:
public SampleFlexWrapperWidget(int width, int height) {
super("flexgwtintegration/Test.swf", width, height);
addFlashVar("swfid", getSwfId());
}
2. In the Flex component, add an accessor to that property:
public function get swfID():String {
return Application.application.parameters.swfid;
}
Now we can use the swf id within Flex. The next step is to listen for the application complete event in Flex and to forward it to GWT.
3. Add the event listener for the application complete event in the init() method of our Flex widget. We use the application complete event, because we want to make sure that the widget is visible and ready (More information on the Flex Application startup event order).
addEventListener(FlexEvent.APPLICATION_COMPLETE, onApplicationComplete);
The whole init method should look like this:
private function init():void {
addEventListener(FlexEvent.APPLICATION_COMPLETE, onApplicationComplete);
addJSCallback("displayText", displayText);
}
4. Add the event listener method to the Flex widget. We use callLater here to make sure the widget is ready when the event is fired. The method calls the method with the javascript identifier _swf_application_complete, which we will implement soon.
import mx.events.FlexEvent;
private function onApplicationComplete(event:FlexEvent):void {
callLater(function():void {
ExternalInterface.call("_swf_application_complete", swfID);
});
}
The complete Flex widget should look like this by now:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="init()"
backgroundColor="0xffffff" paddingBottom="0" paddingLeft="0"
paddingRight="0" paddingTop="0">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
public function displayText(text:String):void {
textWidget.text = text;
}
private function init():void {
addEventListener(FlexEvent.APPLICATION_COMPLETE, onApplicationComplete);
addJSCallback("displayText", displayText);
}
private function onApplicationComplete(event:FlexEvent):void {
callLater(function():void {
ExternalInterface.call("_swf_application_complete", swfID);
});
}
public static function addJSCallback(jsFunctionName:String, flexFunction:Function):void {
try {
if (ExternalInterface.available) {
ExternalInterface.addCallback(jsFunctionName, flexFunction);
}
} catch (error:SecurityError) {
trace("Couldn't add javascript callback: " + error);
}
}
public function get swfID():String {
return Application.application.parameters.swfid;
}
]]>
</mx:Script>
<mx:Text id="textWidget" width="100%"/>
</mx:Application>
5. Build the Flex project and copy the generated .swf file into the GWT project. It should be under the 'public' folder below the folder that contains the .gwt.xml file, e.g. in my case as 'src/de/larsgrammel/blog/flexgwt/public/Test.swf'.
That's it on the Flex side. On the GWT side, we need to keep track of the different widgets and their swf id's so we can forward the event to the right widget.
6. Create a static map that enables us to find the GWT wrapper for a given swf id:
private static Map<String, SampleFlexWrapperWidget> swfWidgets = new HashMap<String, SampleFlexWrapperWidget>();
7. Register the widget in the map when loaded and deregister it when unloaded:
@Override
protected void onLoad() {
super.onLoad();
SampleFlexWrapperWidget.swfWidgets.put(getSwfId(), this);
}
@Override
protected void onUnload() {
SampleFlexWrapperWidget.swfWidgets.remove(getSwfId());
super.onUnload();
}
Now we can add the methods that are called from Flex.
8. Create a class initializer that calls a JSNI method to register the callback methods. That way, the first time one of our wrapper widgets gets created (i.e. the class is loaded), our callback method is registered.
static {
registerCallbackMethods();
}
9. Create the JSNI method that links a Java method to the callback point '_swf_application_complete':
private static native void registerCallbackMethods() /*-{
$wnd._swf_application_complete=
@de.larsgrammel.blog.flexgwt.client.SampleFlexWrapperWidget::onSwfApplicationComplete(Ljava/lang/String;);
}-*/;
10. Add the method that routes the event to the correct wrapper and calls fireSWFWidgetReady on that wrapper:
public static void onSwfApplicationComplete(String swfId) {
swfWidgets.get(swfId).fireSWFWidgetReady();
}
We need a special event and handler on the GWT. So lets create those and the related methods in the wrapper.
11. Create SWFWidgetReadyEvent and SWFWidgetReadyHandler
package de.larsgrammel.blog.flexgwt.client;
import com.google.gwt.event.shared.GwtEvent;
public class SWFWidgetReadyEvent extends GwtEvent<SWFWidgetReadyHandler> {
public static final Type<SWFWidgetReadyHandler> TYPE = new Type<SWFWidgetReadyHandler>();
private SampleFlexWrapperWidget swfWidget;
public SWFWidgetReadyEvent(SampleFlexWrapperWidget swfWidget) {
assert swfWidget != null;
this.swfWidget = swfWidget;
}
@Override
protected void dispatch(SWFWidgetReadyHandler handler) {
handler.onSWFWidgetReady(this);
}
@Override
public Type<SWFWidgetReadyHandler> getAssociatedType() {
return TYPE;
}
public SampleFlexWrapperWidget getSWFWidget() {
return swfWidget;
}
}
package de.larsgrammel.blog.flexgwt.client;
import com.google.gwt.event.shared.EventHandler;
public interface SWFWidgetReadyHandler extends EventHandler {
void onSWFWidgetReady(SWFWidgetReadyEvent event);
}
12. Add a method to register a SWFWidgetReadyHandler in the wrapper class - make sure to return the HandlerRegistration so the
listener can be remove if needed:
public HandlerRegistration addSWFWidgetReadyHandler(
SWFWidgetReadyHandler handler) {
return addHandler(handler, SWFWidgetReadyEvent.TYPE);
}
13. Implement the fireSWFWidgetReady method:
private void fireSWFWidgetReady() {
fireEvent(new SWFWidgetReadyEvent(this));
}
The whole SampleFlexWrapperWidget should look similar to this by now:
package de.larsgrammel.blog.flexgwt.client;
import java.util.HashMap;
import java.util.Map;
import pl.rmalinowski.gwt2swf.client.ui.SWFWidget;
import com.google.gwt.event.shared.HandlerRegistration;
public class SampleFlexWrapperWidget extends SWFWidget {
private static Map<String, SampleFlexWrapperWidget> swfWidgets = new HashMap<String, SampleFlexWrapperWidget>();
static {
registerCallbackMethods();
}
private static native void _displayText(String swfID, String text) /*-{
$doc.getElementById(swfID).displayText(text);
}-*/;
public static void onSwfApplicationComplete(String swfId) {
swfWidgets.get(swfId).fireSWFWidgetReady();
}
private static native void registerCallbackMethods() /*-{
$wnd._swf_application_complete=
@de.larsgrammel.blog.flexgwt.client.SampleFlexWrapperWidget::onSwfApplicationComplete(Ljava/lang/String;);
}-*/;
public SampleFlexWrapperWidget(int width, int height) {
super("flexgwtintegration/Test.swf", width, height);
addFlashVar("swfid", getSwfId());
}
public HandlerRegistration addSWFWidgetReadyHandler(
SWFWidgetReadyHandler handler) {
return addHandler(handler, SWFWidgetReadyEvent.TYPE);
}
public void displayText(String text) {
_displayText(getSwfId(), text);
}
private void fireSWFWidgetReady() {
fireEvent(new SWFWidgetReadyEvent(this));
}
@Override
protected void onLoad() {
super.onLoad();
SampleFlexWrapperWidget.swfWidgets.put(getSwfId(), this);
}
@Override
protected void onUnload() {
SampleFlexWrapperWidget.swfWidgets.remove(getSwfId());
super.onUnload();
}
}
14. In the client code that uses the widget, we can now disable our control widgets by default and then enable them once the Flex widgets are ready:
nameField.setEnabled(false);
sendButton.setEnabled(false);
flexWidget.addSWFWidgetReadyHandler(new SWFWidgetReadyHandler() {
@Override
public void onSWFWidgetReady(SWFWidgetReadyEvent event) {
nameField.setEnabled(true);
sendButton.setEnabled(true);
}
});
I refactored the client code a bit. It now adds two similar Flex wrappers including controls by calling a addFlexWidgetAndGWTControls method. I also removed the automatic text focus - you would need to decide for one of those controls to get the focus for this to work properly. The client code looks like this:
package de.larsgrammel.blog.flexgwt.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
public class FlexGWTIntegration implements EntryPoint {
public void onModuleLoad() {
addFlexWidgetAndGWTControls();
addFlexWidgetAndGWTControls();
}
private void addFlexWidgetAndGWTControls() {
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
nameField.setEnabled(false);
sendButton.setEnabled(false);
final SampleFlexWrapperWidget flexWidget = new SampleFlexWrapperWidget(
100, 50);
RootPanel.get().add(nameField);
RootPanel.get().add(sendButton);
RootPanel.get().add(flexWidget);
class MyHandler implements ClickHandler, KeyUpHandler {
public void onClick(ClickEvent event) {
displayTextInFlex();
}
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
displayTextInFlex();
}
}
private void displayTextInFlex() {
flexWidget.displayText(nameField.getText());
}
}
// Add a handler to send the name to the server
MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
flexWidget.addSWFWidgetReadyHandler(new SWFWidgetReadyHandler() {
@Override
public void onSWFWidgetReady(SWFWidgetReadyEvent event) {
nameField.setEnabled(true);
sendButton.setEnabled(true);
}
});
}
}
With this approach, your GWT controls should be disabled until the Flex widgets are completely loaded - and it should work with multiple Flex widgets. More on integrating Flex and GWT will be covered in future posts, so stay tuned.
Bridging Lightweight and Heavyweight Task Organization: The Role of Tags in Adopting New Task Categories
Our submission to the NIER (New Ideas and Emerging Results) track at ICSE 2010 has been accepted!
In this paper, Peggy and I explore the idea that the use of tags in task management systems could lead to the introduction of new task categories. This research was prompted by the observation that the software development team in one of our Jazz case studies used tags such as linux and windows to indicate that a particular task was specific to an operating system. During the replication of our study a year later, we observed that the team didn’t use these tags anymore, instead the category Operating System had been made a field in every task.
Looking at this phenomenon in more detail, we found that there were other instances: Tags such as testing and selfhosting had been replaced by a How Found category, and tags such as eclipse, firefox and ie had been replaced by a Client category.
Based on these preliminary insights, we pose the following research questions:
RQ How can tagging play a role in bridging lightweight task management and heavyweight task management?
- What role do tags play in the adoption of new task categories?
- How can data on the use of tags help determine the right balance between lightweight and heavyweight task organization?
- How is software developers’ use of tags for task organization different from the tag use of users outside of software development?
We have focused on the first sub question for the NIER paper, but the positive comments from our reviewers encouraged us to keep working on this research. Looking beyond Jazz, a very interesting case is given by the way labels are implemented in Google Code (see: http://code.google.com/p/support/wiki/IssueTracker#Labels). Their concept of labels is similar to social tagging in other task management systems. However, the Google Code issue tracker goes beyond basic labels to support key-value labels. Key-value labels contain one or more dashes, and the part before the first dash is considered to be a field name while the part after that dash is considered to be the value. For each project, a list of predefined labels and their meaning can be specified. Studying how developers make use of this approach is on top of our to-do list.
This is the preliminary abstract of our NIER paper:
In collaborative software development projects, tasks are often used as a mechanism to coordinate and track shared development work. Modern development environments provide explicit support for task management where tasks are typically organized and managed through predefined categories. Although there have been many studies that analyze data available from task management systems, there has been relatively little work on the design of task management tools. In this paper we explore how tagging with freely assigned keywords provides developers with a lightweight mechanism to further categorize and annotate development tasks. We investigate how tags that are frequently used over a long period of time reveal the need for additional predefined categories of keywords in task management tool support. Finally, we suggest future work to explore how integrated lightweight tool features in a development environment may improve software development practices.

If you’re not on Twitter, you’re missing half the conversation
Traditionally the Eclipse community has used the mailing lists, newsgroups and an aggregation of blogs to stay connected. Mailing lists and newsgroups have generally been more technical, while the blog-o-sphere has everything from tutorials to highly opinionated views. Over the past year and a half, many of those in the Eclipse Community have also emerged on Twitter.
We have used twitter for Bug reporting, bug triaging, blowing off steam, tracking down committers — and we even organized our Movember team through the social medium. Twitter takes some getting used to, but once you get the hang of it, it can be a valuable way to stay connected. I’ve been using twitter for about a year now. Here are a few tips if you’re just getting started:
- Post some content before you start following people. You can post the typical: I’m just figuring out twitter. But follow it up with a few interesting posts — ideally about something you care about.
- Follow your friends first. It’s good to follow some people who will follow you back… Once you get some people listening, others will follow you too.
- Get a good twitter client. I personally like http://brizzly.com/. I hear there are very good clients for the Mac.
- Follow people (and topics) that you find interesting. In the Eclipse ecosystem, there is a lot of activity on twitter.
- Once on, Re-tweet and Reply to things you find interesting…. i.e. Join the conversation
If you’re interested in Eclipse and are looking for people to follow, check our twitter wiki page, or look at wefollow.com.
Peter Friese also has a great post on why he uses Twitter. I really like his suggestion Don’t protected your posts. If you’re worried about privacy, just be mindful of what you write!
Note: Yesterday Google announced ‘Google Buzz‘, which some are calling ‘What Twitter Should Be’. While Buzz may take down twitter, likely it just means one more stop in my daily commute (E-mail, twitter, blogs… now buzz).
AP2 API
As I mentioned a while back, Eclipse Helios M5 was made available for Download. There are number of New and Noteworthy features, but one really big feature was omitted from the N&N. The Eclipse provisioning platform, p2, finally has API! Really, go take a look at the code… all those internal.provisional packages are now gone! This was actually a huge milestone for the p2 team, and Pascal did a great job steering us towards the API.
What does this mean to you? Well, if you are building anything on top of p2 you should grab M5 and see how the new API feels. We are going to be pushing hard to finalize the API for M6, so if there is anything missing, speak up now.
John Arthorne even started a Migration guide: http://wiki.eclipse.org/Equinox/p2/Helios_Migration_Guide
GWT Wrapper for Flex components
This tutorial is the first part of a series of blog posts about using Flex components in GWT with the library gwt2swf:
1. GWT Wrapper for Flex components (this tutorial)
2. Notifying GWT when a Flex widget is loaded
I will explain how to create a GWT adapter around a Flex component that enables calling Flex from GWT. The code will use the library gwt2swf. This post will be pretty strait forward and matches the gwt2swf docs for most part, but will include sample GWT and Flex code. Essentially, I will create a subclass of SWFWidget (part of gwt2swf) that wraps all the Flex specifics and can be used from GWT. This approach enables the use of several swf widgets from GWT at the same time.
To create a sample Flex component, I used the following steps:
1. Create a new Flex Project (e.g. in Flex Builder)
2. Add a creationComplete handler (here: init) to the mxml header
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="init()">
3. Remove the padding from the Flex component & set the background color in the mxml header
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="init()"
backgroundColor="0xffffff"
paddingBottom="0" paddingLeft="0"
paddingRight="0" paddingTop="0">
4. Add the init method and a addJsCallback method with code that I shamelessly stole from my colleague Chris Callendar, who helped me getting this to work and who has an awesome Flex blog, http://flexdevtips.blogspot.com/.
public static function addJSCallback(jsFunctionName:String, flexFunction:Function):void {
try {
if (ExternalInterface.available) {
ExternalInterface.addCallback(jsFunctionName, flexFunction);
}
} catch (error:SecurityError) {
trace("Couldn't add javascript callback: " + error);
}
}
5. Add a text field to the flex component as an example element. We will change the contents of the text field from GWT. The width is set to 100%, so that the widget resizes based on the surrounding HTML element. For other widgets, e.g. a table, you might want to set the height to 100% as well.
<mx:Text id="textWidget" width="100%"/>
6. Add a displayText function and register it as a callback for JavaScript access under the name "displayText" in the init() method.
public function displayText(text:String):void {
textWidget.text = text;
}
private function init():void {
addJSCallback("displayText", displayText);
}
7. The complete .mxml file should look similar to this by now:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="init()"
backgroundColor="0xffffff" paddingBottom="0" paddingLeft="0"
paddingRight="0" paddingTop="0">
<mx:Script>
<![CDATA[
public function displayText(text:String):void {
textWidget.text = text;
}
private function init():void {
addJSCallback("displayText", displayText);
}
public static function addJSCallback(jsFunctionName:String, flexFunction:Function):void {
try {
if (ExternalInterface.available) {
ExternalInterface.addCallback(jsFunctionName, flexFunction);
}
} catch (error:SecurityError) {
trace("Couldn't add javascript callback: " + error);
}
}
]]>
</mx:Script>
<mx:Text id="textWidget" width="100%"/>
</mx:Application>
8. Build the Flex project and copy the generated .swf file into the GWT project. It should be under the 'public' folder below the folder that contains the .gwt.xml file, e.g. in my case as 'src/de/larsgrammel/blog/flexgwt/public/Test.swf'
That's it on the Flex side. Here is the list of steps I followed on the GWT side:
1. Download gwt2swf from http://sourceforge.net/projects/gwt2swf/ (I use version 0.6.0 in the example presented here)
2. Extract the gwt2swf.jar and add it project's buildpath
3. Add gwt2swf to your project's .gwt.xml file:
<inherits name='pl.rmalinowski.gwt2swf.GWT2SWF' />
4. Create a subclass of SWFWidget (here: SampleFlexWrapperWidget) that sets swf file by specifying the swf source path in the constructor call. The first part of the swf source path is the module name, the rest the path below the 'public' directory including the .swf name.
public SampleFlexWrapperWidget(int width, int height) {
super("flexgwtintegration/Test.swf", width, height);
}
5. Add a displayText method to that class as a public interface on the Java side. This method calls a private static native method that resolves the SWF DOM element and calls the exposed Flex method:
private static native void _displayText(String swfID, String text) /*-{
$doc.getElementById(swfID).displayText(text);
}-*/;
public void displayText(String text) {
_displayText(getSwfId(), text);
}
6. The wrapper should look similar to this by now:
public class SampleFlexWrapperWidget extends SWFWidget {
private static native void _displayText(String swfID, String text) /*-{
$doc.getElementById(swfID).displayText(text);
}-*/;
public SampleFlexWrapperWidget(int width, int height) {
super("flexgwtintegration/Test.swf", width, height);
}
public void displayText(String text) {
_displayText(getSwfId(), text);
}
}
7. The wrapper can now be used in GWT, e.g. in the entry point class:
public class FlexGWTIntegration implements EntryPoint {
public void onModuleLoad() {
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
final SampleFlexWrapperWidget flexWidget1 = new SampleFlexWrapperWidget(100, 50);
final SampleFlexWrapperWidget flexWidget2 = new SampleFlexWrapperWidget(100, 50);
RootPanel.get().add(nameField);
RootPanel.get().add(sendButton);
RootPanel.get().add(flexWidget1);
RootPanel.get().add(flexWidget2);
nameField.setFocus(true);
nameField.selectAll();
class MyHandler implements ClickHandler, KeyUpHandler {
public void onClick(ClickEvent event) {
displayTextInFlex();
}
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
displayTextInFlex();
}
}
private void displayTextInFlex() {
flexWidget1.displayText(nameField.getText());
flexWidget2.displayText(nameField.getText() + " 2nd version");
}
}
MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
}
}
Using this approach, you can use the SWF wrapper inside GWT like any other GWT widget, except for a small loading delay. I will explain how to deal with delayed loading, events from Flex and others integration issues in future blog posts - stay tuned.
Image CheckBox and RadioButton
The main property to set is imageSource which acts just like the Image.source property.
The image position depends on the labelPlacement property (left, right, top, bottom) and the horizontalGap style.
You can also set the imageWidth and imageHeight properties to scale the image down. If you only set one of those properties then the other one is calculated to keep the image's width and height ratio the same.
Note that the ImageCheckBox actually extends my flex.utils.ui.CheckBox class and not the expected mx.controls.CheckBox class.
The flex.utils.ui.CheckBox class supports backgroundColor and backgroundAlpha styles, and as a result the background is always painted. But the default alpha value is 0, so usually you won't see the background unless you set the background color and alpha. The reason for this is that the default mx.controls.CheckBox class has a gap between the checkbox icon and the label (which is the horizontalGap style). This gap causes mouse out events to fire when your cursor moves from the icon or label into this gap. As a result the checkbox tooltip will disappear, and the checkbox will not have the rollover styles. So by painting an invisible background color over the whole area of the checkbox this problem doesn't occur. Same thing applies with the RadioButton class.
The Perils of Multi-Platform Eclipse Development
So, here is my problem. I have a plug-in that has a little bit of platform-specific code in it. The code works on both windows and linux, and I have precompiled binaries for them. In other words, the build of the (C++) native code doesn't need to be part of my build process. I do that separately just because it is easier. Setting up cross-compilers is a nightmare, and takes more time than I have.
So, here is what I do: I separate my native code into plug-in fragments for windows and for linux. After that, I have to go through all of my different manifests to make sure that P2 knows what to do with the the fragments. First, a p2.inf file has to be made for each fragment and the host plug-in, so that P2 knows the fragments are installable units that should be downloaded. OK, that's fine. Then, I have to the feature.xml for the feature that contains my plugins and fragments to make sure that I specify the supporting environments:

OK, then I have to set up my fragments to make sure that the platform filters match their target environment:

Platform filters are basically read as a functional notation, where sets of attributes are bound to operators. For example, (|(osgi.arch=x86)(osgi.arch=x86_64)) binds the selection of the attributes (osgi.arch=x86 and osgi.arch=x86_64) to the logical OR operator (|), so that it reads, "the osgi architecture can be either x86 or x86_64." So, I've got that down. I also had to set up the Bundle-NativeCode attribute in the manifest for the fragment so that my application knows where to find the binaries, but I'll get back to that later.
OK, now one might expect that everything is ready to export. After all, the binaries don't depend on any native Eclipse fragments (they don't reference SWT or anything). So, it seems that my fragments should be able to be packaged up just like anything else.
That's not the case however. When you run a build in PDE, and you put a platform filter on a fragment, Eclipse checks your current target platform and builds only for what you currently have. I, for example, have a machine with Windows XP on it, and that is the version of Eclipse that I downloaded. So, Eclipse will build only the windows fragment for me. There is no option to build for other platforms. If I use the Export Deployable Features wizard, this is what I get:

Even though my fragments don't have any dependencies on any other platform-specific code and all I really need is a jar with my binaries in it, the PDE says, "No! I can't build that for you." OK, that's fine. I know that it is possible to build for multiple platforms (the SWT guys do it), so I did some searching.
It turns out that what I need is something called the Eclipse Delta Pack. The Delta Pack is basically a bunch of fragments for different platforms which include native code for user interfaces and other i/o such as file manipulation. Getting the Delta Pack can transform your Eclipse workbench into a catch-all platform which targets everything that Eclipse can manage.
The unfortunate thing is that the Delta Pack isn't that easy to find. If you go to the Eclipse Download page, you won't find any reference to it. You have to go down to the bottom of the page, and find the Classic Eclipse distribution. And select Other Downloads:

Once there, you will want to get the release that you are targeting (probably somewhere in the 3.5.1 stream or later), and look to the left-hand menu. You will find the Delta Pack there:

Or, you can follow this link for the 3.5.1 drop.
When you download the Delta Pack, you have to unpack it. Make sure that you don't unpack it over your current Eclipse install. That could make things go bad. Instead, unpack it somewhere else and you can tell Eclipse to add it to your target platform.
To do that, go to your Eclipse Preferences, and find the page for Target Platform, select the running platform, and Add the Delta Pack to it as an Eclipse Install:

After that's done, you will have a new magic option in your Export Deployable Features wizard called Export for multiple platforms. That's exactly what I was looking for!

So, one would think at this point that one could simply export all of the features, upload them to a P2 repository, and release the new version. Not so fast. If you are me and you do that, you get this bug report.
It was silly of me. I shouldn't have assumed that the build would work flawlessly without testing. So, I checked my P2 repository, and low-and-behold, the Linux fragment was missing. That seemed strange. After all I did export for Linux. There's no rocket science here. It's just a pre-compiled binary after all.
So, after hours of fighting with trying different combinations of platform filters, and different ways of building, there were no warnings and no errors in the build. Unfortunately, there was also no Linux fragment. It just would not get created on my windows box. I was about to go and file a bug on P2, when I decided that maybe I should just try to get the build on Linux. So, I went through all the above steps again on a fresh install of Eclipse on a Linux machine. What I expected to happen was that it would build fine on the Linux machine, but instead of not having a Linux fragment, I would be left without a windows fragment.
That isn't what happened. I did get a windows fragment. What was missing? You guessed it: the Linux fragment! My Linux machine failed to build the Linux fragment. But, at least I got an error this time:

It looks like there was something about my Bundle-NativeCode property in the Linux fragment which the PDE build system didn't like. So, I went to investigate it.
I had used native code previously in an RCP toy application in which I was experimenting with OpenGL. When I looked up how to do it at that time, I learnt that I was supposed to use various keys such as processor= and os= to tell the plug-in when to use different compiled libraries. In fact, that is what I used in previous versions of Diver. When both the Windows and Linux binaries were in one fragment, it worked fine. But apparently, now that I had them in two fragments, that was very, very wrong:

I didn't really know what to do, though since this is what I had read was correct, and it was previously working. In fact it still works for the different Windows versions. Not for Linux, though. I don't know why. So, after another hour or so on Google, I learned about the key selection-filter which works in the same way that the Eclipse-PlatformFilter does. So, I copied my platform filter into the Bundle-NativeCode like this:

And it works! So, I learned a few things from this whole process:
- You Need The Delta Pack. Why you need it for all multi-platform builds, I don't know. In my example, all I needed was to package up pre-compiled binaries into jar files. There doesn't need to be any dependency resolution for that, but the PDE needs the Delta Pack to do the build. That is relatively painless, so I don't mind.
- Pay Attention to the Bundle-NativeCode Format. Eclipse won't necessarily tell you what is wrong. It might just fail to build a fragment or two without you even noticing. The safest way to get it to work just seems to be to copy your Eclipse-PlatformFilter directly into the Bundle-NativeCode property. At least you don't have to manage multiple different syntaxes that way.
Anyway, that is all for now. I hope this can be helpful to anyone who is doing builds for multiple platforms. It isn't an easy problem to solve, so there are bound to be pain points. This post will hopefully get you (and me) through them quickly next time.
Diver 0.1.0 Released (For Real This Time)

If you downloaded for Windows last week, I think that you should be fine. But, there won't be any harm in updating.
Eclipse 3.6 M5 (Helios) available for download
Eclipse 3.6 M5 is now available for download. There are lots of new and exciting features, like the ability to open and file directly from the command line. You can also use the synchronize view to compare patches:
Debug also introduced a few new features (like instance counts):
Check out all the new features in the New and Noteworthy.
Download the milestone:
http://download.eclipse.org/eclipse/downloads/drops/S-3.6M5-201001291300/index.php
or use p2 to upgrade to it:
http://download.eclipse.org/eclipse/updates/3.6milestones/
Drawing Dashed Lines, Arcs, and Cubic Curves
I've created a sample application that shows the three line types: straight, quadratic curve and cubic curve. It also lets you choose between showing a solid line, a dashed line, or both. The line thickness can also be adjusted.
I also got a little carried away and added the quadratic and cubic control points as buttons that you can drag around the canvas to change the curve.
Most of the drawing functionality for these examples is in the GraphicsUtils.as class that contains the following static functions:
- drawLine() - draws a straight line, either solid (using Graphics.lineTo() function) or dashed
- drawQuadCurve() - draws a quadratic curve, either solid (using Graphics.curveTo() function) or dashed
- drawCubicCurve() - draws a cubic curve (two control points), either solid or dashed. The curve is an approximation done by dividing the curve into many small segments and drawing straight lines
- drawCircle() - draws a circle, either solid (using Graphics. drawCircle() function) or dashed
- drawArc() - draws an arc, either solid or dashed
The equations used to calculate the values at any point along the line for the three cases were found on the Wikipedia entry for Bézier curves.






