Java tutorial
/* * polymap.org Copyright 2013 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.kaps.ui; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.beans.PropertyChangeEvent; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.geotools.data.FeatureStore; import org.opengis.feature.Feature; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.polymap.core.data.ui.featuretable.FeatureTableViewer; import org.polymap.core.model.Entity; import org.polymap.core.model.EntityType; import org.polymap.core.project.ui.util.SimpleFormData; import org.polymap.rhei.data.entityfeature.ReloadablePropertyAdapter.CompositeProvider; import org.polymap.rhei.field.IFormField; import org.polymap.rhei.field.IFormFieldListener; import org.polymap.rhei.form.IFormEditorPageSite; import org.polymap.kaps.ui.NamedCompositesFeatureContentProvider.FeatureTableElement; /** * @author <a href="http://www.polymap.de">Steffen Stundzig</a> */ public abstract class KapsDefaultFormEditorPageWithFeatureTable<T extends Entity> extends KapsDefaultFormEditorPage { private static Log log = LogFactory.getLog(KapsDefaultFormEditorPageWithFeatureTable.class); public class LastNameInvocationHandler implements InvocationHandler { private String lastCall; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // do nothing if ("toString".equals(method.getName())) { return lastCall; } lastCall = method.getName(); return null; } } protected FeatureStore featureStore; private FeatureTableViewer viewer; private boolean dirty; private List<T> model = new ArrayList<T>(); protected CompositeProvider<T> selectedComposite = new CompositeProvider<T>(); private Set<T> deletedComposites = new HashSet<T>(); protected List<IFormField> reloadables = new ArrayList<IFormField>(); private boolean updatingElements; protected final T nameTemplate; public KapsDefaultFormEditorPageWithFeatureTable(Class<T> type, String id, String title, Feature feature, FeatureStore featureStore) { super(id, title, feature, featureStore); nameTemplate = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { type }, new LastNameInvocationHandler()); } @Override public void createFormContent(final IFormEditorPageSite site) { super.createFormContent(site); } protected abstract EntityType addViewerColumns(FeatureTableViewer viewer); protected void refreshReloadables() throws Exception { // log.info("refreshReloadables"); // Thread.currentThread().dumpStack(); boolean enabled = selectedComposite.get() != null; for (IFormField field : reloadables) { field.setEnabled(enabled); field.load(); } dirty = false; } protected IFormField reloadable(IFormField formField) { reloadables.add(formField); return formField; } /** * * @param parent */ protected Composite createTableForm(Composite parent, Control top) { return createTableForm(parent, top, false); } protected Composite createTableForm(Composite parent, Control top, boolean addAllowed) { return createTableForm(parent, top, addAllowed, true); } protected Composite createTableForm(Composite parent, Control top, boolean addAllowed, boolean deleteAllowed) { return createTableForm(parent, top, addAllowed, deleteAllowed, false); } protected Composite createTableForm(Composite parent, Control top, boolean addAllowed, boolean deleteAllowed, boolean copyAllowed) { int TOPSPACING = 20; viewer = new FeatureTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.getTable().setLayoutData(new SimpleFormData().fill().left(0).height(100).right(85) .top(top, TOPSPACING).bottom(100).create()); // columns EntityType<T> type = addViewerColumns(viewer); // model/content viewer.setContent(new NamedCompositesFeatureContentProvider(null, type)); // try { // doLoad( new NullProgressMonitor() ); // } // catch (Exception e) { // throw new RuntimeException( e ); // } ActionButton addBtn = null; if (addAllowed) { AddCompositeAction<T> addAction = new AddCompositeAction<T>() { protected void execute() throws Exception { dirty = true; T newComposite = createNewComposite(); selectedComposite.set(newComposite); model.add(0, newComposite); doLoad(new NullProgressMonitor()); viewer.getTable().deselectAll(); viewer.getTable().select(((NamedCompositesFeatureContentProvider) viewer.getContentProvider()) .getIndicesForElements(newComposite)); // refreshReloadables(); // refreshReloadables is triggered bei selection event(); } }; addBtn = new ActionButton(parent, addAction); addBtn.setLayoutData(new SimpleFormData().left(viewer.getTable(), 6).top(top, TOPSPACING).right(100) .height(30).create()); } ActionButton copyBtn = null; if (copyAllowed) { CopyCompositeAction<T> copyAction = new CopyCompositeAction<T>() { protected void execute() throws Exception { if (selectedComposite.get() != null) { T toCopy = selectedComposite.get(); dirty = true; T newComposite = createNewComposite(); selectedComposite.set(newComposite); model.add(0, newComposite); doLoad(new NullProgressMonitor()); viewer.getTable().deselectAll(); viewer.getTable() .select(((NamedCompositesFeatureContentProvider) viewer.getContentProvider()) .getIndicesForElements(newComposite)); copyCompositeData(toCopy); } } }; copyBtn = new ActionButton(parent, copyAction); copyBtn.setLayoutData(new SimpleFormData().left(viewer.getTable(), 6) .top(addBtn != null ? addBtn : top, addBtn != null ? SPACING : TOPSPACING).right(100).height(30) .create()); } if (deleteAllowed) { DeleteCompositeAction<T> deleteAction = new DeleteCompositeAction<T>() { protected void execute() throws Exception { if (selectedComposite.get() != null) { T toSelect = selectedComposite.get(); model.remove(toSelect); if (viewer != null) { Collection<T> viewerInput = (Collection<T>) viewer.getInput(); viewerInput.remove(toSelect); } queueDeleteComposite(toSelect); selectedComposite.set(null); // pageSite.reloadEditor(); doLoad(new NullProgressMonitor()); // refreshReloadables(); dirty = true; // pageSite.fireEvent( this, id, // IFormFieldListener.VALUE_CHANGE, null ); // viewer.refresh( true ); } } }; ActionButton delBtn = new ActionButton(parent, deleteAction); Control topBtn = copyBtn != null ? copyBtn : addBtn; delBtn.setLayoutData(new SimpleFormData().left(viewer.getTable(), 6) .top(topBtn != null ? topBtn : top, topBtn != null ? SPACING : TOPSPACING).right(100).height(30) .create()); } parent.layout(true); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { if (!updatingElements) { // Felder fr ausgewhlten Eintrag in UI wurden gendert // keine Selektion hier StructuredSelection selection = (StructuredSelection) event.getSelection(); FeatureTableElement tableRow = (FeatureTableElement) selection.getFirstElement(); if (tableRow != null) { selectedComposite.set((T) tableRow.getComposite()); try { refreshReloadables(); } catch (Exception e) { e.printStackTrace(); } } } } }); if (model.size() > 0) { viewer.getTable().select(0); } return viewer.getTable(); } protected void queueDeleteComposite(final T toSelect) { deletedComposites.add(toSelect); queue(new UpdateCommand() { @Override public void execute() { deleteComposite(toSelect); } }); } protected void deleteComposite(T toSelect) { repository.removeEntity(toSelect); } protected T createNewComposite() throws Exception { // must only be implemented if add-action on table is enabled throw new RuntimeException("not yet implemented."); } protected void copyCompositeData(T toCopy) { // must only be implemented if copy-action on table is enabled throw new RuntimeException("not yet implemented."); } public void updateElements(Collection<T> coll) { if (viewer != null && !viewer.isBusy()) { updatingElements = true; viewer.refresh(true); updatingElements = false; } } protected abstract Iterable<T> getElements(); public void doLoad(IProgressMonitor monitor) throws Exception { if (viewer != null && !viewer.isBusy()) { // model = new HashMap(); for (T elm : getElements()) { if (!model.contains(elm) && !deletedComposites.contains(elm)) { // TODO wie wird der EventHandler registriert? // elm.addPropertyChangeListener( this ); model.add(elm); } } // transform to list viewer.setInput(model); // viewer.refresh( true ); if (model.size() > 0) { viewer.getTable().select(0); selectedComposite.set(model.get(0)); } } if (pageSite != null) { refreshReloadables(); } super.doLoad(monitor); dirty = false; } public void doSubmit(IProgressMonitor monitor) throws Exception { if (model != null) { updateElements(model); } deletedComposites.clear(); super.doSubmit(monitor); dirty = false; } /** * Handles Value property changes. */ public void propertyChange(PropertyChangeEvent evt) { try { dirty = true; // update dirty/valid flags of the editor pageSite.fireEvent(this, id, IFormFieldListener.VALUE_CHANGE, null); if (!viewer.isBusy()) { viewer.refresh(true); } } catch (Exception e) { throw new RuntimeException(e); } } @Override public void dispose() { super.dispose(); if (model != null) { model.clear(); model = null; } // viewer.dispose(); } public List<T> getModel() { return model; } }