Java tutorial
/* * polymap.org * Copyright (C) 2011-2014, Polymap GmbH. 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.core.data.ui.featureselection; import static org.polymap.core.project.ILayer.PROP_GEORESID; import static org.polymap.core.qi4j.event.PropertyChangeSupport.PROP_ENTITY_REMOVED; import java.util.EventObject; import java.util.List; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import org.geotools.factory.CommonFactoryFinder; import org.geotools.factory.GeoTools; import org.geotools.filter.v1_1.OGCConfiguration; import org.geotools.xml.Configuration; import org.geotools.xml.Encoder; import org.geotools.xml.Parser; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.Id; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.qi4j.api.unitofwork.NoSuchEntityException; import com.vividsolutions.jts.geom.Geometry; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.ui.IActionDelegate; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IViewReference; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.polymap.core.data.DataPlugin; import org.polymap.core.data.FeatureChangeEvent; import org.polymap.core.data.FeatureChangeListener; import org.polymap.core.data.PipelineFeatureSource; import org.polymap.core.data.ui.featuretable.DefaultFeatureTableColumn; import org.polymap.core.data.ui.featuretable.FeatureTableViewer; import org.polymap.core.data.ui.featuretable.IFeatureTableElement; import org.polymap.core.geohub.LayerFeatureSelectionManager; import org.polymap.core.project.ILayer; import org.polymap.core.project.ProjectRepository; import org.polymap.core.project.ui.util.SelectionAdapter; import org.polymap.core.project.ui.util.SimpleFormData; import org.polymap.core.runtime.Polymap; import org.polymap.core.runtime.event.EventFilter; import org.polymap.core.runtime.event.EventHandler; import org.polymap.core.runtime.event.EventManager; import org.polymap.core.workbench.PolymapWorkbench; /** * * * @author <a href="http://www.polymap.de">Falko Brutigam</a> */ public class FeatureSelectionView extends ViewPart implements ISelectionChangedListener { private static Log log = LogFactory.getLog(FeatureSelectionView.class); public static final String ID = "org.polymap.core.data.FeatureSelectionView"; private static final FilterFactory ff = CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints()); /* Bad but effective way to pass the layer to the view. */ private static final ThreadLocal<ILayer> initLayer = new ThreadLocal(); /** * Makes sure that the view for the layer is open. If the view is already open, * then it is activated. * * @param layer * @return The view for the given layer, or null if there was an error opening * the view. */ public static FeatureSelectionView open(final ILayer layer) { final FeatureSelectionView[] result = new FeatureSelectionView[1]; Polymap.getSessionDisplay().syncExec(new Runnable() { public void run() { try { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); initLayer.set(layer); IViewPart view = page.showView(FeatureSelectionView.ID, layer.id(), IWorkbenchPage.VIEW_ACTIVATE); if (view instanceof FeatureSelectionView) { result[0] = (FeatureSelectionView) view; } } catch (Exception e) { PolymapWorkbench.handleError(DataPlugin.PLUGIN_ID, null, e.getMessage(), e); } finally { initLayer.remove(); } } }); return result[0]; } public static void close(final ILayer layer) { Polymap.getSessionDisplay().asyncExec(new Runnable() { public void run() { try { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); FeatureSelectionView view = (FeatureSelectionView) page.findView(FeatureSelectionView.ID); if (view != null) { page.hideView(view); view.dispose(); } } catch (Exception e) { PolymapWorkbench.handleError(DataPlugin.PLUGIN_ID, this, e.getMessage(), e); } } }); } // instance ******************************************* private ILayer layer; /** Might be null if fs could not be instantiated for the layer */ private PipelineFeatureSource fs; private Filter filter = Filter.EXCLUDE; /** Might be null if fs could not be instantiated for the layer */ private FeatureTableViewer viewer; private String basePartName; private Composite parent; private FeatureSelectionListener selectionListener = new FeatureSelectionListener(); private FeatureChangeListener changeListener; private ModelListener modelListener = new ModelListener(); public IActionDelegate openAction; public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); if (memento != null) { final String layerId = memento.getString("layerId"); final String filterText = memento.getTextData(); if (layerId != null && filterText != null) { try { layer = ProjectRepository.instance().findEntity(ILayer.class, layerId); if (layer != null) { Configuration config = new org.geotools.filter.v1_1.OGCConfiguration(); Parser parser = new Parser(config); final Filter parsedFilter = (Filter) parser .parse(new ByteArrayInputStream(filterText.getBytes("UTF8"))); // set selection *after* createPartControl() Polymap.getSessionDisplay().asyncExec(new Runnable() { public void run() { LayerFeatureSelectionManager.forLayer(layer).changeSelection(parsedFilter, LayerFeatureSelectionManager.MODE.REPLACE, null); // XXX views loose their memento if not initialized in a session(?); afterwards, // without memento, they are not usable; besides, to much open feature tables // are anoying - so this closes all views but the one that was active IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage(); for (IViewReference view : page.getViewReferences()) { if (view.getId().equals(ID) && !view.getSecondaryId().equals(layerId)) { page.hideView(view); } } } }); } } catch (NoSuchEntityException e) { log.warn("Layer does no longer exists: " + layerId); } catch (Exception e) { log.warn("Unable to restore state.", e); } } // no layer in memento else { Polymap.getSessionDisplay().asyncExec(new Runnable() { public void run() { try { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage(); page.hideView(FeatureSelectionView.this); } catch (Exception e) { log.warn("", e); } } }); } } } public void saveState(IMemento memento) { if (layer != null) { try { if (filter == null) { filter = Filter.EXCLUDE; } // save max. 500 Fids if (filter instanceof Id && ((Id) filter).getIdentifiers().size() > 500) { return; } OGCConfiguration config = new org.geotools.filter.v1_1.OGCConfiguration(); Encoder encoder = new Encoder(config); encoder.setIndenting(true); encoder.setIndentSize(4); ByteArrayOutputStream bout = new ByteArrayOutputStream(4096); encoder.encode(filter, org.geotools.filter.v1_0.OGC.Filter, bout); if (bout.size() < 10 * 1024) { memento.putTextData(bout.toString("UTF8")); memento.putString("layerId", layer.id()); log.info(bout.toString("UTF8")); } } catch (Exception e) { log.warn("Unable to save state:", e); } } } protected void init(ILayer _layer) { try { this.layer = _layer; this.basePartName = layer.getLabel(); setPartName(basePartName); // PropertyChangeListener: layer layer.addPropertyChangeListener(modelListener); // FeatureSelectionListener LayerFeatureSelectionManager fsm = LayerFeatureSelectionManager.forLayer(layer); filter = fsm.getFilter(); fsm.addSelectionChangeListener(selectionListener); // FeatureChangeListener EventManager.instance().subscribe(changeListener = new FeatureChangeListener() { public void featureChanges(List<FeatureChangeEvent> events) { viewer.refresh(); } }, new EventFilter<EventObject>() { public boolean apply(EventObject ev) { return viewer != null && layer.equals(ev.getSource()); } }); this.fs = PipelineFeatureSource.forLayer(layer, false); } catch (Exception e) { PolymapWorkbench.handleError(DataPlugin.PLUGIN_ID, this, "", e); } } public void dispose() { super.dispose(); if (layer != null) { try { layer.removePropertyChangeListener(modelListener); LayerFeatureSelectionManager.forLayer(layer).removeSelectionChangeListener(selectionListener); EventManager.instance().unsubscribe(changeListener); } catch (NoSuchEntityException e) { // layer is deleted -> ignore } } if (viewer != null) { viewer.dispose(); viewer = null; } layer = null; fs = null; } public ILayer getLayer() { return layer; } public PipelineFeatureSource getFeatureStore() { return fs; } public Filter getFilter() { return filter; } public IFeatureTableElement[] getTableElements() { return fs != null ? viewer.getElements() : new IFeatureTableElement[0]; } public IFeatureTableElement[] getSelectedElements() { return viewer.getSelectedElements(); } public void createPartControl(@SuppressWarnings("hiding") Composite parent) { if (initLayer.get() != null) { init(initLayer.get()); } else { if (layer == null) { log.warn("No layer set. Closing view..."); Label msg = new Label(parent, SWT.NONE); msg.setText("No layer."); close(null); } else { init(layer); } } this.parent = parent; this.parent.setLayout(new FormLayout()); // check fs -> error message if (fs == null) { Label msg = new Label(parent, SWT.NONE); msg.setText("No feature pipeline for layer: " + (layer != null ? layer.getLabel() : "???")); return; } viewer = new FeatureTableViewer(parent, SWT.MULTI); viewer.getTable().setLayoutData(new SimpleFormData().fill().create()); viewer.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { if (ev.getPropertyName().equals(FeatureTableViewer.PROP_CONTENT_SIZE)) { Integer count = (Integer) ev.getNewValue(); setPartName(basePartName + " (" + count + ")"); } } }); viewer.addSelectionChangedListener(this); // double-click viewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent ev) { log.info("doubleClick(): " + ev); //IAction openHandler = getViewSite().getActionBars().getGlobalActionHandler( "org.polymap.rhei.OpenFormAction" ); if (openAction != null) { openAction.run(null); } } }); // columns assert fs != null : "fs not set. Call init() first."; SimpleFeatureType schema = fs.getSchema(); for (PropertyDescriptor prop : schema.getDescriptors()) { if (Geometry.class.isAssignableFrom(prop.getType().getBinding())) { // skip Geometry } else { viewer.addColumn(new DefaultFeatureTableColumn(prop)); } } viewer.getTable().pack(true); getSite().setSelectionProvider(viewer); hookContextMenu(); loadTable(filter); } protected void hookContextMenu() { final MenuManager contextMenu = new MenuManager("#PopupMenu"); contextMenu.setRemoveAllWhenShown(true); contextMenu.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { // Other plug-ins can contribute there actions here manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); //manager.add( new Separator() ); // TreeSelection sel = (TreeSelection)viewer.getSelection(); // if (!sel.isEmpty() && sel.getFirstElement() instanceof IMap) { // ProjectView.this.fillContextMenu( manager ); // } } }); Menu menu = contextMenu.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); getSite().registerContextMenu(contextMenu, viewer); } protected void loadTable(@SuppressWarnings("hiding") Filter filter) { this.filter = filter; viewer.setContent(fs, filter); } /** * */ class FeatureSelectionListener implements PropertyChangeListener { /** * Other party has changed feature selection. */ @EventHandler(display = true) public void propertyChange(final PropertyChangeEvent ev) { // select if (ev.getPropertyName().equals(LayerFeatureSelectionManager.PROP_FILTER)) { loadTable((Filter) ev.getNewValue()); } // hover else if (ev.getPropertyName().equals(LayerFeatureSelectionManager.PROP_HOVER)) { LayerFeatureSelectionManager fsm = (LayerFeatureSelectionManager) ev.getSource(); if (fsm.getHovered() != null) { viewer.removeSelectionChangedListener(FeatureSelectionView.this); viewer.selectElement(fsm.getHovered(), true); viewer.addSelectionChangedListener(FeatureSelectionView.this); } } } } /** * */ class ModelListener { @EventHandler(display = true) public void propertyChange(PropertyChangeEvent ev) { String propName = ev.getPropertyName(); if (PROP_ENTITY_REMOVED.equals(propName)) { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); page.hideView(FeatureSelectionView.this); } else if (PROP_GEORESID.equals(propName)) { try { fs = PipelineFeatureSource.forLayer(layer, false); loadTable(filter); } catch (Exception e) { PolymapWorkbench.handleError(DataPlugin.PLUGIN_ID, this, "", e); } } } } /* * Element was selected in the table. */ public void selectionChanged(SelectionChangedEvent ev) { SelectionAdapter sel = new SelectionAdapter(ev.getSelection()); IFeatureTableElement elm = sel.first(IFeatureTableElement.class); if (elm != null) { LayerFeatureSelectionManager fsm = LayerFeatureSelectionManager.forLayer(layer); fsm.setHovered(elm.fid()); } } public void setFocus() { } }