Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

Java, the OLPC, and community responsibility

The "One Laptop Per Child" project has a great device ready to ship, but there's no Java on there. Let's think about working together to put Java on OLPC!
Replies: 20 - Pages: 2   [ 1 2 | Next ]
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

Sorting a TableViewer's columns both ways

At 4:01 AM on Dec 12, 2005, Christian Soltenborn Javalobby Newcomers wrote:

Hi,

I was kind of surprised that JFace table sorting doesn't work both ways. I'm sure that there are reasons for this I don't see (I'm not a very experienced GUI programmer), but I thought it must be easy to provide a minimal "framework" for this, and here it is. Feel free to add any comments on how to improve this!

The first class represents an InvertableSorter; it extends the ViewerSorter class:
abstract class InvertableSorter extends ViewerSorter {
	public abstract int compare(Viewer viewer, Object e1, Object e2);
 
	abstract InvertableSorter getInverseSorter();
 
	public abstract int getSortDirection();
}


The second class is the class you have to extend when implementing your sorter. All you have to do is to overwrite the compare(Viewer viewer, Object e1, Object e2) method. I expect that in many cases it's best to extend this class with your own abstract class (see example below).
public abstract class AbstractInvertableTableSorter extends InvertableSorter {
	private final InvertableSorter inverse = new InvertableSorter() {
 
		public int compare(Viewer viewer, Object e1, Object e2) {
			return (-1)*AbstractInvertableTableSorter.this
							.compare(viewer, e1, e2);
		}
 
		InvertableSorter getInverseSorter() {
			return AbstractInvertableTableSorter.this;
		}
 
		public int getSortDirection() {
			return SWT.DOWN;
		}
	};
 
	InvertableSorter getInverseSorter() {
		return inverse;
	}
 
	public int getSortDirection() {
		return SWT.UP;
	}
}


The last class, TableSortSelectionListener, does the actual work. It extends SelectionListener and takes care of event handling. It knows to which column of the table it belongs. Note that in the constructor you can select in which order the column is to be sorted initially, and if the last ordering is to be restored after another column had been selected.
public class TableSortSelectionListener implements SelectionListener {
	private final TableViewer viewer;
	private final TableColumn column;
	private final InvertableSorter sorter;
	private final boolean keepDirection;
	private InvertableSorter currentSorter;
 
	/**
	 * The constructor of this listener.
	 * 
	 * @param viewer
	 *            the tableviewer this listener belongs to
	 * @param column
	 *            the column this listener is responsible for
	 * @param sorter
	 *            the sorter this listener uses
	 * @param defaultDirection
	 *            the default sorting direction of this Listener. Possible
	 *            values are {@link SWT.UP} and {@link SWT.DOWN}
	 * @param keepDirection
	 *            if true, the listener will remember the last sorting direction
	 *            of the associated column and restore it when the column is
	 *            reselected. If false, the listener will use the default soting
	 *            direction
	 */
	public TableSortSelectionListener(TableViewer viewer, TableColumn column,
			AbstractInvertableTableSorter sorter, int defaultDirection,
			boolean keepDirection) {
		this.viewer = viewer;
		this.column = column;
		this.keepDirection = keepDirection;
		this.sorter = (defaultDirection == SWT.UP) ?
			sorter : sorter.getInverseSorter();
		this.currentSorter = this.sorter;
 
		this.column.addSelectionListener(this);
	}
 
	/**
	 * Chooses the colum of this listener for sorting of the table. Mainly used
	 * when first initialising the table.
	 */
	public void chooseColumnForSorting() {
		viewer.getTable().setSortColumn(column);
		viewer.getTable().setSortDirection(currentSorter.getSortDirection());
		viewer.setSorter(currentSorter);
	}
 
	public void widgetSelected(SelectionEvent e) {
		InvertableSorter newSorter;
		if (viewer.getTable().getSortColumn() == column) {
			newSorter = ((InvertableSorter) viewer.getSorter())
					.getInverseSorter();
		} else {
			if (keepDirection) {
				newSorter = currentSorter;
			} else {
				newSorter = sorter;
			}
		}
 
		currentSorter = newSorter;
		chooseColumnForSorting();
	}
 
	public void widgetDefaultSelected(SelectionEvent e) {
		widgetSelected(e);
	}
}


Ok, and here is the example I promised at the beginning :-). There's not too much to say about it, I guess...
public class TableDemo {
 
	private TableDemo() {
		// create shell
		Display display = new Display();
		Shell shell = new Shell(display, SWT.SHELL_TRIM);
		shell.setLayout(new FillLayout());
		shell.setText("TableDemo");
 
		// set up table layout
		TableViewer viewer = new TableViewer(shell);
		TableLayout layout = new TableLayout();
		layout.addColumnData(new ColumnWeightData(50, 100, true));
		layout.addColumnData(new ColumnWeightData(50, 100, true));
		viewer.getTable().setLayout(layout);
		viewer.getTable().setLinesVisible(true);
		viewer.getTable().setHeaderVisible(true);
 
		// create columns. The 1st coumn will initially be the sorting column.
		// It will be sorted SWT.DOWN, and it will remember its last sorting order.
		// The 2nd column will initially be sorted SWT.UP, and it will reset to
		// that initial sorting order when being reselected.
		TableDemo.createTableColumn(viewer, "Column 1", "Column 1 tooltip",
				new TextSorter(), SWT.DOWN, true).chooseColumnForSorting();
		TableDemo.createTableColumn(viewer, "Column 2", "Column 2 tooltip",
				new NumberSorter(), SWT.UP, false);
 
		// set providers
		viewer.setContentProvider(new TableDemoContentProvider());
		viewer.setLabelProvider(new TableDemoLableProvider());
 
		// create and set data of demo
		Set<Data> set = new HashSet<Data>();
		set.add(new Data("a", 1));
		set.add(new Data("b", 2));
		set.add(new Data("c", 3));
		viewer.setInput(set);
 
		// pack everything
		viewer.getTable().pack();
		shell.pack();
 
		// open shell
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}
 
	// convenience method
	public static TableSortSelectionListener createTableColumn(
			TableViewer viewer, String text, String tooltip,
			AbstractInvertableTableSorter sorter, int initialDirection,
			boolean keepDirection) {
		TableColumn column = new TableColumn(viewer.getTable(), SWT.LEFT);
		column.setText(text);
		column.setToolTipText(tooltip);
		return new TableSortSelectionListener(viewer, column, sorter,
				initialDirection, keepDirection);
	}
 
	public static void main(String[] args) {
		new TableDemo();
	}
 
	private class Data {
		String text;
		int number;
 
		private Data(String text, int number) {
			this.text = text;
			this.number = number;
		}
	}
 
	private class TableDemoContentProvider implements
			IStructuredContentProvider {
		public Object[] getElements(Object inputElement) {
			return ((Set) inputElement).toArray();
		}
 
		public void dispose() {
		}
 
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		}
	}
 
	private class TableDemoLableProvider implements ITableLabelProvider {
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}
 
		public String getColumnText(Object element, int columnIndex) {
			Data data = (Data) element;
			String columnText;
			switch (columnIndex) {
			case 0:
				columnText = data.text;
				break;
			case 1:
				columnText = StringConverter.asString(data.number);
				break;
			default:
				columnText = "not set";
			}
			return columnText;
		}
 
		public void addListener(ILabelProviderListener listener) {
		}
 
		public void dispose() {
		}
 
		public boolean isLabelProperty(Object element, String property) {
			return false;
		}
 
		public void removeListener(ILabelProviderListener listener) {
		}
	}
 
	// convenience class which avoids casting in subclasses
	private abstract class AbstractDemoSorter extends
			AbstractInvertableTableSorter {
 
		public int compare(Viewer viewer, Object e1, Object e2) {
			return compare((Data) e1, (Data) e2);
		}
 
		public abstract int compare(Data d1, Data d2);
	}
 
	private class TextSorter extends AbstractDemoSorter {
 
		public int compare(Data d1, Data d2) {
			return Collator.getInstance().compare(d1.text, d2.text);
		}
	}
 
	private class NumberSorter extends AbstractDemoSorter {
 
		public int compare(Data d1, Data d2) {
			return Util.compare(d1.number, d2.number);
		}
	}
}


As I said in the beginning: Feel free to add any comments on how to improve this! I'm really looking forward to learn...

Bye,
Christian
  Click to reply to this thread Reply
1. At 10:08 PM on Dec 12, 2005, Ed Burnette Javalobby Junkies wrote:

Re: Sorting a TableViewer's columns both ways

Thanks for the tip. Extra credit for some who adds persisting the sort order and column widths, and handling moving columns around.
Ed Burnette
Author, Google Web Toolkit, Eclipse IDE Pocket Guide, Eclipse in Action
ZDNet blogger, Dev Connection; former Top Eclipse Ambassador.
  Click to reply to this thread Reply
2. At 3:33 AM on Dec 19, 2005, Neil Greenwood Occasional Javalobby Visitor wrote:

Re: Sorting a TableViewer's columns both ways

Hi Christian,

Nice work. Can you add the examples as attachments, or a zip containing them all? It's a lot easier than cut-n-paste.

Cheers,
Neil.
  Click to reply to this thread Reply
3. At 12:28 PM on Dec 19, 2005, Christian Soltenborn Javalobby Newcomers wrote:

Re: Sorting a TableViewer's columns both ways

Hi Neil,

thanks! I've attached a jar file containing the class and source files of the "framework" and the demo.

Bye,
Christian
  Click to reply to this thread Reply
4. At 12:32 PM on Dec 19, 2005, Christian Soltenborn Javalobby Newcomers wrote:

Re: Sorting a TableViewer's columns both ways

Hi Ed,

could you explain in more detail what you would like to have? I'm not sure what you mean... I'll definitely have a look at it then.

Thanks,
Christian
  Click to reply to this thread Reply
5. At 10:34 PM on Dec 19, 2005, Ed Burnette Javalobby Junkies wrote:

Re: Sorting a TableViewer's columns both ways

Recent versions of Eclipse support moving columns around in a table. And of course you could always resize them. It's nice to be able to close a view (or all of Eclipse or your RCP app) and come back and have everything exactly the way you set it up before closing it.
Ed Burnette
Author, Google Web Toolkit, Eclipse IDE Pocket Guide, Eclipse in Action
ZDNet blogger, Dev Connection; former Top Eclipse Ambassador.
  Click to reply to this thread Reply
6. At 3:12 AM on Dec 20, 2005, Christian Soltenborn Javalobby Newcomers wrote:

Re: Sorting a TableViewer's columns both ways

Hi again,

ok, your request makes more sense in the context of RCP apps. My "framework" (does anybody have a better name for this?) is also usable in plain JFace applications.

Actually, I'm right now learning to build an RCP app (for which I don't have too much time, though, because I'm also working on my diploma thesis). So I don't think it's the right time to jump into such a kind of specialized topic...

But I totally agree that it would be nice to have something like this.

Bye,
Christian
  Click to reply to this thread Reply
7. At 7:50 PM on Jan 8, 2006, Marco Ferreira Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

what is your jface or swt version? could be the versions?

because i have some error in:

//line 104 and 114
if (viewer.getTable().getSortColumn().equals(column)) {
//The method getSortColumn() is undefined for the type Table

//line 105 viewer.getTable().setSortDirection(currentSorter.getSortDirection());
//The method setSortDirection(int) is undefined for the //type Table

thanks
Marco
  Click to reply to this thread Reply
8. At 7:50 PM on Jan 8, 2006, Marco Ferreira Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

ahh, i forgot..the file is TableSortSelectionListener.java
  Click to reply to this thread Reply
9. At 11:02 PM on Jan 8, 2006, Sanjay Chaudhuri Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

If I have not mistaken, these 2 methods
getSortColumn(),
setSortDirection(int)
got introduced in 3.2

I am not sure about 3.2M1 and 3,2M2, but if you use 3.2M3 and above, you will not get any errors
  Click to reply to this thread Reply
10. At 12:22 PM on Jan 9, 2006, Marco Ferreira Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

ok.
i'm using eclipse 3.1
  Click to reply to this thread Reply
11. At 3:02 AM on Jan 13, 2006, Marco Ferreira Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
i have to update the eclipse too?

2. if i use the swt 3.2 instead of the 3.1 that i'm using now, should i have to do some changes im my code in order to support the 3.2?


thanks.
Marco
  Click to reply to this thread Reply
12. At 3:31 PM on Feb 16, 2006, André Dietisheim Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

Hi Christian

Cool stuff! I like your construction. I've got 2 comments on this:

1.) you can drastically improve the sorting speed by disabling the redraw in the tableViewer before sorting and reenabling it just afterwards:

public void chooseColumnForSorting() {
viewer.getTable().setSortColumn(column);
viewer.getTable().setSortDirection(currentSorter.getSortDirection());
viewer.getControl().setRedraw(false);
viewer.setSorter(currentSorter);
viewer.getControl().setRedraw(true);
}


2.) you use a model object specially for the table (Data with its properties). This might be usefull but could e a problem in an app that already has huge amount of data (like in a db-viewer). In this case it's better to use the original domain objects and interfaces/refletion to access the property of this domain-object thats displayed in the column.
  Click to reply to this thread Reply
13. At 4:13 AM on Feb 18, 2006, Sanjay Chaudhuri Blooming Javalobby Member wrote:

Re: Sorting a TableViewer's columns both ways

Sorry, was not monitoring the threads for a while. To answer your questions:

1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
i have to update the eclipse too?
>> You need to download eclipse version 3.2.

2. if i use the swt 3.2 instead of the 3.1 that i'm using now, should i have to do some changes im my code in order to support the 3.2?
>> You may need to change your code in 3.2, depending on what you have used. If you have used the published API, you maynot need to changed, but few things are deprecated. I would advise you to create a project using the standard template, and then have your views/editors/etc added. This should make life simple.

Thanks

Sanjay
  Click to reply to this thread Reply
14. At 5:10 AM on Feb 18, 2006, Christian Soltenborn Javalobby Newcomers wrote:

Re: Sorting a TableViewer's columns both ways

Hi,

I also need to say sorry for the late response - Sanjay's mail was the reminder :-)

> 1. how i update the swt 3.1 to 3.2 in eclipse 3.1?
> i have to update the eclipse too?

No, you don't, but you need to download it (or at least the current version of SWT), as Sanjay already pointed out.

If you run something within Eclipse as an SWT Application, Eclipse takes care of the SWT libraries needed in the classpath etc., but you can also manually add the to the classpath (and run as a normal Java Application).

Just grab the SWT libraries from a current Eclipse version (e.g. 3.2M5), copy them into a lib folder within your project and add them as libraries, and your project should compile fine.

To run your application, you also need to add the native libraries with Run.../Arguments/VM Arguments.

> 2. if i use the swt 3.2 instead of the 3.1 that i'm
> using now, should i have to do some changes im my
> code in order to support the 3.2?

I don't think so...

Bye,
Christian

thread.rss_message