/******************************************************************************* * Copyright (c) 2002, 2015 Innoopract Informationssysteme GmbH and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Innoopract Informationssysteme GmbH - initial API and implementation * EclipseSource - ongoing development ******************************************************************************/ package org.eclipse.rap.demo.controls; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; import org.eclipse.jface.viewers.ICellEditorValidator; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.ILazyContentProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TableViewerEditor; import org.eclipse.jface.viewers.TableViewerFocusCellManager; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; 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.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; public class TableViewerTab extends ExampleTab { private static final int ADD_ITEMS = 100; private static final int COL_FIRST_NAME = 0; private static final int COL_LAST_NAME = 1; private static final int COL_AGE = 2; private static final int COL_MARRIED = 3; private final PersonFilter viewerFilter; private final List<Person> persons; private Image uncheckedImage; private Image checkedImage; private TableViewer viewer; private TableViewerColumn firstNameColumn; private TableViewerColumn lastNameColumn; private TableViewerColumn ageColumn; private CheckboxTableViewerColumn marriedColumn; private Label lblSelection; private Button btnCreateCellEditor; public TableViewerTab() { super( "TableViewer" ); persons = new ArrayList<Person>(); viewerFilter = new PersonFilter(); } @Override protected void createStyleControls( Composite parent ) { createStyleButton( "MULTI", SWT.MULTI ); createStyleButton( "VIRTUAL", SWT.VIRTUAL ); createOrientationButton(); createAddItemsButton(); createSelectYoungestPersonButton(); createRemoveButton(); createCellEditorButton(); lblSelection = new Label( styleComp, SWT.WRAP ); } private void initializeImages() { if( uncheckedImage == null || checkedImage == null ) { uncheckedImage = loadImage( "resources/unchecked.png" ); checkedImage = loadImage( "resources/checked.png" ); } } @Override protected void createExampleControls( Composite parent ) { initializeImages(); if( btnCreateCellEditor != null && !btnCreateCellEditor.isDisposed() ) { btnCreateCellEditor.setEnabled( true ); } parent.setLayout( new GridLayout( 2, false ) ); Label lblFilter = new Label( parent, SWT.NONE ); lblFilter.setText( "Filter" ); lblFilter.setEnabled( ( getStyle() & SWT.VIRTUAL ) == 0 ); Text txtFilter = new Text( parent, SWT.BORDER ); txtFilter.setEnabled( ( getStyle() & SWT.VIRTUAL ) == 0 ); txtFilter.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false ) ); txtFilter.addModifyListener( new ModifyListener() { @Override public void modifyText( ModifyEvent event ) { Text text = ( Text )event.widget; viewerFilter.setText( text.getText() ); viewer.refresh(); } } ); if( viewer != null && !viewer.getControl().isDisposed() ) { viewer.getControl().dispose(); } initPersons(); createViewer( parent ); registerControl( viewer.getControl() ); } private void initPersons() { persons.clear(); persons.add( new Person( "Ada", "Lovelace", 1815, true ) ); persons.add( new Person( "John", "von Neumann", 1903, true ) ); persons.add( new Person( "Kurt", "Gödel", 1906, true ) ); persons.add( new Person( "Grace Murray", "Hopper", 1906, true ) ); persons.add( new Person( "Alan", "Turing", 1912, false ) ); persons.add( new Person( "Claude", "Shannon", 1916, true ) ); persons.add( new Person( "John", "Backus", 1924, true ) ); persons.add( new Person( "Alan", "Kay", 1940, true ) ); persons.add( new Person( "Dennis", "Ritchie", 1941, true ) ); persons.add( new Person( "David", "Parnas", 1941, true ) ); persons.add( new Person( "Larry", "Wall", 1954 , true ) ); persons.add( new Person( "Linus", "Torvalds", 1969 , true ) ); } private void createViewer( Composite parent ) { viewer = new TableViewer( parent, getStyle() ); viewer.setContentProvider( createContentProvider() ); firstNameColumn = createFirstNameColumn(); lastNameColumn = createLastNameColumn(); ageColumn = createAgeColumn(); marriedColumn = createMarriedColumn(); viewer.setInput( persons ); viewer.setItemCount( persons.size() ); viewer.addFilter( viewerFilter ); viewer.addSelectionChangedListener( new ISelectionChangedListener() { @Override public void selectionChanged( SelectionChangedEvent event ) { lblSelection.setText( "Selection: " + event.getSelection() ); lblSelection.getParent().layout( new Control[] { lblSelection } ); } } ); ColumnViewerToolTipSupport.enableFor( viewer ); Table table = viewer.getTable(); table.setHeaderVisible( true ); table.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.TRUE ); GridData tableData = new GridData( SWT.FILL, SWT.FILL, true, true ); tableData.horizontalSpan = 2; table.setLayoutData( tableData ); } private IContentProvider createContentProvider() { IContentProvider result; if( ( getStyle() & SWT.VIRTUAL ) == 0 ) { result = new PersonContentProvider(); } else { result = new LazyPersonContentProvider(); } return result; } private TableViewerColumn createFirstNameColumn() { TableViewerColumn result = new TableViewerColumn( viewer, SWT.NONE ); result.setLabelProvider( new PersonLabelProvider( COL_FIRST_NAME ) ); TableColumn column = result.getColumn(); column.setText( "First Name" ); column.setWidth( 170 ); column.setMoveable( true ); column.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { int sortDirection = updateSortDirection( ( TableColumn )event.widget ); sort( viewer, COL_FIRST_NAME, sortDirection == SWT.DOWN ); } } ); return result; } private TableViewerColumn createLastNameColumn() { TableViewerColumn result = new TableViewerColumn( viewer, SWT.NONE ); result.setLabelProvider( new PersonLabelProvider( COL_LAST_NAME ) ); TableColumn column = result.getColumn(); column.setText( "Last Name" ); column.setWidth( 120 ); column.setMoveable( true ); column.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { int sortDirection = updateSortDirection( ( TableColumn )event.widget ); sort( viewer, COL_LAST_NAME, sortDirection == SWT.DOWN ); } } ); return result; } private TableViewerColumn createAgeColumn() { TableViewerColumn result = new TableViewerColumn( viewer, SWT.NONE ); result.setLabelProvider( new PersonLabelProvider( COL_AGE ) ); TableColumn column = result.getColumn(); column.setText( "Born" ); column.setWidth( 80 ); column.setMoveable( true ); column.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { int sortDirection = updateSortDirection( ( TableColumn )event.widget ); sort( viewer, COL_AGE, sortDirection == SWT.DOWN ); } } ); return result; } private CheckboxTableViewerColumn createMarriedColumn() { CheckboxTableViewerColumn result = new CheckboxTableViewerColumn( viewer, SWT.NONE ); result.setLabelProvider( new PersonLabelProvider( COL_MARRIED ) ); TableColumn column = result.getColumn(); column.setText( "Married" ); column.setWidth( 60 ); column.setMoveable( true ); column.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { int sortDirection = updateSortDirection( ( TableColumn )event.widget ); sort( viewer, COL_MARRIED, sortDirection == SWT.DOWN ); } } ); return result; } private void createAddItemsButton() { Button button = new Button( styleComp, SWT.PUSH ); button.setText( "Add " + ADD_ITEMS + " Items" ); button.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { for( int i = 0; i < ADD_ITEMS; i++ ) { int counter = 11 + i; persons.add( new Person( "new " + counter, "person " + counter, counter, false ) ); } getViewer().setInput( persons ); if( ( getStyle() & SWT.VIRTUAL ) != 0 ) { getViewer().setItemCount( persons.size() ); } } } ); } private void createSelectYoungestPersonButton() { Button button = new Button( styleComp, SWT.PUSH ); button.setText( "Select youngest Person" ); button.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { Person youngestPerson = null; int minAge = Integer.MAX_VALUE; for( int i = 0; i < persons.size(); i++ ) { Person person = persons.get( i ); if( person.age < minAge ) { minAge = person.age; youngestPerson = person; } } getViewer().setSelection( new StructuredSelection( youngestPerson ) ); getViewer().reveal( youngestPerson ); } } ); } private void createRemoveButton() { Button button = new Button( styleComp, SWT.PUSH ); button.setText( "Remove selected rows" ); button.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { IStructuredSelection selection = ( IStructuredSelection )getViewer().getSelection(); Iterator<?> iter = selection.iterator(); while( iter.hasNext() ) { Person person = ( Person )iter.next(); persons.remove( person ); } getViewer().getTable().setTopIndex( 0 ); if( ( getViewer().getTable().getStyle() & SWT.VIRTUAL ) != 0 ) { getViewer().setItemCount( persons.size() ); } getViewer().setInput( persons ); } } ); } private void createCellEditorButton() { btnCreateCellEditor = new Button( styleComp, SWT.PUSH ); btnCreateCellEditor.setText( "Create Cell Editor" ); btnCreateCellEditor.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { createCellEditor(); btnCreateCellEditor.setEnabled( false ); } } ); } private void createCellEditor() { EditingSupport editingSupport; editingSupport = new FirstNameEditingSupport( viewer ); firstNameColumn.setEditingSupport( editingSupport ); editingSupport = new LastNameEditingSupport( viewer, getLastNames() ); lastNameColumn.setEditingSupport( editingSupport ); editingSupport = new AgeEditingSupport( viewer ); ageColumn.setEditingSupport( editingSupport ); marriedColumn.setEditingSupport( new MarriedEditingSupport() ); ColumnViewerEditorActivationStrategy activationStrategy = new EditorActivationStrategy( viewer ); FocusCellOwnerDrawHighlighter highlighter = new FocusCellOwnerDrawHighlighter( viewer ); TableViewerFocusCellManager focusManager = new TableViewerFocusCellManager( viewer, highlighter ); int feature = ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR; TableViewerEditor.create( viewer, focusManager, activationStrategy, feature ); marriedColumn.attachToEditor(); } private static int updateSortDirection( TableColumn column ) { Table table = column.getParent(); if( column == table.getSortColumn() ) { if( table.getSortDirection() == SWT.UP ) { table.setSortDirection( SWT.DOWN ); } else { table.setSortDirection( SWT.UP ); } } else { table.setSortColumn( column ); table.setSortDirection( SWT.DOWN ); } return table.getSortDirection(); } @SuppressWarnings("unchecked") private static void sort( TableViewer viewer, int property, boolean ascending ) { if( ( viewer.getControl().getStyle() & SWT.VIRTUAL ) != 0 ) { List<Person> input = ( List<Person> )viewer.getInput(); Collections.sort( input, new PersonComparator( property, ascending ) ); viewer.refresh(); } else { viewer.setComparator( new PersonComparator( property, ascending ) ); } } private TableViewer getViewer() { return viewer; } private String[] getLastNames() { ArrayList<String> list = new ArrayList<String>(); for( Person person : persons ) { if( person.lastName.length() > 0 ) { list.add( person.lastName ); } } String[] result = new String[ list.size() ]; list.toArray( result ); return result; } private static final class Person { String firstName; String lastName; int age; boolean married; public Person( String firstName, String lastName, int age, boolean married ) { this.firstName = firstName; this.lastName = lastName; this.age = age; this.married = married; } @Override public String toString() { return firstName + " " + lastName + " " + age + " " + married; } } private static final class PersonContentProvider implements IStructuredContentProvider { Object[] elements; @Override public Object[] getElements( Object inputElement ) { return elements; } @Override public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) { if( newInput == null ) { elements = new Object[ 0 ]; } else { List<?> personList = ( List<?> )newInput; elements = personList.toArray(); } } @Override public void dispose() { // do nothing } } private static final class LazyPersonContentProvider implements ILazyContentProvider { private TableViewer tableViewer; private List<?> elements; @Override public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) { tableViewer = ( TableViewer )viewer; elements = ( List<?> )newInput; } @Override public void updateElement( int index ) { tableViewer.replace( elements.get( index ), index ); } @Override public void dispose() { // do nothing } } private class PersonLabelProvider extends ColumnLabelProvider { private final int columnIndex; private final Color nameBackground; public PersonLabelProvider( int columnIndex ) { this.columnIndex = columnIndex; nameBackground = new Color( Display.getCurrent(), 248, 248, 248 ); } @Override public String getText( Object element ) { Person person = ( Person )element; String result = person.toString(); switch( columnIndex ) { case COL_FIRST_NAME: result = person.firstName; break; case COL_LAST_NAME: result = person.lastName; break; case COL_AGE: result = String.valueOf( person.age ); break; case COL_MARRIED: result = person.married ? "yes" : "no"; break; } return result; } @Override public Image getImage( Object element ) { Image result = null; if( columnIndex == COL_MARRIED ) { Person person = ( Person )element; result = person.married ? checkedImage : uncheckedImage; } return result; } @Override public Color getBackground( Object element ) { Color result = null; switch( columnIndex ) { case COL_FIRST_NAME: case COL_LAST_NAME: result = nameBackground; break; } return result; } @Override public String getToolTipText( Object element ) { Person person = ( Person )element; String text = null; switch( columnIndex ) { case COL_FIRST_NAME: text = "<i>" + person.firstName + "</i>"; break; case COL_LAST_NAME: text = person.lastName; break; case COL_AGE: text = String.valueOf( person.age ); break; case COL_MARRIED: text = person.married ? "yes" : "no"; break; } return text; } } private static final class PersonComparator extends ViewerComparator implements Comparator<Person> { private final boolean ascending; private final int property; public PersonComparator( int property, boolean ascending ) { this.property = property; this.ascending = ascending; } @Override public int compare( Viewer viewer, Object object1, Object object2 ) { return compare( ( Person )object1, ( Person )object2 ); } @Override public boolean isSorterProperty( Object elem, String property ) { return true; } @Override public int compare( Person person1, Person person2 ) { int result = 0; if( property == COL_FIRST_NAME ) { result = person1.firstName.compareTo( person2.firstName ); } else if( property == COL_LAST_NAME ) { result = person1.lastName.compareTo( person2.lastName ); } else if( property == COL_AGE ) { result = person1.age - person2.age; } else if( property == COL_MARRIED ) { if( person1.married && !person2.married ) { result = -1; } else if( !person1.married && person2.married ) { result = +1; } } if( !ascending ) { result = result * -1; } return result; } } private static final class PersonFilter extends ViewerFilter { private String text; public void setText( final String string ) { text = string; } @Override public boolean select( Viewer viewer, Object parentElement, Object element ) { boolean result = true; Person person = ( Person )element; if( text != null && text.length() > 0 ) { String personText = person.toString().toLowerCase(); result = personText.indexOf( text.toLowerCase() ) != -1; } return result; } @Override public boolean isFilterProperty( Object element, String prop ) { return true; } } private static final class EditorActivationStrategy extends ColumnViewerEditorActivationStrategy { private EditorActivationStrategy( ColumnViewer viewer ) { super( viewer ); setEnableEditorActivationWithKeyboard( true ); } @Override protected boolean isEditorActivationEvent( ColumnViewerEditorActivationEvent event ) { boolean result; if( event.character == '\r' ) { result = true; } else { result = super.isEditorActivationEvent( event ); } return result; } } private static final class FirstNameEditingSupport extends EditingSupport { private final CellEditor editor; public FirstNameEditingSupport( TableViewer viewer ) { super( viewer ); editor = new TextCellEditor( viewer.getTable() ); } @Override protected boolean canEdit( Object element ) { return true; } @Override protected CellEditor getCellEditor( Object element ) { return editor; } @Override protected Object getValue( Object element ) { Person person = ( Person )element; String result; result = person.firstName; return result; } @Override protected void setValue( Object element, Object value ) { Person person = ( Person )element; person.firstName = ( String )value; getViewer().update( element, null ); } } private static final class LastNameEditingSupport extends EditingSupport { private final CellEditor editor; public LastNameEditingSupport( TableViewer viewer, String[] suggestions ) { super( viewer ); editor = new ComboBoxCellEditor( viewer.getTable(), suggestions, SWT.NONE ); } @Override protected boolean canEdit( Object element ) { return true; } @Override protected CellEditor getCellEditor( Object element ) { return editor; } @Override protected Object getValue( Object element ) { Person person = ( Person )element; CCombo ccombo = ( CCombo )editor.getControl(); ccombo.setText( person.lastName ); return new Integer( -2 ); } @Override protected void setValue( Object element, Object value ) { Person person = ( Person )element; CCombo ccombo = ( CCombo )editor.getControl(); person.lastName = ccombo.getText(); getViewer().update( element, null ); } } private static final class AgeEditingSupport extends EditingSupport { private final CellEditor editor; public AgeEditingSupport( TableViewer viewer ) { super( viewer ); editor = new TextCellEditor( viewer.getTable() ); editor.setValidator( new ICellEditorValidator() { @Override public String isValid( Object value ) { String result = null; try { Integer.parseInt( ( String )value ); } catch( NumberFormatException e ) { String text = "''{0}'' is not a valid age."; result = MessageFormat.format( text, new Object[] { value } ); } return result; } }); } @Override protected boolean canEdit( Object element ) { return true; } @Override protected CellEditor getCellEditor( Object element ) { return editor; } @Override protected Object getValue( Object element ) { Person person = ( Person )element; return String.valueOf( person.age ); } @Override protected void setValue( Object element, Object value ) { if( value != null ) { Person person = ( Person )element; person.age = Integer.parseInt( ( String )value ); getViewer().update( element, null ); } } } private static class MarriedEditingSupport extends CheckboxEditingSupport { @Override public boolean canEdit( Object element ) { return true; } @Override public Boolean getValue( Object element ) { Person person = ( Person )element; return Boolean.valueOf( person.married ); } @Override public void setValue( Object element, Boolean value ) { Person person = ( Person )element; person.married = value.booleanValue(); } } }