net.refractions.udig.tool.select.TableView.java Source code

Java tutorial

Introduction

Here is the source code for net.refractions.udig.tool.select.TableView.java

Source

/*
 *    uDig - User Friendly Desktop Internet GIS client
 *    http://udig.refractions.net
 *    (C) 2004-2011, Refractions Research Inc.
 *
 *    This library 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;
 *    version 2.1 of the License.
 *
 *    This library 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 net.refractions.udig.tool.select;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import net.refractions.udig.aoi.AOIListener;
import net.refractions.udig.aoi.IAOIService;
import net.refractions.udig.core.IBlockingProvider;
import net.refractions.udig.core.IProvider;
import net.refractions.udig.core.StaticBlockingProvider;
import net.refractions.udig.core.filter.AdaptingFilter;
import net.refractions.udig.core.filter.AdaptingFilterFactory;
import net.refractions.udig.internal.ui.UDIGDropHandler;
import net.refractions.udig.project.EditManagerEvent;
import net.refractions.udig.project.IEditManagerListener;
import net.refractions.udig.project.ILayer;
import net.refractions.udig.project.ILayerListener;
import net.refractions.udig.project.IMapCompositionListener;
import net.refractions.udig.project.LayerEvent;
import net.refractions.udig.project.MapCompositionEvent;
import net.refractions.udig.project.command.AbstractCommand;
import net.refractions.udig.project.command.CompositeCommand;
import net.refractions.udig.project.command.MapCommand;
import net.refractions.udig.project.command.UndoableCommand;
import net.refractions.udig.project.command.UndoableComposite;
import net.refractions.udig.project.command.factory.EditCommandFactory;
import net.refractions.udig.project.command.factory.SelectionCommandFactory;
import net.refractions.udig.project.command.provider.FIDFeatureProvider;
import net.refractions.udig.project.internal.Layer;
import net.refractions.udig.project.internal.Map;
import net.refractions.udig.project.internal.ProjectPlugin;
import net.refractions.udig.project.internal.commands.edit.DeleteFeatureCommand;
import net.refractions.udig.project.internal.commands.edit.DeleteManyFeaturesCommand;
import net.refractions.udig.project.ui.ApplicationGIS;
import net.refractions.udig.project.ui.IUDIGView;
import net.refractions.udig.project.ui.internal.MapEditor;
import net.refractions.udig.project.ui.internal.MapPart;
import net.refractions.udig.project.ui.internal.tool.display.ToolManager;
import net.refractions.udig.project.ui.tool.IToolContext;
import net.refractions.udig.project.ui.tool.ToolsConstants;
import net.refractions.udig.tool.select.internal.Messages;
import net.refractions.udig.tool.select.internal.ZoomSelection;
import net.refractions.udig.ui.FeatureTableControl;
import net.refractions.udig.ui.IDropAction;
import net.refractions.udig.ui.IDropHandlerListener;
import net.refractions.udig.ui.IFeatureTableLoadingListener;
import net.refractions.udig.ui.PlatformGIS;
import net.refractions.udig.ui.ProgressManager;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.internal.UIPlugin;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureEvent;
import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureStore;
import org.geotools.data.Query;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.Schema;
import org.geotools.filter.FilterAttributeExtractor;
import org.geotools.filter.IllegalFilterException;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureVisitor;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.Id;
import org.opengis.filter.IncludeFilter;
import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.Intersects;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

/**
 * Table view for selected Layer, may choose
 * to display FeatureSource with out supporting selection
 * in the future.
 * </p>
 * Currently this is a playground using the FeatureTable
 * to look at a FeautreSource, syncing up the slection
 * with the Layer's filter will come next.
 * </p>
 * <p>
 * Long term responsibilities include:
 * <ul>
 * <li>Access to a Filter editor for selection specification
 * <li>Allowing in view edits
 * <li>Real random access for shapefile allowing the table view
 *     everyone expects (tm)
 * </ul>
 * @author Jody Garnett, Refractions Research, Inc.
 * @since 0.6
 * @version 1.3.0
 */
public class TableView extends ViewPart implements ISelectionProvider, IUDIGView {

    private static final String INITIAL_TEXT = Messages.TableView_search;

    protected static final String ANY = Messages.TableView_search_any;
    protected static final String CQL = "CQL";

    /** filter the content by the current AOI */
    private boolean aoiFilter = false;

    /** Used to show the current feature source */
    FeatureTableControl table;

    /** Current editor */
    MapPart currentEditor;

    /** Current layer under study */
    Layer layer;

    /** Toolbar entry used to turn on selection mode */
    private IAction select;

    /**
     * This listener watches the workbench selection and reports
     * back anything that.
     */
    private ISelectionListener workbenchSelectionListener = new ISelectionListener() {
        public void selectionChanged(IWorkbenchPart part, ISelection selection) {
            if (part instanceof MapPart) {
                editorActivated((MapPart) part);
                return; // we already have sorted out map / layer
            }
            if (!(selection instanceof IStructuredSelection)) {
                return;
            }
            if (part == getSite().getPart()) {
                // we are swapping to ourself!
                return; // ignore
            }

            Object selected = ((IStructuredSelection) selection).getFirstElement();

            final Layer selectedLayer;
            // this is horribly inelegant. is there not some other way?
            if (selected instanceof Map) {
                selectedLayer = ((Map) selected).getEditManagerInternal().getSelectedLayer();
            } else if (selected instanceof Layer) {
                selectedLayer = (Layer) selected;
            } else if (selected instanceof IAdaptable) {
                // This is often an AdaptableFilter
                IAdaptable adaptable = (IAdaptable) selected;
                selectedLayer = (Layer) adaptable.getAdapter(Layer.class);
            } else {
                return;
            }

            if (selectedLayer != null) {
                PlatformGIS.run(new ISafeRunnable() {
                    public void handleException(Throwable exception) {
                        SelectPlugin.log("error selecting layer", exception); //$NON-NLS-1$
                    }

                    public void run() throws Exception {
                        layerSelected(selectedLayer);
                    }
                });

                //todo add layer event
            }
        }
    };

    /**
     * page that the part listener and the workbenchSelectionListener are listening to.
     */
    private IWorkbenchPage page;

    /**
     * Listener that deactivates/reactivates view when it is hidden/shown
     */
    private IPartListener2 activePartListener;

    private MenuManager contextMenu;

    /**
     * Indicates whether the view is visible and therefore is active
     */
    private volatile boolean active = false;

    /**
     * Indicates that the features in the view need to be reloaded when the view is visible again. 
     */
    protected volatile boolean reloadNeeded = false;

    /**
     * Indicates that the selection filter has changed while inactive 
     */
    protected volatile boolean filterChange = false;

    /**
     * Indicates that the a feature is being updated by the table view so 
     * it is not necessary to load the change indicated by the feature event.
     */
    protected volatile boolean editing = false;

    /**
     * Indicates that the selection of the table is being updated by the view because
     * the filter has been updated on the layer.
     */
    private volatile boolean updatingSelection = false;

    /**
     * Indicates that the view is updating the layer's filter because the selection on the table has changed.
     */
    protected volatile boolean updatingLayerFilter;

    private PromoteSelectionAction promoteSelection;

    private Label featuresSelected;

    private Combo attributeCombo;

    private IAction zoom;
    private IAction deleteAction;

    private Button selectAllCheck;

    private Text searchWidget;

    private AOIListener aoiServiceListener;

    /**
     * Construct <code>SelectView</code>.
     * <p>
     * Don't do setup here - there is an init method you can override that has
     * access to configuration and stuff.
     * </p>
     */
    public TableView() {
        super();
    }

    @Override
    public void createPartControl(Composite parent) {
        active = true;

        featuresSelected = new Label(parent, SWT.NONE);
        featuresSelected.setText(Messages.TableView_featureSelected + 0);

        attributeCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
        attributeCombo.setItems(new String[] { ANY, CQL });
        attributeCombo.select(0);
        attributeCombo.setEnabled(false);

        SearchBox search = new SearchBox();
        searchWidget = search.createPart(parent);

        IProvider<IProgressMonitor> provider = new IProvider<IProgressMonitor>() {

            public IProgressMonitor get(Object... params) {
                IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
                statusLineManager.setCancelEnabled(true);
                return statusLineManager.getProgressMonitor();
            }

        };

        // Select All Button
        selectAllCheck = new Button(parent, SWT.CHECK);
        selectAllCheck.setText(Messages.TableView_allCheckText);
        selectAllCheck.setToolTipText(Messages.TableView_allToolTip);
        selectAllCheck.setEnabled(false);
        selectAllCheck.setSelection(true);

        table = new FeatureTableControl(provider);
        table.createTableControl(parent);
        table.setSelectionColor(new IProvider<RGB>() {

            public RGB get(Object... params) {
                ScopedPreferenceStore store = ProjectPlugin.getPlugin().getPreferenceStore();
                String key = net.refractions.udig.project.preferences.PreferenceConstants.P_SELECTION_COLOR;
                RGB color = PreferenceConverter.getColor(store, key);
                return color;
            }

        });

        IAOIService aOIService = PlatformGIS.getAOIService();

        aoiServiceListener = new AOIListener() {
            @Override
            public void handleEvent(Event event) {
                if (isAOIFilter()) {
                    reloadFeatures(layer);
                }
            }
        };

        aOIService.addListener(aoiServiceListener);

        table.addLoadingListener(new IFeatureTableLoadingListener() {

            public void loadingStarted(IProgressMonitor monitor) {
                searchWidget.setEnabled(false);
                selectAllCheck.setEnabled(false);
                attributeCombo.setEnabled(false);
            }

            public void loadingStopped(boolean canceled) {
                searchWidget.setEnabled(true);
                selectAllCheck.setEnabled(true);
                attributeCombo.setEnabled(true);
            }

        });
        layoutComponents(parent);

        // Create menu and toolbars
        createActions();
        createMenu();
        createToolbar();
        hookGlobalActions();
        createContextMenu();

        // restore state (from previous session)

        page = getSite().getPage();

        if (page.getActiveEditor() instanceof MapPart) {
            editorActivated((MapPart) page.getActiveEditor());
        }

        addTableSelectionListener();
        addWorkbenchSelectionListener();
        addPageListener();

        //provide workbench selections
        getSite().setSelectionProvider(this);

        ApplicationGIS.getToolManager().registerActionsWithPart(this);

    }

    public boolean isAOIFilter() {
        return aoiFilter;
    }

    public void setAOIFilter(boolean aoiFilter) {
        this.aoiFilter = aoiFilter;
        reloadFeatures(layer);
    }

    private void addTableSelectionListener() {
        table.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged(SelectionChangedEvent event) {
                if (event.getSource() == table)
                    featuresSelected.setText(Messages.TableView_featureSelected + table.getSelectionCount());
                if (updatingSelection) {
                    updatingSelection = false;
                    return;
                }

                ISelection selection = getSelection();
                if (selection.isEmpty()) {
                    updateLayerFilter((Filter) Filter.EXCLUDE);
                } else if (selection instanceof IStructuredSelection) {
                    IStructuredSelection structuredSelection = (IStructuredSelection) selection;
                    Filter firstElement = (Filter) structuredSelection.getFirstElement();
                    updateLayerFilter(firstElement);
                }
                //TODO Sprint Mauricio Aritz: The next line provoke the SelectionTool cannot execute the commit operation (acceptChangeBehaviour line 109). 
                // Actually we do not understand the purpose of this line, but it is the source of problem.  
                //layer.getMapInternal().getEditManagerInternal().setEditFeature(null, null);

                fireSelectionChanged();
            }
        });
    }

    private void updateLayerFilter(Filter filter) {
        updatingLayerFilter = true;
        MapCommand createSelectCommand = SelectionCommandFactory.getInstance().createSelectCommand(layer, filter);
        layer.getMap().sendCommandSync(createSelectCommand);
        updatingLayerFilter = false;

        setZoomToSelectionToolEnablement();
    }

    private void layoutComponents(Composite parent) {
        FormLayout layout = new FormLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.spacing = 0;
        parent.setLayout(layout);

        FormData dLabel = new FormData(); // bind to left & text
        dLabel.left = new FormAttachment(0, 5);
        dLabel.top = new FormAttachment(attributeCombo, 2);
        dLabel.right = new FormAttachment(100, -5);
        featuresSelected.setLayoutData(dLabel);

        FormData dCombo = new FormData(); // bind to label and text
        dCombo.left = new FormAttachment(0, 5);
        dCombo.top = new FormAttachment(0);
        dCombo.right = new FormAttachment(30, -5);
        attributeCombo.setLayoutData(dCombo);

        FormData dText = new FormData(); // bind to label and text
        dText.left = new FormAttachment(attributeCombo);
        dText.top = new FormAttachment(0);
        dText.right = new FormAttachment(95, -5);
        searchWidget.setLayoutData(dText);

        FormData dCheck = new FormData(); // bind to top, label, bbox
        dCheck.top = new FormAttachment(2);
        dCheck.left = new FormAttachment(searchWidget, 5);
        dCheck.right = new FormAttachment(100, -5);
        selectAllCheck.setLayoutData(dCheck);

        FormData dContents = new FormData(100, 100); // text & bottom
        dContents.right = new FormAttachment(100); // bind to right of form
        dContents.left = new FormAttachment(0); // bind to left of form
        dContents.top = new FormAttachment(featuresSelected, 2); // attach with 2 pixel offset
        dContents.bottom = new FormAttachment(100); // bind to bottom of form        
        table.getControl().setLayoutData(dContents);
    }

    /**
     * Adds a post selection listener that listens to the workbench's selection for maps, layers or MapEditor.
     */
    private void addWorkbenchSelectionListener() {
        // page.addPostSelectionListener(workbenchSelectionListener);        
        ISelectionService selectionService = getSite().getWorkbenchWindow().getSelectionService();
        selectionService.addPostSelectionListener(workbenchSelectionListener);
    }

    /**
     * Adds a listener to {@link #page} that deactivates the view when part is hidden and reactivates it when it is made
     * visible.  This is to prevent a bunch of featurestore accesses when view is not visible. 
     */
    private void addPageListener() {
        activePartListener = new IPartListener2() {
            public void partActivated(IWorkbenchPartReference partRef) {
            }

            public void partBroughtToTop(IWorkbenchPartReference partRef) {
            }

            public void partClosed(IWorkbenchPartReference partRef) {
            }

            public void partDeactivated(IWorkbenchPartReference partRef) {
            }

            public void partOpened(IWorkbenchPartReference partRef) {
            }

            public void partHidden(IWorkbenchPartReference partRef) {
                if (partRef.getPart(false) == TableView.this)
                    deactivate();
            }

            public void partVisible(IWorkbenchPartReference partRef) {
                if (partRef.getPart(false) == TableView.this)
                    activate();
            }

            public void partInputChanged(IWorkbenchPartReference partRef) {
            }
        };
        // listen for editor changes
        page.addPartListener(activePartListener);
    }

    protected void activate() {
        if (active)
            return;

        PlatformGIS.run(new ISafeRunnable() {

            public void handleException(Throwable exception) {
                SelectPlugin.log("error activating table", exception); //$NON-NLS-1$
            }

            public void run() throws Exception {
                active = true;
                if (reloadNeeded)
                    reloadFeatures(layer);
                if (!updates.isEmpty())
                    updateTable(layer);
                if (filterChange)
                    updateSelection(layer);
            }

        });
    }

    protected void deactivate() {
        active = false;
    }

    private void hookGlobalActions() {
        ApplicationGIS.getToolManager().contributeGlobalActions(this, getViewSite().getActionBars());
        IKeyBindingService service = getSite().getKeyBindingService();
        IAction action = deleteAction;
        getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.DELETE.getId(), action);
        service.registerAction(action);

    }

    /**
     * Create actions, linking view to current map.
     */
    private void createActions() {
        select = ApplicationGIS.getToolManager().createToolAction(BBoxSelection.ID,
                ToolsConstants.SELECTION_CATEGORY);
        ImageDescriptor icon = AbstractUIPlugin.imageDescriptorFromPlugin(SelectPlugin.ID,
                "icons/eview16/select_view.gif"); //$NON-NLS-1$
        select.setImageDescriptor(icon);

        this.promoteSelection = new PromoteSelectionAction();

        zoom = ((ToolManager) ApplicationGIS.getToolManager()).createToolAction(ZoomSelection.ID,
                ToolsConstants.ZOOM_CATEGORY);
        icon = AbstractUIPlugin.imageDescriptorFromPlugin(SelectPlugin.ID, "icons/elcl16/zoom_select_co.png"); //$NON-NLS-1$
        zoom.setImageDescriptor(icon);
        zoom.setText(Messages.TableView_zoomToolText);
        zoom.setToolTipText(Messages.TableView_zoomToolToolTip);

        deleteAction = new DeleteAction();
    }

    /* Called when a Layer is selected - will need to check if we care */
    void layerSelected(ILayer selected) {
        if (layer == selected) {
            return; // we already know
        }
        if (layer != null) {
            layer.removeListener(layerListener);
            if (layer.getMap() != null) {
                layer.getMap().removeMapCompositionListener(compositionListener);
                layer.getMap().getEditManager().removeListener(editManagerListener);
            }
        }

        if (selected == null || !selected.hasResource(FeatureSource.class) || selected.getMap() == null) {
            if (currentEditor != null) {
                currentEditor.getMap().getEditManager().addListener(editManagerListener);
            }
            layer = null;
            filterChange = false;
            reloadNeeded = false;
            table.getControl().getDisplay().asyncExec(new Runnable() {
                public void run() {
                    table.clear();
                    table.message(Messages.TableView_noFeatureWarning);
                }
            });
            return;
        }

        layer = (Layer) selected;
        layer.addListener(layerListener);
        layer.getMap().addMapCompositionListener(compositionListener);
        layer.getMap().getEditManager().addListener(editManagerListener);

        if (!active) {
            filterChange = true;
            reloadNeeded = true;
            return;
        }

        setZoomToSelectionToolEnablement();
        reloadFeatures(layer);
        updateSelection(layer);
    }

    private void setZoomToSelectionToolEnablement() {
        final boolean enabled;

        if (layer.getMap() == ApplicationGIS.getActiveMap() && layer.getFilter() != Filter.EXCLUDE)
            enabled = true;
        else
            enabled = false;

        table.getControl().getDisplay().asyncExec(new Runnable() {
            public void run() {
                zoom.setEnabled(enabled);
            }
        });
    }

    /**
     * The list of updates that have occurred but have not yet been applied to the FeatureTable
     */
    private List<FeatureEvent> updates = Collections.synchronizedList(new ArrayList<FeatureEvent>());

    /**
     * Listener that watches the current layer; and will update the table selection to match
     */
    private ILayerListener layerListener = new ILayerListener() {

        public void refresh(LayerEvent event) {
            final ILayer notifierLayer = event.getSource();
            assert layer == notifierLayer;

            switch (event.getType()) {
            case EDIT_EVENT:
                if (!editing) {
                    if (event.getNewValue() == null) {
                        // there are now bounds associated with this event so we are going to have to reload everyone!
                        reloadFeatures(notifierLayer);
                        return;
                    }
                    // okay we will add these bounds to the list of "updates" and updateTable can fetch everything
                    // when we are back to being "active"
                    updates.add((FeatureEvent) event.getNewValue());
                    if (active) {
                        updateTable(notifierLayer);
                    }
                }
                break;
            case FILTER:
                if (active) {
                    updateSelection(notifierLayer);
                } else {
                    filterChange = true;
                }
                break;
            }

        }

    };

    private IMapCompositionListener compositionListener = new IMapCompositionListener() {

        public void changed(MapCompositionEvent event) {

            if (event.getType() == MapCompositionEvent.EventType.REMOVED) {
                if (event.getLayer() == layer) {
                    layerSelected(null);
                }
            } else if (event.getType() == MapCompositionEvent.EventType.MANY_REMOVED) {
                if (((List<?>) event.getNewValue()).contains(layer))
                    layerSelected(null);
            }
        }

    };

    private IEditManagerListener editManagerListener = new IEditManagerListener() {

        public void changed(EditManagerEvent event) {
            assert layer == null || (layer != null && layer.getMap() == event.getSource().getMap());

            switch (event.getType()) {
            case EditManagerEvent.POST_COMMIT:
            case EditManagerEvent.POST_ROLLBACK:
                if (!active) {
                    reloadNeeded = true;
                    return;
                }
                reloadFeatures(layer);
                break;
            case EditManagerEvent.SELECTED_LAYER:
                layerSelected((ILayer) event.getNewValue());
                break;
            default:
                break;
            }
        }

    };
    private Set<ISelectionChangedListener> selectionChangeListeners = new CopyOnWriteArraySet<ISelectionChangedListener>();

    private IToolContext currentContext;

    /**
     * Watch current editor to indicate current selectable layers.
     * 
     * @param editor
     */
    protected void editorActivated(MapPart editor) {
        if (currentEditor == editor)
            return;

        currentEditor = editor;
        if (editor == null) {
            select.setEnabled(false);
            table.clear();
            table.update();
            return;
        }

        Map map = currentEditor.getMap();
        final ILayer selectedLayer = map.getEditManager().getSelectedLayer();
        // layerSelecte returns if layer==newLayer.  If both are null we still want to listen to map for a
        // layer being added (and selected).
        if (selectedLayer == null && layer == null) {
            map.getEditManager().addListener(editManagerListener);
            return;
        }

        PlatformGIS.run(new ISafeRunnable() {

            public void handleException(Throwable exception) {
                SelectPlugin.log("error selecting layer", exception); //$NON-NLS-1$
            }

            public void run() throws Exception {
                layerSelected(selectedLayer);
            }

        });
        if (selectedLayer != null)
            select.setEnabled(true);
    }

    private void createToolbar() {
        IToolBarManager toolbar = getViewSite().getActionBars().getToolBarManager();
        toolbar.add(select);
        toolbar.add(zoom);
        toolbar.add(promoteSelection);
    }

    private void createContextMenu() {
        contextMenu = new MenuManager();

        contextMenu.setRemoveAllWhenShown(true);
        contextMenu.addMenuListener(new IMenuListener() {

            public void menuAboutToShow(IMenuManager mgr) {
                contextMenu.add(deleteAction);
                contextMenu.add(zoom);
                contextMenu.add(promoteSelection);
                contextMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
                contextMenu.add(ApplicationGIS.getToolManager().createOperationsContextMenu(getSelection()));
                contextMenu.add(ActionFactory.EXPORT.create(getSite().getWorkbenchWindow()));
            }

        });

        // Create menu.
        table.setMenuManager(contextMenu);
        getSite().registerContextMenu(contextMenu, this);
    }

    private void createMenu() {
        // create view menu, consider sync
    }

    @Override
    public void setFocus() {
        hookGlobalActions();
        // select your "main" control
        if (table.getControl() != null)
            table.getControl().setFocus();
    }

    @Override
    public void dispose() {
        if (table != null)
            table.dispose();

        if (aoiServiceListener != null) {
            IAOIService aOIService = PlatformGIS.getAOIService();
            aOIService.removeListener(aoiServiceListener);
        }

        super.dispose();
        if (activePartListener != null)
            page.removePartListener(activePartListener);
        if (workbenchSelectionListener != null) {
            ISelectionService selectionService = getSite().getWorkbenchWindow().getSelectionService();
            selectionService.removePostSelectionListener(workbenchSelectionListener);
        }
        if (layer != null && layerListener != null)
            layer.removeListener(layerListener);
        table = null;
        activePartListener = null;
        workbenchSelectionListener = null;
        layer = null;
        layerListener = null;
    }

    protected void updateSelection(final ILayer notifierLayer) {
        if (!active) {
            filterChange = true;
            return;
        }
        if (updatingLayerFilter) {
            return; // our own table view is updating the selection (so we can ignore this
                    // notification)
        }

        try {
            final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = notifierLayer
                    .getResource(FeatureSource.class, null);
            filterChange = false;
            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    updatingSelection = true;
                    if (updatingLayerFilter) {
                        return; // we are updating table so please ignore this one
                    }
                    Filter filter = (Filter) notifierLayer.getFilter();
                    if (filter == Filter.EXCLUDE) {
                        table.setSelection(new StructuredSelection());
                        return;
                    }
                    AdaptingFilter adaptingFilter = AdaptingFilterFactory.createAdaptingFilter(filter);
                    adaptingFilter.addAdapter(featureSource);

                    StructuredSelection selection = new StructuredSelection(adaptingFilter);
                    table.setSelection(selection);
                }
            });
        } catch (IOException e) {
            SelectPlugin.log("", e); //$NON-NLS-1$
        }
    }

    protected void updateTable(final ILayer notifierLayer) {
        try {
            // Envelope indicating the bounds of the added features from all the updates currently available in the
            // updates field;
            Envelope addedBounds = null;
            // Envelope indicating the bounds of the modified features from all the updates currently available in the
            // updates field;
            Envelope modifiedBounds = null;

            synchronized (updates) {
                for (FeatureEvent event : updates) {
                    Envelope bounds = event.getBounds();
                    switch (event.getEventType()) {
                    case FeatureEvent.FEATURES_ADDED:
                        if (bounds != null) {
                            if (addedBounds == null) {
                                addedBounds = new Envelope(bounds);
                            } else {
                                addedBounds.expandToInclude(bounds);
                            }
                        }
                        break;
                    case FeatureEvent.FEATURES_REMOVED:
                        // With current Event API there is no way to know what was removed
                        reloadNeeded = true;
                        if (active)
                            reloadFeatures(notifierLayer);
                        return;

                    case FeatureEvent.FEATURES_CHANGED:
                        if (event.getBounds() == null) {
                            return;
                        }
                        if (modifiedBounds == null) {
                            modifiedBounds = new Envelope(bounds);
                        } else {
                            modifiedBounds.expandToInclude(bounds);
                        }
                        break;

                    default:
                        break;
                    }
                }
                updates.clear();
            }
            // check if we actually go something out of all that
            if (addedBounds == null && modifiedBounds == null) {
                // fine we did not get anything we will need to reload
                if (active) {
                    reloadFeatures(notifierLayer);
                } else {
                    reloadNeeded = true;
                }
                return;
            }
            // okay now we will do a query for everything in the added or modified bounds
            FeatureSource<SimpleFeatureType, SimpleFeature> source = notifierLayer.getResource(FeatureSource.class,
                    ProgressManager.instance().get());
            SimpleFeatureType schema = source.getSchema();

            FilterFactory fac = CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints());
            final List<String> queryAtts = obtainQueryAttributesForFeatureTable(schema);
            final DefaultQuery query = new DefaultQuery(schema.getName().getLocalPart(), Filter.EXCLUDE,
                    queryAtts.toArray(new String[0]));

            String name = schema.getGeometryDescriptor().getName().getLocalPart();
            // add new features
            if (addedBounds != null) {
                double minx = addedBounds.getMinX();
                double miny = addedBounds.getMinY();
                double maxx = addedBounds.getMaxX();
                double maxy = addedBounds.getMaxY();
                String srs = CRS.lookupIdentifier(schema.getCoordinateReferenceSystem(), false);
                BBOX bboxFilter = fac.bbox(name, minx, miny, maxx, maxy, srs);

                query.setFilter(bboxFilter);
                FeatureCollection<SimpleFeatureType, SimpleFeature> features = source.getFeatures(query);
                this.table.update(features);
            }
            // update modified features
            if (modifiedBounds != null) {
                double minx = modifiedBounds.getMinX();
                double miny = modifiedBounds.getMinY();
                double maxx = modifiedBounds.getMaxX();
                double maxy = modifiedBounds.getMaxY();
                String srs = CRS.lookupIdentifier(schema.getCoordinateReferenceSystem(), false);
                BBOX bboxFilter = fac.bbox(name, minx, miny, maxx, maxy, srs);

                query.setFilter(bboxFilter);
                FeatureCollection<SimpleFeatureType, SimpleFeature> features = source.getFeatures(query);
                this.table.update(features);
            }
        } catch (IOException e) {
            if (active) {
                reloadFeatures(notifierLayer);
            } else {
                reloadNeeded = true;
            }
        } catch (IllegalFilterException e) {
            if (active) {
                reloadFeatures(notifierLayer);
            } else {
                reloadNeeded = true;
            }
        } catch (FactoryException e) {
            if (active) {
                reloadFeatures(notifierLayer);
            } else {
                reloadNeeded = true;
            }
        }
    }

    private Filter addAOIFilter(Filter filter, CoordinateReferenceSystem dataCRS) {
        IAOIService aOIService = PlatformGIS.getAOIService();
        Geometry geometry = aOIService.getGeometry();

        if (aOIService.getExtent() == null)
            return filter;

        if (geometry == null) {
            // note we could make a BBOX query here and go faster
            geometry = JTS.toGeometry(aOIService.getExtent());
            if (geometry == null) {
                return filter; // no change!
            }
        }
        CoordinateReferenceSystem aoiCRS = aOIService.getCrs();
        if (aoiCRS != null && !CRS.equalsIgnoreMetadata(aoiCRS, dataCRS)) {
            try {
                MathTransform transform = CRS.findMathTransform(aoiCRS, dataCRS);
                geometry = JTS.transform(geometry, transform);
            } catch (TransformException outOfBounds) {
                return filter; // unable to use this bounds
            } catch (FactoryException notSupported) {
                return filter; // unable to use this bounds
            }
        }

        FilterFactory2 ff = (FilterFactory2) CommonFactoryFinder.getFilterFactory(null);

        String geomProperty = layer.getSchema().getGeometryDescriptor().getLocalName();
        Filter aoiFilter = ff.intersects(ff.property(geomProperty), ff.literal(geometry));

        return ff.and(aoiFilter, filter);
    }

    protected void reloadFeatures(final ILayer notifierLayer) {

        try {
            reloadNeeded = false;
            updates.clear();

            //        icon = getLayerIcon()
            final FeatureTypeCellModifier featureTypeCellModifier = new FeatureTypeCellModifier(notifierLayer) {
                @Override
                public Object getValue(Object element, String property) {
                    ApplicationGIS.getToolManager().unregisterActions(TableView.this);

                    return super.getValue(element, property);
                }

                @Override
                protected void makeModification(SimpleFeature feature, ILayer layer, String property, Object value,
                        Item item) {
                    if (value == null) {
                        // not a valid entry.
                        return;
                    }
                    TableItem tableItem = (TableItem) item;
                    Schema schema = new Schema();
                    int columnIndex = schema.getIndexOf(feature.getFeatureType(), property);
                    tableItem.setText(columnIndex + 1, value.toString());

                    UndoableComposite composite = new UndoableComposite();
                    composite.getCommands().add(new SetEditingFlag(true));

                    composite.getCommands().add(EditCommandFactory.getInstance().createSetAttributeCommand(feature,
                            layer, property, value));
                    composite.getFinalizerCommands().add(new SetEditingFlag(false));
                    layer.getMap().sendCommandASync(composite);
                }
            };

            final SimpleFeatureType schema = notifierLayer.getSchema();
            Filter filter = Filter.INCLUDE;
            final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = notifierLayer
                    .getResource(FeatureSource.class, null);
            final List<String> queryAtts = obtainQueryAttributesForFeatureTable(schema);

            //if the filter action is true, filter our results by the AOI service
            if (isAOIFilter()) {
                filter = addAOIFilter(filter, schema.getCoordinateReferenceSystem());
            }
            final Query query = new DefaultQuery(schema.getName().getLocalPart(), filter,
                    queryAtts.toArray(new String[0]));
            FeatureCollection<SimpleFeatureType, SimpleFeature> featuresF = featureSource.getFeatures(query);
            //AdaptableFeatureCollection adaptableCollection = new AdaptableFeatureCollection(features);

            final FeatureCollection<SimpleFeatureType, SimpleFeature> features = featuresF;
            //final Query query = new DefaultQuery(schema.getName().getLocalPart(), Filter.INCLUDE, queryAtts.toArray(new String[0]));

            //final FeatureCollection<SimpleFeatureType, SimpleFeature>  features = featureSource.getFeatures(query);
            //        final FeatureCollection<SimpleFeatureType, SimpleFeature>  features = featureSource.getFeatures();

            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    if (!table.showWarning(table.getControl().getDisplay())) {
                        //user doesn't want to show table.
                        return;
                    }

                    // we don't need to display the geometries, that's what the map is for.
                    queryAtts.add(0, ANY);
                    queryAtts.add(CQL);
                    attributeCombo.setItems(queryAtts.toArray(new String[0]));
                    attributeCombo.select(0);

                    AdaptableFeatureCollection adaptableCollection = new AdaptableFeatureCollection(features);

                    if (featureSource instanceof FeatureStore)
                        enableEditing(featureTypeCellModifier, query, adaptableCollection);

                    table.setFeatures(adaptableCollection);
                }

                private void enableEditing(final FeatureTypeCellModifier featureTypeCellModifier, final Query query,
                        AdaptableFeatureCollection adaptableCollection) {
                    adaptableCollection.addAdapter(featureTypeCellModifier);
                    ICellEditorListener[] keyBindingActivators = new ICellEditorListener[query
                            .getPropertyNames().length];
                    for (int i = 0; i < keyBindingActivators.length; i++) {
                        keyBindingActivators[i] = new ICellEditorListener() {
                            public void applyEditorValue() {
                                ApplicationGIS.getToolManager().registerActionsWithPart(TableView.this);
                            }

                            public void cancelEditor() {
                                applyEditorValue();
                            }

                            public void editorValueChanged(boolean oldValidState, boolean newValidState) {

                            }

                        };
                    }
                    adaptableCollection.addAdapter(keyBindingActivators);
                }
            });
        } catch (final IOException e) {
            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    table.message(e.getMessage());
                }
            });
        }
    }

    private List<String> obtainQueryAttributesForFeatureTable(final SimpleFeatureType schema) {
        final List<String> queryAtts = new ArrayList<String>();

        for (int i = 0; i < schema.getAttributeCount(); i++) {
            AttributeDescriptor attr = schema.getDescriptor(i);
            if (!(attr instanceof GeometryDescriptor)) {
                queryAtts.add(attr.getName().getLocalPart());
            }
        }
        return queryAtts;
    }

    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        selectionChangeListeners.add(listener);
    }

    public ISelection getSelection() {
        Id firstElement = getFilter();
        if (firstElement == null) {
            return new StructuredSelection();
        }
        AdaptingFilter filter = AdaptingFilterFactory.createAdaptingFilter(firstElement, layer);
        if (layer.getGeoResource().canResolve(FeatureSource.class)) {
            try {
                FeatureSource<?, ?> resolve = layer.getGeoResource().resolve(FeatureSource.class, null);
                FeatureCollection<?, ?> features = resolve.getFeatures(filter);
                filter.addAdapter(features);
            } catch (IOException e) {
                // TODO Handle IOException
                throw (RuntimeException) new RuntimeException().initCause(e);
            }
        }
        return new StructuredSelection(filter);
    }

    private Id getFilter() {
        IStructuredSelection selection = (IStructuredSelection) table.getSelection();
        if (selection.isEmpty())
            return null;

        Id firstElement = (Id) selection.getFirstElement();
        return firstElement;
    }

    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        selectionChangeListeners.remove(listener);
    }

    protected void fireSelectionChanged() {
        final SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection());
        for (ISelectionChangedListener listener : selectionChangeListeners) {
            final ISelectionChangedListener l = listener;
            SafeRunnable.run(new SafeRunnable() {
                public void run() {
                    l.selectionChanged(event);
                }
            });
        }
    }

    public void setSelection(ISelection selection) {
        table.setSelection(selection);
    }

    private class PromoteSelectionAction extends Action {

        public PromoteSelectionAction() {
            setText(Messages.TableView_promote_text);
            setToolTipText(Messages.TableView_promote_tooltip);
            setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(SelectPlugin.ID,
                    "icons/elcl16/promote_selection_co.gif")); //$NON-NLS-1$
        }

        @Override
        public void run() {
            table.promoteSelection();
        }

    }

    /**
     * Delete Action used to delete the currently selected feature.
     */
    private class DeleteAction extends Action {
        public DeleteAction() {
            setActionDefinitionId("org.eclipse.ui.edit.delete"); //$NON-NLS-1$
            IWorkbenchAction actionTemplate = ActionFactory.DELETE
                    .create(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
            setText(actionTemplate.getText());
            setToolTipText(actionTemplate.getToolTipText());
            setImageDescriptor(actionTemplate.getImageDescriptor());
            setDescription(actionTemplate.getDescription());
            setDisabledImageDescriptor(actionTemplate.getDisabledImageDescriptor());
        }

        @Override
        public void run() {
            IStructuredSelection selection = ((IStructuredSelection) table.getSelection());
            if (selection == null || selection.isEmpty() || table.getSelectionCount() == 0)
                return;

            Id filter = (Id) selection.getFirstElement();

            CompositeCommand composite;
            if (table.getSelectionCount() == 1) {
                composite = deleteFeature();
            } else {
                composite = deleteManyFeatures(filter);
            }

            layer.getMap().sendCommandASync(composite);
        }

        private CompositeCommand deleteFeature() {
            CompositeCommand composite = new CompositeCommand();
            composite.setName(Messages.TableView_compositeName);
            composite.getCommands().add(new SetEditingFlag(true));
            DeleteFromTableCommand deleteFromTableCommand = new DeleteFromTableCommand(layer);
            composite.getCommands().add(deleteFromTableCommand);
            IBlockingProvider<ILayer> layerProvider = new StaticBlockingProvider<ILayer>(layer);
            composite.getCommands().add(new DeleteFeatureCommand(deleteFromTableCommand, layerProvider));
            composite.getFinalizerCommands().add(new SetEditingFlag(false));
            return composite;
        }

        private CompositeCommand deleteManyFeatures(Id filter) {
            CompositeCommand composite = new CompositeCommand();
            composite.setName(Messages.TableView_compositeName);
            composite.getCommands().add(new SetEditingFlag(true));
            composite.getCommands().add(new DeleteManyFeaturesCommand(layer, filter));
            composite.getCommands().add(new DeleteFromTableCommand(layer));
            composite.getFinalizerCommands().add(new SetEditingFlag(false));
            return composite;
        }
    }

    private class DeleteFromTableCommand extends AbstractCommand
            implements UndoableCommand, IBlockingProvider<SimpleFeature> {

        private FeatureCollection<SimpleFeatureType, SimpleFeature> deletedFeatures;
        private Layer layer;

        public DeleteFromTableCommand(Layer layer) {
            this.layer = layer;
        }

        public void rollback(IProgressMonitor monitor) throws Exception {
            table.update(deletedFeatures);
        }

        public String getName() {
            return Messages.TableView_deleteCommandName;
        }

        public void run(IProgressMonitor monitor) throws Exception {
            deletedFeatures = table.deleteSelection();
        }

        public SimpleFeature get(IProgressMonitor monitor, Object... params) throws IOException {

            IBlockingProvider<ILayer> layerProvider = new StaticBlockingProvider<ILayer>(layer);
            String featureID = deletedFeatures.features().next().getID();
            IBlockingProvider<SimpleFeature> featureProvider = new FIDFeatureProvider(featureID, layerProvider);

            return featureProvider.get(monitor);
        }

    }

    private class SetEditingFlag extends AbstractCommand implements UndoableCommand {
        boolean oldState;
        final boolean newState;

        public SetEditingFlag(boolean newState) {
            this.newState = newState;
        }

        public void rollback(IProgressMonitor monitor) throws Exception {
            editing = oldState;
        }

        public String getName() {
            return "Set Editing Flag"; //$NON-NLS-1$
        }

        public void run(IProgressMonitor monitor) throws Exception {
            oldState = editing;
            editing = newState;
        }

    }

    public void editFeatureChanged(SimpleFeature feature) {
        if (feature == null) {
            return;
        }
        if (getContext().getEditManager().getSelectedLayer() != layer || updatingLayerFilter)
            return;

        if (table.getSelectionCount() == 1
                && getFilter().getIDs().toArray(new String[0])[0].equals(feature.getID()))
            return;

        updatingLayerFilter = true;
        try {
            StructuredSelection structuredSelection;
            structuredSelection = new StructuredSelection(feature);

            setSelection(structuredSelection);
        } finally {
            updatingLayerFilter = false;
        }
    }

    public IToolContext getContext() {
        return currentContext;
    }

    public void setContext(IToolContext newContext) {
        this.currentContext = newContext;
    }

    private class SearchBox extends AbstractHandler implements Listener {
        private Color systemColor;

        public void handleEvent(Event e) {
            if (e.keyCode == SWT.CR || e.keyCode == SWT.LF) {
                doSearch();
            }
        }

        public Text createPart(Composite parent) {
            final Text searchWidget = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.CANCEL);
            searchWidget.setEnabled(false);

            systemColor = searchWidget.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);

            searchWidget.setText(INITIAL_TEXT);
            searchWidget.setForeground(systemColor);
            searchWidget.setEditable(true);
            searchWidget.addListener(SWT.FocusIn, new Listener() {
                public void handleEvent(Event e) {
                    if (searchWidget.getForeground().equals(systemColor)) {
                        searchWidget.setForeground(e.display.getSystemColor(SWT.COLOR_BLACK));
                        searchWidget.setText(""); //$NON-NLS-1$
                    }
                    ApplicationGIS.getToolManager().unregisterActions(TableView.this);
                }
            });
            searchWidget.addListener(SWT.FocusOut, new Listener() {
                public void handleEvent(Event e) {
                    if (!searchWidget.getForeground().equals(systemColor)
                            && searchWidget.getText().trim().length() == 0) {
                        searchWidget.setForeground(systemColor);
                        searchWidget.setText(""); //$NON-NLS-1$
                    }
                    ApplicationGIS.getToolManager().registerActionsWithPart(TableView.this);
                }
            });
            searchWidget.addListener(SWT.KeyUp, this);
            return searchWidget;
        }

        public Object execute(ExecutionEvent arg0) throws ExecutionException {
            doSearch();
            return null;
        }

        @SuppressWarnings("unchecked")
        private void doSearch() {
            if (searchWidget.getText().trim().length() == 0) {
                searchWidget.setText(INITIAL_TEXT);
                searchWidget.setForeground(systemColor);
            }

            String[] attsToSearch;
            String item = attributeCombo.getItem(attributeCombo.getSelectionIndex());
            boolean selectAll = selectAllCheck.getSelection();
            if (item.equals(CQL)) {
                try {
                    String txt = searchWidget.getText().trim();
                    //table.select( txt, selectAll);
                    //searchWidget.setToolTipText(null);
                    Filter filter = (Filter) org.geotools.filter.text.cql2.CQL.toFilter(txt);
                    //updateLayerFilter( filter );

                    FeatureSource<SimpleFeatureType, SimpleFeature> source = layer.getResource(FeatureSource.class,
                            ProgressManager.instance().get());
                    SimpleFeatureType schema = source.getSchema();
                    //FilterFactory fac=CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints());
                    //final List<String> queryAtts = obtainQueryAttributesForFeatureTable(schema);

                    Set<String> required = (Set<String>) filter.accept(new FilterAttributeExtractor(), null);
                    String[] names = required.toArray(new String[required.size()]);
                    final DefaultQuery query = new DefaultQuery(schema.getName().getLocalPart(), filter, names);

                    FeatureCollection<SimpleFeatureType, SimpleFeature> features;
                    features = source.getFeatures(query); // we just want the FeatureID no attributes needed

                    //features = source.getFeatures( filter );

                    final Set<FeatureId> selection = new HashSet<FeatureId>();
                    features.accepts(new FeatureVisitor() {
                        public void visit(Feature feature) {
                            // we are using FeatureId to allow for a "temporary" FID when inserting content
                            // (a real FID is not assigned until commit)
                            //
                            FeatureId identifier = feature.getIdentifier();
                            selection.add(identifier);
                        }
                    }, null);
                    table.select(selection);
                } catch (Exception e) {
                    Status status = new Status(Status.WARNING, "net.refractions.udig.ui", e.getLocalizedMessage(),
                            e);
                    UIPlugin.getDefault().getLog().log(status);
                    searchWidget.setToolTipText(e.getLocalizedMessage());
                }
            } else {
                if (item.equals(ANY)) {
                    attsToSearch = FeatureTableControl.ALL;
                } else {
                    attsToSearch = new String[] { item };
                }
                table.select(searchWidget.getText().trim(), attsToSearch, selectAll);
            }
        }

    }

}