Who’s On Phirst

Official blog of Phurnace Software.

Shawn Spiars's Blog
Description:
Shawn Spiars is the Lead User Interface Designer and Developer for the Phurnace Deliver product. Shawn specializes in Eclipse Rich Client Platform and plug-in development.
He has over 20 years of application development experience ranging from mainframe programming, DB2 Database Administration, Quality Assurance,
Java Swing Programming, and User Interface Developer. His career has included working for various technology companies including BMC, Evoke, Rocket,
Pervasive, and Phurnace.

Posted by: Shawn Spiars on

From time to time I visit the Eclipse news groups to find a solution to a problem I am having with a particular area of Eclipse. Since Eclipse is such a huge platform with many projects there are many different news groups, each designed to cover a particular project or API (Application Programming Interface).

Some of my favorite Eclipse news groups are:

eclipse.platform
eclipse.platform.rcp
eclipse.platform.swt

Often while I am looking for answers in a news group I run across questions that I have already conquered and so I try to give back and help others. Recently I responded to a question about how to perform in-line editing within the cell of an SWT (Standard Widget Toolkit) table. I have included my example java program below. If you are a Java developer and somewhat familiar with SWT/JFace then you should have no problems understanding the example code. If you are new to SWT/JFace I have provided a brief summary of the primary components used to create the example.

Looking at the java code below you will see that the program contains a main method to launch the java program. The primary UI component is an SWT Table which is added to an SWT Composite. Under the table I have added SWT buttons to “Add” and “Remove” rows from the table. The SelectionListeners on the buttons handle the add and remove actions. The model for the table is a POJO (Plain Old Java Object) which I have named “Row”. A TableContentProvider and TableLabelProvider provide the content and labels for the table and the TextCellEditor provides the ability to edit the table allowing a user to type data directly into the table’s cells.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

/**
* This is an example program showing how to use a TableCellEditor
* to allow direct editing of a table's cell.
*
* @author Shawn Spiars
*
*/

public class TableCellModifierExample {

private Table table;
private TableViewer tableViewer;

private final static String[] COLUMN_HEADINGS = {"Property",
"Value"}
;

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

public TableCellModifierExample() {
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setText("TableCellModifier Example");
shell.setLayout(new FillLayout());

createContents(shell);

shell.setSize(400, 400);
shell.open();

while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}

protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
layout.verticalSpacing = 10;
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
composite.setLayoutData(data);

table = new Table(composite, SWT.BORDER | SWT.V_SCROLL
| SWT.MULTI | SWT.FULL_SELECTION);
table.setLinesVisible(true);
table.setHeaderVisible(true);
data = new GridData(SWT.FILL, SWT.FILL, true, false);
data.heightHint = 300;
table.setLayoutData(data);

TableLayout tableLayout = new TableLayout();
table.setLayout(tableLayout);

tableLayout.addColumnData(new ColumnWeightData(10, 100,
true));
TableColumn column = new TableColumn(table, SWT.NONE);
column.setText(COLUMN_HEADINGS[0]);
column.setAlignment(SWT.LEFT);

tableLayout.addColumnData(new ColumnWeightData(15, 200,
true));
column = new TableColumn(table, SWT.NONE);
column.setText(COLUMN_HEADINGS[1]);
column.setAlignment(SWT.LEFT);

tableViewer = new TableViewer(table);
tableViewer.setColumnProperties(COLUMN_HEADINGS);
tableViewer.setContentProvider(new
TableContentProvider());
tableViewer.setLabelProvider(new TableLabelProvider());

CellEditor[] editors = new CellEditor[2];
editors[0] = new TextCellEditor(table);
editors[1] = new TextCellEditor(table);
tableViewer.setCellEditors(editors);
tableViewer.setCellModifier(new TableCellModifier());

Composite buttonComposite = new Composite(composite,
SWT.NONE);
FillLayout fillLayout = new FillLayout(SWT.HORIZONTAL);
fillLayout.spacing = 10;
buttonComposite.setLayout(fillLayout);

Button addButton = new Button(buttonComposite,
SWT.PUSH);
addButton.setText("Add");
addButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Row row = new Row("", "");
tableViewer.add(row);
table.setTopIndex(table.getItemCount());
table.select(table.getItemCount()-1);
tableViewer.editElement(row, 0);
}
});

Button removeButton = new Button(buttonComposite,
SWT.PUSH);
removeButton.setText("Remove");
removeButton.addSelectionListener(new
SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection =
tableViewer.getSelection();
if (selection instanceof
IStructuredSelection) {
Iterator iterator =
((IStructuredSelection)selection).iterator();
while(iterator.hasNext()) {
Object obj = iterator.next();
tableViewer.remove(obj);
}
}
}
});

return composite;
}

public class TableLabelProvider extends LabelProvider
implements
ITableLabelProvider {
public Image getColumnImage(Object element, int
columnIndex) {
return null;
}

public String getColumnText(Object element,
int columnIndex) {
Row row = (Row) element;

switch
(columnIndex) {
case 0:
return row.getKey();
case 1:
return row.getValue();
}

return null;
}

}

public class TableContentProvider implements
IStructuredContentProvider {
public Object[] getElements(Object parent) {
List results = new ArrayList();
if (parent instanceof ArrayList) {
results = (ArrayList) parent;
}
return results.toArray();
}

public void dispose() {
}

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

}

class TableCellModifier implements ICellModifier {

public boolean canModify(Object element,
String property) {
return true;
}

public Object getValue(Object element,
String property) {
Object result = null;

Row row = (Row) element;

List list = Arrays.asList(COLUMN_HEADINGS);
int columnIndex = list.indexOf(property);

switch (columnIndex) {
case 0:
result = row.getKey();
break;
case 1:
result = row.getValue();
break;
}

return result;
}

public void modify(Object element, String property,
Object value) {
List list = Arrays.asList(COLUMN_HEADINGS);
int columnIndex = list.indexOf(property);

TableItem tableItem = (TableItem) element;
Row row = (Row) tableItem.getData();

switch (columnIndex) {
case 0:
String key = (String) value;
if (key.length() > 0) {
row.setKey(key);
}
break;

case 1:
String v = (String) value;
if (v.length() > 0) {
row.setValue(v);
}
break;
}
tableViewer.update(row, null);
}

}

private class Row {
private String key;
private String value;

public Row(String key, String value) {
setKey(key);
setValue(value);
}

public void setKey(String key) {
this.key = key
}

public String getKey() {
return key;
}

public void setValue(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}

}

In SWTJFaceSWTStandard Widget ToolkitEclipse
Comment (0) Read More...


Posted by: Shawn Spiars on

It seems like there are more visual GUI builder products available on the market today than ever before. Visual GUI builders propose an easier way to design and create user interface components. They usually consist of a palette from which you select and drag controls or widgets onto a window, frame, or dialog. Then they provide a table or list where you can manipulate the properties of your controls (size, font, color, coordinates, etc) without requiring the user to know the subtleties’ of the syntax or layout managers. Here is a really good link if you are interested in Java GUI Builders.

Call me old fashion, but I always prefer a language editor (HTML, XML, Java, etc…) over a visual editor because I want to understand the commands I write, and I want to format and organize the code in a way that is meaningful to me so I can easily edit the code later. A good language editor will have syntax highlighting, syntax checking, command completion and various other features to assist you in developing the code, but it won’t generate the substance of the code for you.

Another type of code generation tool falls into the Model Driven Development (MDA) category. With MDD, logical models are used to capture design decisions and generate code, and sometimes the generated code is user interface code. The problem I have with user interfaces generated from models is that there is no consideration by the machine for who the user is, their technical aptitude, or the way they approach a task (workflow). The entire human experience is missing and the user interface has been reduced to a bunch of domain objects and business rules.

For example, the Eclipse Modeling Framework (EMF) can use a model to quickly generate a cool looking prototype consisting of a relational tree, object listeners, pop-up menus, and a properties view, but this in no way resembles a complex, well designed, user friendly application. And don’t be fooled into thinking you can easily tweak the generated code to get it to behave the way you want it to. I’ve spent hours and hours digging thru layers and layers of cryptic machine generated code trying to find the one line that needs to be changed to get the desired behavior.

There are plenty of MDD advocates out there who will disagree with me. Most of them are experts in modeling, but I’ve never met one who is an expert in user interface design. Since most project leads and architects today are very familiar with UML and modeling tools they often buy into the promise that MDD will save them time on their UI development. This has not been my experience.

If you do choose to use a modeling tool to generate UI code – I recommend you decouple the UI model from the back-end model. Just imagine a project where every time the back-end architect decides to change a relationship in the model the UI mysteriously breaks with no warnings.

“And that’s all I have to say about that.”

-Shawn

In Java GUIEclipse
Comment (0) Read More...


Posted by: Shawn Spiars on

When I started working with Eclipse in 2003 I would just download the plug-ins I needed from the Eclipse website, unzip them into my plugins directory, and restart Eclipse. Sometime later, the Eclipse Update Manager was introduced to help you configure your Eclipse development environment providing the ability to update your existing features and plug-ins and search for new features. I have always found the Update Manager dialogs difficult to understand and use. Customizing the Update Manager to work with my Rich Client Platform (RCP) applications has also been very difficult.

When I heard about the new Equinox p2 provisioning system at EclipseCon this year I was excited that the Update Manager was finally being replaced. However, one thing I have learned when working with Eclipse is to take a “wait and see” approach before adopting the newest and improved APIs and methodologies. So, I have been reading various blogs to see what experiences developers are having implementing p2 in their products. Here are a couple of postings that make me think that p2 may not be quite ready for prime time:

Why Eclipse Equinox P2 Update Manager Sucks

Why Eclipse Equinox P2 Update Manager is not good enough for me yet #2

If you have had a positive experience replacing Update Manager functionality with p2 in your software product I would love to hear about it.

-Shawn

 

In Eclipse
Comment (0) Read More...


Posted by: Shawn Spiars on

There are quite a few toolkits available for Java developers. Let me help point you in some directions and maybe save you some research time.

Many of you will be familiar with the Abstract Windows Toolkit (AWT) that is available with every Java Runtime Environment (JRE). AWT is the original Java GUI toolkit developed by Sun Microsystems. AWT is a peer-based toolkit meaning that each AWT control is dependent upon a host operating system control. AWT usage is limited because it was designed to only support controls which are available in all Java host environments. For example, AWT does not support Trees and Tables.

Swing is another Java GUI toolkit developed by Sun Microsystems and was designed to work with AWT and is built on top of AWT components. Unlike AWT, most Swing controls are emulated. This emulation makes user interfaces written in Swing portable across all operating systems and supports Sun’s “write-once, run anywhere” motto. One disadvantage to Swing is that the emulated controls often don’t result in a native looking application. Swing’s answer to this problem is provided by look-and-feel emulators that attempt to change the appearance and behavior of their components to adapt to a particular operation system or theme. Another disadvantage to Swing is that the emulated controls tend to run slower than peer-based controls.

The Standard Widget Toolkit (SWT) is another peer-based GUI toolkit. IBM designed SWT to solve some of the problems that have limited the usage of AWT. SWT provides a different Java implementation for each operating system platform using Java Native Interface (JNI) calls. One disadvantage for SWT is that developers are required to dispose of OS-dependent objects within their application code.

JFace is a GUI library that was developed to compliment SWT and simplify common GUI programming tasks. SWT and JFace libraries are used extensively throughout the Eclipse IDE.

As a Java user interface developer I have used each of these GUI libraries and I find the combination of SWT/JFace my favorite choice because of the native look-and-feel of the components. I also find the SWT and JFace APIs cleaner and easier to develop with than AWT and Swing. My two cents, comments welcome.

In Java GUI ToolkitsJava GUIjavaAbstract Windows Toolkit
Comment (0) Read More...


Posted by: Shawn Spiars on

As a software engineer I often find it entertaining reading the technology job postings. You can learn a lot about a company's values and culture by what they reveal in their job postings. I once had a job interview with a VP of Engineering who was bragging to me during the interview about how much money he saved his company by sending half of his development positions offshore. So I am thinking to myself "if I take this job just how long until my position goes offshore"?

One of my biggest pet peeves is with the postings that say "Entry Level Programmer" and then go on to list detailed requirements that would take 10 to 15 years of experience to accumulate. This type of posting tells me that the company is really cheap and doesn't want to pay for the experience that is required for the position.

Then there are the companies that think they are doing you a big favor by allowing you to Join their world-class team because they are so much smarter than everyone else in the industry. They only hire engineers with advanced degrees and certifications and take great pride in Their superior intellect. A few years ago I had a short stint at one of these companies with "All Chiefs and no Indians". These folks were so smart that it took them over 2 years to get a software release out the door. They just kept arguing about how to do things better and better, and ended up rewriting the same Code over and over again until they ran out of money.

One of the things I like most about working at Phurnace is the "No Punks Allowed" philosophy as Robert likes to phrase it. "No Punks Allowed" basically means we look for people who are mature in how they perform their work and in how they relate to others. It also refers to the notion of egos in check, and a willingness to constructively share ideas and have ideas shared with you. After all it's the quality and character of the people that you work with that makes a job enjoyable or not. So, if you are a developer and you are trying to decide on your next gig, just remember - "No Punks Allowed."

Shawn

In java
Comment (1) Read More...


Posted by: Shawn Spiars on

 Last week I attended the EclipseCon 2008 conference in Santa Clara, CA.  This was my third EclipseCon and by far my best experience.  ThisEclipseCon year there were a lot more technical sessions to choose from and overall the presentations seemed more professional than in the previous years.  I also liked that the Monday tutorials were included in the overall conference registration fee, rather than an extra charge.

I think the highlight of the conference was the key note speech of Dan Lyon (Fake Steve Jobs).   Here's a quote about Dan from the EclipseCon website.

"At his blog, fakesteve.blogspot.com, Lyons has captured the Zeitgeist, from perhaps the one place it is clearest-the point of view of Steve Jobs. In the tradition of Jonathan Swift and The Onion, he uses a pitch-perfect satirical style to deliver trenchant social commentary, reflecting on everything from the Cult of Steve and the rise of Apple ("Dude, I invented the friggin' iPhone. Perhaps you've heard of it!") to the ubiquitous influence of the tech industry on our everyday lives."

Another key note speaker was Sam Ramji, Director of Platform Strategy at Microsoft.   I think of Microsoft as the Borg and their presence at EclipseCon as another strategy to assimilate the Eclipse Community and open source.

The sessions that I found most interesting were those discussing the Rich AJAX Platform (RAP), The Rich Client Platform (RCP), and the Web Tools Platform (WTP).  I particularly enjoyed the "GWT vs RAP" presentation by Mark Russell and Dan Rubel, discussing the differences between Google Web Toolkit (GWT) and Eclipse Rich AJAX Platform (RAP) development.

If you are a software developer I would highly recommend you check out next year's EclipseCon.                 

In Open SourceEclipse
Comment (1) Read More...