Generics for the Combo-,List- and TableViewer

Currently the generic ComboViewer has been merged into the eclipse master branch and the changes for the List- and TableViewer are waiting for there reviews. In this blogpost I want to show you how to use this viewers with the type parameters, to have more typesafe code and avoid ugly castings.
Besides the examples from this post you can see the usage of the viewers in a small sample application I’ve uploaded to github.com.

ComboViewer

The changes for this view have already been merged, so you just have to download and install the current Luna integration build to use it.
The generified ComboViewer allows you to define the types your viewer handles. If you look at the ComboViewer class, you see that it supports two type parameters, E and I.
E stands for element and defines the type a single element, which should be displayed, has. For example this could be the domain specific class Person which holds all data which belong to a person.
The type parameter I stands for input which defines the type of the input you usually set with the setInput method for the viewer. The input holds all models which should be displayed by the viewer. Often this are lists of the elements e.g. List, but also can be domain specific types which holds the elements.

The following example shows a simple implementation of a ComboViewer with use of generic types:

	private List<Person> content;
	private ComboViewer<Person, List<Person>> comboViewer;

	@PostConstruct
	public void createComposite(Composite parent) {
		parent.setLayout(new GridLayout());
		comboViewer = new ComboViewer<Person, List<Person>>(parent);
		content = new ArrayList<Person>();

		content.add(new Person("Peter", new Date()));
		content.add(new Person("Hans", new Date()));

		comboViewer
				.setContentProvider(new IStructuredContentProvider<Person, List<Person>>() {

					public void inputChanged(Viewer<List<Person>> viewer,
							List<Person> oldInput, List<Person> newInput) {
						// TODO Auto-generated method stub

					}

					public void dispose() {

					}

					public Person[] getElements(List<Person> inputElement) {

						List<Person> personList = inputElement;
						return personList.toArray(new Person[personList.size()]);
					}

				});


		
		
		comboViewer.setLabelProvider(new LabelProvider<Person>() {
			@Override
			public String getText(Person element) {
				return element.getName();
			}
		});
		comboViewer.setInput(content);


	}

So you see the ComboViewer is typed with the element type Person and the input type List.

ComboViewer<Person, List<Person>> comboViewer = new ComboViewer<Person, List<Person>>(parent);

After we typed the viewer, it just excepts correct typed ContentProvider and LableProvider.

comboViewer.setContentProvider(new IStructuredContentProvider<Person, List<Person>>() { ... }
comboViewer.setLabelProvider(new LabelProvider<Person>() { ... }

Because the LableProvider and ContentProvider also use Type Parameters, the overwritten methods like getText can use the defined element type as type for the method parameter:

comboViewer.setLabelProvider(new LabelProvider<Person>() {
	@Override
	public String getText(Person element) {
		return element.getName();
	}
});

This avoids the casting from Object to Person and ensures that the element parameter will ever be from the type Person or it’s subtype

ListViewer

The ListViewer is currently not merged, so if you want to try the generic feature for this viewer you can pull the changes from the gerrit review system.
You can use the generified ListViewer like the ComboViewer by defining the used types.

	private List<Person> content;
	private ListViewer<Person, List<Person>> listViewer;

	@PostConstruct
	public void createComposite(Composite parent) {

	    parent.setLayout(new GridLayout());
	    listViewer = new ListViewer<Person, List<Person>>(parent);
	    content = new ArrayList<Person>();

	    content.add(new Person("Peter", new Date()));
	    content.add(new Person("Lars", new Date()));

	    listViewer
	            .setContentProvider(new IStructuredContentProvider<Person, List<Person>>() {

	                public void inputChanged(Viewer<List<Person>> viewer,
	                        List<Person> oldInput, List<Person> newInput) {
	                    // TODO Auto-generated method stub

	                }

	                public void dispose() {

	                }

	                public Person[] getElements(List<Person> inputElement) {

	                    List<Person> personList = inputElement;
	                    return personList.toArray(new Person[personList.size()]);
	                }

	            });




	    listViewer.setLabelProvider(new LabelProvider<Person>() {
	        @Override
	        public String getText(Person element) {
	            return element.getName();
	        }
	    });
	    listViewer.setInput(content);
	}

TableViewer

Like the ListViewer the TableViewer still has note been merged, you find the gerrit review here. The TableViewer has additional to the normal Viewer for every column a TableViewerColumn which is also generified.
The following example shows a sample usage of the TableViewer

	@PostConstruct
	public void createComposite(Composite parent) {

	    List<Person> content = new ArrayList<Person>();
	    content.add(new Person("Peter", new Date()));
	    content.add(new Person("Lars", new Date()));

		TableViewer<Person,List<Person>> tableViewer = new TableViewer<Person,List<Person>>(parent);

		tableViewer.setContentProvider(new IStructuredContentProvider<Person,List<Person>>() {

			public void dispose() {

			}

			public Person[] getElements(List<Person> inputElement) {
				return (Person[]) inputElement.toArray();
			}

			public void inputChanged(Viewer<List<Person>> viewer, List<Person> oldInput,
					List<Person> newInput) {
			}

		});


		class MySelectionChangedListner implements ISelectionChangedListener{

			public void selectionChanged(SelectionChangedEvent event) {
				IStructuredSelection selection = (IStructuredSelection) event.getSelection();

				System.out.println(((Person)selection.getFirstElement()).getName());
			}

		}

		tableViewer.addSelectionChangedListener(new MySelectionChangedListner());

		TableViewerColumn<Person,List<Person>> column = new TableViewerColumn<Person,List<Person>>(tableViewer, SWT.NONE);

		column.setLabelProvider(new ColumnLabelProvider<Person,List<Person>>(){
			@Override
			public String getText(final Person element) {
				return element.getName();
			}
		});

		column.getColumn().setWidth(200);

		column.getColumn().setText("Name:");


		column = new TableViewerColumn<Person,List<Person>>(tableViewer, SWT.NONE);

		column.setLabelProvider(new ColumnLabelProvider<Person,List<Person>>(){
			@Override
			public String getText(Person element) {
				// TODO Auto-generated method stub
				return element.getBirthdate().toString();
			}
		});

		column.getColumn().setWidth(200);

		column.getColumn().setText("Date:");

		tableViewer.setInput(content);
	}
This entry was posted in Eclipse, Hendrik Still and tagged , , . Bookmark the permalink.

2 Responses to Generics for the Combo-,List- and TableViewer

  1. Christian Schwarz says:

    Generics are a long overdue feature in JFace, good to see some progress here. Is it planned to add generics to Data-Bindings too?

  2. Lars Vogel says:

    Yes, the e4 project hosts a modified variant of the databinding plug-ins which supports generics.

Comments are closed.