Java tutorial
/* * polymap.org * Copyright (C) 2011-2015, Falko Brutigam, and other contributors as * indicated by the @authors tag. All rights reserved. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.polymap.rhei.table; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import org.geotools.data.FeatureSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.ILazyContentProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.polymap.core.runtime.ListenerList; import org.polymap.core.runtime.UIThreadExecutor; import org.polymap.core.ui.SelectionAdapter; import org.polymap.core.ui.UIUtils; /** * * <p/> * Use of the following content providers: * <ul> * <li>{@link LazyFeatureContentProvider}: filter and sorting in backend {@link FeatureSource}</li> * <li>{@link DeferredFeatureContentProvider2}: sorting in background thread via {@link Comparator}</li> * <li>{@link FeatureCollectionContentProvider}: simple provider for small number of features </li> * <li>{@link CollectionContentProvider}: simple provider for small number of features </li> * <li></li> * </ul> * * @author <a href="http://www.polymap.de">Falko Brutigam</a> */ public class FeatureTableViewer extends TableViewer { private static Log log = LogFactory.getLog(FeatureTableViewer.class); /** Property type that is fired when the content of the viewer has changed. */ public static final String PROP_CONTENT_SIZE = "contentsize"; public static final Object LOADING_ELEMENT = "LOADING_ELEMENT"; public static final Color LOADING_FOREGROUND = UIUtils.getColor(0xa0, 0xa0, 0xa0); public static final Color LOADING_BACKGROUND = UIUtils.getColor(0xfa, 0xfb, 0xff); protected Map<String, IFeatureTableColumn> displayed = new HashMap(); protected Map<String, IFeatureTableColumn> available = new HashMap(); private Map<String, CellEditor> editors = new HashMap(); private ListenerList<PropertyChangeListener> listeners = new ListenerList(); private Color foreground, background; private Composite layoutParent; private TableColumnLayout tableColumnLayout; public FeatureTableViewer(Composite parent, int style) { super(parent, style | SWT.VIRTUAL); ColumnViewerToolTipSupport.enableFor(this); getTable().setLinesVisible(true); getTable().setHeaderVisible(true); getTable().setLayout(new TableLayout()); this.foreground = getTable().getForeground(); this.background = getTable().getBackground(); //setUseHashlookup( true ); parent.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent ev) { FeatureTableViewer.this.controlResized(ev); } }); // tableColumnLayout = new TableColumnLayout(); // parent.setLayout( tableColumnLayout ); } private int cachedWidth = -1; protected void controlResized(ControlEvent ev) { if (!getTable().isDisposed() && !displayed.isEmpty()) { Rectangle area = getTable().getParent().getClientArea(); if (area.width != cachedWidth) { cachedWidth = area.width; int avgWidth = area.width / displayed.size(); int sumWeight = displayed.values().stream().mapToInt(c -> c.getWeight()).sum(); for (IFeatureTableColumn column : displayed.values()) { TableViewerColumn viewerColumn = column.getViewerColumn(); if (column.getWeight() > 0) { // weighted with int width = ((area.width / sumWeight) * column.getWeight()) - 5; // min width if (column.getMinWidth() > 0) { width = Math.max(column.getMinWidth(), width); } viewerColumn.getColumn().setWidth(width); } else { viewerColumn.getColumn().setWidth(avgWidth); } } } } } public void dispose() { if (!getTable().isDisposed()) { getTable().dispose(); listeners.clear(); listeners = null; displayed.clear(); available.clear(); editors.clear(); } } /** * Suppress selection of rows altogether. This is useful for tables with editing enabled. */ public void suppressSelection() { Table table = getTable(); table.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event ev) { ev.detail = SWT.NONE; ev.type = SWT.None; ev.doit = false; try { table.setRedraw(false); table.deselectAll(); } finally { table.setRedraw(true); } } }); } @Override public void addFilter(ViewerFilter filter) { assert getContentProvider() != null; super.addFilter(filter); if (getContentProvider() instanceof DeferredFeatureContentProvider2) { DeferredFeatureContentProvider2 provider = (DeferredFeatureContentProvider2) getContentProvider(); provider.addViewerFilter(filter); } } @Override public void removeFilter(ViewerFilter filter) { super.removeFilter(filter); if (getContentProvider() instanceof DeferredFeatureContentProvider2) { DeferredFeatureContentProvider2 provider = (DeferredFeatureContentProvider2) getContentProvider(); provider.removeViewerFilter(filter); } } /** * */ @Override public void refresh() { // FIXME ??? super.refresh(); // if (getContentProvider() instanceof DeferredFeatureContentProvider2) { // DeferredFeatureContentProvider2 provider = (DeferredFeatureContentProvider2)getContentProvider(); // provider.inputChanged( this, null, null ); // provider.sortContent( sor provider.getSortOrder() ); // } } public int getElementCount() { return doGetItemCount(); } public IFeatureTableElement[] getElements() { IFeatureTableElement[] result = new IFeatureTableElement[getElementCount()]; for (int i = 0; i < getElementCount(); i++) { result[i] = (IFeatureTableElement) getElementAt(i); } return result; } public IFeatureTableElement[] getSelectedElements() { return SelectionAdapter.on(getSelection()).asArray(IFeatureTableElement.class); } public void clearSelection() { getTable().deselectAll(); } /** * Selects the element with the given feature id. * * @param fid * @param reveal */ public void selectElement(final String fid, boolean reveal, boolean fireEvent) { assert fid != null; IFeatureTableElement search = new DefaultFeatureTableElement() { @Override public Object getValue(String name) { throw new RuntimeException("not yet implemented."); } @Override public void setValue(String name, Object value) { throw new RuntimeException("not yet implemented."); } @Override public String fid() { return fid; } }; int index = -1; if (getContentProvider() instanceof IDeferredFeatureContentProvider) { // find index from content provider index = ((IDeferredFeatureContentProvider) getContentProvider()).findElement(search); // select table getTable().setSelection(index); log.debug("getTable().getSelectionIndex(): " + getTable().getSelectionIndex()); if (reveal) { getTable().showSelection(); } // fire event if (fireEvent) { ISelection sel = getSelection(); log.debug("getSelection(): " + sel); updateSelection(sel); } } else if (getContentProvider() instanceof ILazyContentProvider) { throw new UnsupportedOperationException(); } else { ISelection sel = new StructuredSelection(search); setSelection(sel, reveal); } getTable().layout(); } public IFeatureTableColumn addColumn(IFeatureTableColumn column) { column.setViewer(this); TableViewerColumn viewerColumn = column.newViewerColumn(); viewerColumn.getColumn().setData("name", column.getName()); // tableColumnLayout.setColumnData( viewerColumn.getColumn(), // new ColumnPixelData( 120, true ) ); available.put(column.getName(), column); displayed.put(column.getName(), column); return column; } public <T extends IFeatureTableColumn> T getColumn(String propName) { return (T) available.get(propName); } // /** // * Set the content of this viewer. A {@link DeferredFeatureContentProvider} is // * used to fetch and sort the features. // * // * @param fs // * @param filter // */ // public void setContent( final FeatureSource fs, final Filter filter ) { // TableColumn sortColumn = getTable().getSortColumn(); // int sortDir = SWT.DOWN; // if (sortColumn == null) { // sortColumn = getTable().getColumn( 0 ); // getTable().setSortColumn( sortColumn ); // getTable().setSortDirection( sortDir ); // } // else { // sortDir = getTable().getSortDirection(); // } // // String colName = (String)sortColumn.getData( "name" ); // IFeatureTableColumn sortTableColumn = displayed.get( colName ); // // setContentProvider( new DeferredFeatureContentProvider2( // this, fs, filter, sortTableColumn, sortDir, getFilters() ) ); // setInput( fs ); // } public boolean addPropertyChangeListener(PropertyChangeListener listener) { return listeners.add(listener); } public boolean removePropertyChangeListener(PropertyChangeListener listener) { return listeners.remove(listener); } protected void firePropChange(final String name, Object oldValue, final Object newValue) { final PropertyChangeEvent ev = new PropertyChangeEvent(this, name, oldValue, newValue); Display display = getTable().getDisplay(); display.asyncExec(new Runnable() { public void run() { if (getTable().isDisposed()) { return; } // if (PROP_CONTENT_SIZE.equals( name ) ) { // getTable().setForeground( Graphics.getColor( 0x70, 0x70, 0x80 ) ); // } for (PropertyChangeListener l : listeners.getListeners()) { l.propertyChange(ev); } } }); } /** * Sorts the table entries by delegating the call to the content provider. * * @param column The table column to sort. * @param dir {@link SWT#UP}, {@link SWT#DOWN} or {@link SWT#NONE} * @param column */ public void sortContent(IFeatureTableColumn column, int dir) { IContentProvider contentProvider = getContentProvider(); if (contentProvider == null) { throw new IllegalStateException("Call sortContent() after content provider is set."); } // ContentProvider else if (contentProvider instanceof ISortingContentProvider) { ((ISortingContentProvider) contentProvider).sortContent(column, dir); } // normal else { Comparator<IFeatureTableElement> comparator = column.newComparator(dir); setComparator(new ViewerComparator(comparator) { public int compare(Viewer viewer, Object e1, Object e2) { return comparator.compare((IFeatureTableElement) e1, (IFeatureTableElement) e2); } }); } getTable().setSortColumn(column.getViewerColumn().getColumn()); getTable().setSortDirection(dir); } public void markTableLoading(final boolean loading) { UIThreadExecutor.asyncFast(() -> { if (getTable().isDisposed()) { return; } if (loading) { getTable().setForeground(LOADING_FOREGROUND); getTable().setBackground(LOADING_BACKGROUND); // setBusy( true ); } else { getTable().setForeground(foreground); getTable().setBackground(background); // setBusy( false ); } }); } }