com.rcpcompany.uibindings.internal.ViewerBindingImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.rcpcompany.uibindings.internal.ViewerBindingImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2006-2013 The RCP Company and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     The RCP Company - initial API and implementation
 *******************************************************************************/
package com.rcpcompany.uibindings.internal;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.util.EObjectWithInverseEList;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.jface.databinding.viewers.IViewerValueProperty;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.layout.AbstractColumnLayout;
import org.eclipse.jface.viewers.CellNavigationStrategy;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.FocusCellHighlighter;
import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerEditor;
import org.eclipse.jface.viewers.TableViewerFocusCellManager;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerEditor;
import org.eclipse.jface.viewers.TreeViewerFocusCellManager;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;

import com.rcpcompany.uibindings.BindingState;
import com.rcpcompany.uibindings.Constants;
import com.rcpcompany.uibindings.ContainerCellType;
import com.rcpcompany.uibindings.IBinding;
import com.rcpcompany.uibindings.IBindingDataType;
import com.rcpcompany.uibindings.IChildCreationSpecification;
import com.rcpcompany.uibindings.IColumnBinding;
import com.rcpcompany.uibindings.IColumnBindingCellInformation;
import com.rcpcompany.uibindings.IElementParentage;
import com.rcpcompany.uibindings.IManager;
import com.rcpcompany.uibindings.ISourceProviderStateContext;
import com.rcpcompany.uibindings.IUIBindingsFactory;
import com.rcpcompany.uibindings.IUIBindingsPackage;
import com.rcpcompany.uibindings.IValueBinding;
import com.rcpcompany.uibindings.IValueBindingCell;
import com.rcpcompany.uibindings.IViewerBinding;
import com.rcpcompany.uibindings.UIBindingsEMFObservables;
import com.rcpcompany.uibindings.UIBindingsUtils;
import com.rcpcompany.uibindings.bindingMessages.ValidationLabelDecorator;
import com.rcpcompany.uibindings.fragments.jfaceif.IMyViewerFocusCellManager;
import com.rcpcompany.uibindings.internal.observables.properties.MySelectionProviderSingleSelectionProperty;
import com.rcpcompany.uibindings.internal.utils.DoubleClickAdapter;
import com.rcpcompany.uibindings.internal.utils.UIHandlerUtils;
import com.rcpcompany.uibindings.utils.IManagerRunnable;
import com.rcpcompany.utils.logging.LogUtils;

/**
 * <!-- begin-user-doc --> An implementation of the model object '<em><b>Viewer Binding</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 * <li>{@link com.rcpcompany.uibindings.internal.ViewerBindingImpl#getColumns <em>Columns</em>}</li>
 * <li>{@link com.rcpcompany.uibindings.internal.ViewerBindingImpl#getList <em>List</em>}</li>
 * <li>{@link com.rcpcompany.uibindings.internal.ViewerBindingImpl#getElements <em>Elements</em>}</li>
 * <li>{@link com.rcpcompany.uibindings.internal.ViewerBindingImpl#getMultipleSelection <em>Multiple
 * Selection</em>}</li>
 * <li>{@link com.rcpcompany.uibindings.internal.ViewerBindingImpl#getViewer <em>Viewer</em>}</li>
 * <li>{@link com.rcpcompany.uibindings.internal.ViewerBindingImpl#getFirstTableColumnOffset <em>
 * First Table Column Offset</em>}</li>
 * </ul>
 * </p>
 * 
 * @param <SWTFocusCellManager>
 * 
 * @generated
 */
public class ViewerBindingImpl extends ContainerBindingImpl implements IViewerBinding {
    @Override
    public IViewerBinding viewer(ColumnViewer viewer) {
        assertTrue(viewer != null, "viewer must be non-null");
        setViewer(viewer);

        if (getControl() instanceof Table) {
            /*
             * Add an empty first column to the table to avoid alignment problems
             */
            // TODO: only for Windows?
            final Table table = (Table) getControl();
            final TableColumn column = new TableColumn(table, SWT.NONE, 0);
            setFirstTableColumnOffset(1);
            column.setText("__SPARE__"); //$NON-NLS-1$
            column.setWidth(0);
            column.setMoveable(false);
            column.setResizable(false);

            /*
             * Check whether the table uses any special layout
             */
            Layout l = table.getParent().getLayout();
            if (l instanceof AbstractColumnLayout) {
                final AbstractColumnLayout layout = (AbstractColumnLayout) l;
                layout.setColumnData(column, new ColumnPixelData(0, false, false));
            }
            l = table.getLayout();
            if (l instanceof TableLayout) {
                final TableLayout layout = (TableLayout) l;
                layout.addColumnData(new ColumnPixelData(0, false, false));
            }
        }

        return this;
    }

    @Override
    public IViewerBinding viewer(Table t) {
        assertTrue(t != null, "viewer must be non-null");
        return viewer(new TableViewer(t));
    }

    @Override
    public IViewerBinding viewer(Tree t) {
        assertTrue(t != null, "viewer must be non-null");
        return viewer(new TreeViewer(t));
    }

    private IViewerBinding model(IObservableList list, IBindingDataType dataType, boolean disposeList) {
        assertTrue(list != null, "The list must be non-null");
        assertTrue(dataType != null, "The data type must be non-null");
        setList(list);
        setStaticDataType(dataType);
        for (final Object o : list) {
            assertTrue(o instanceof EObject, "Only EObjects are allowed in root elements of tree: " + o);
        }
        assertTrue(getModelEType() instanceof EClass,
                "The data type must be an EClass (and not an EDataType): " + getModelEType());
        myListDispose = disposeList;
        return this;
    }

    @Override
    public IViewerBinding model(IObservableList list) {
        assertTrue(list != null, "List must be non-null");
        return model(list, IBindingDataType.Factory.create(list), false);
    }

    @Override
    public IViewerBinding model(EObject object, EReference reference) {
        assertTrue(object != null, "Object must be non-null");
        assertTrue(reference != null, "Reference must be non-null");
        assertTrue(reference.isMany(), "Reference for viewer must be to-many: " + reference.getName());
        return model(UIBindingsEMFObservables.observeList(null, getEditingDomain(), object, reference),
                IBindingDataType.Factory.create(object.eClass(), reference), true);
    }

    @Override
    public IViewerBinding model(IObservableValue value, EReference reference) {
        assertTrue(value != null, "Value must be non-null");
        assertTrue(reference != null, "Reference must be non-null");
        assertTrue(reference.isMany(), "Reference for viewer must be to-many: " + reference.getName());
        return model(UIBindingsEMFObservables.observeDetailList(value, reference),
                IBindingDataType.Factory.create(value, reference), true);
    }

    @Override
    public IColumnBinding addColumn() {
        final IColumnBinding column = IUIBindingsFactory.eINSTANCE.createColumnBinding();
        column.setContext(getContext());
        column.setViewerBinding(this);
        return column;
    }

    @Override
    public IColumnBinding addColumn(ViewerColumn column, EStructuralFeature feature) {
        return addColumn().column(column).model(feature);
    }

    @Override
    public IColumnBinding addColumn(TableColumn column, EStructuralFeature feature) {
        return addColumn().column(column).model(feature);
    }

    @Override
    public IColumnBinding addColumn(TreeColumn column, EStructuralFeature feature) {
        return addColumn().column(column).model(feature);
    }

    @Override
    public IViewerBinding arg(String name, Object value) {
        assertTrue(name != null, "name must be non-null"); //$NON-NLS-1$
        getArguments().put(name.intern(), value);
        return this;
    }

    @Override
    public IViewerBinding args(Map<String, Object> arguments) {
        setArguments(arguments);
        return this;
    }

    @Override
    public IViewerBinding readonly() {
        return arg(Constants.ARG_READONLY, true);
    }

    @Override
    public IViewerBinding id(String id) {
        setId(id);
        return this;
    }

    @Override
    public IViewerBinding type(String type) {
        return arg(Constants.ARG_TYPE, type);
    }

    @Override
    public boolean isChangeable() {
        if (getArgument(Constants.ARG_READONLY, Boolean.class, Boolean.FALSE) == Boolean.TRUE)
            return false;

        return true;
    }

    /**
     * Adapter for the manager that insures the table is re-drawn when certain changes are made.
     */
    private final Adapter myManagerAdapter = new AdapterImpl() {
        @Override
        public void notifyChanged(Notification msg) {
            if (msg.isTouch())
                return;
            if (msg.getFeature() == IUIBindingsPackage.Literals.MANAGER__ALTERNATE_ROW_COLORS) {
                IManagerRunnable.Factory.asyncExec("refresh", getViewer(), new Runnable() {
                    @Override
                    public void run() {
                        // TODO SWTB
                        getViewer().refresh();
                    }
                });
            }
        }
    };

    /**
     * Private {@link CellNavigationStrategy}, which will not permit us to go to the first column!
     */
    private final CellNavigationStrategy theCellNavigationStrategy = new CellNavigationStrategy() {
        @Override
        public ViewerCell findSelectedCell(ColumnViewer viewer, ViewerCell currentSelectedCell, Event event) {
            switch (event.keyCode) {
            case SWT.ARROW_LEFT:
                // TODO: get IViewerBinding from control and turn this into a static
                if (currentSelectedCell != null
                        && currentSelectedCell.getColumnIndex() <= getFirstTableColumnOffset())
                    return currentSelectedCell;
                break;
            default:
                break;
            }

            return super.findSelectedCell(viewer, currentSelectedCell, event);
        }

    };

    /**
     * A {@link ILabelDecorator} (possibly <code>null</code>) for use in the viewer. The decorator
     * decorates with the current validation state.
     */
    private ValidationLabelDecorator myValidationLabelDecorator;

    /**
     * A binding used to show messages associated with the viewer itself.
     */
    private IValueBinding myMessagesOnlyValueBinding = null;

    @Override
    public ValidationLabelDecorator getValidationLabelDecorator() {
        return myValidationLabelDecorator;
    }

    @Override
    public Class<?> getUIType() {
        // Not used
        return null;
    }

    @Override
    public void finish1() {
        final ColumnViewer viewer = getViewer(); // TODO SWTB
        assertTrue(viewer != null, "No viewer set"); //$NON-NLS-1$
        assertTrue(getList() != null, "No model list"); //$NON-NLS-1$
        assertTrue(!getColumns().isEmpty(), "No columns in viewer"); //$NON-NLS-1$

        final Control control = getControl();
        assertTrue((control.getStyle() & SWT.FULL_SELECTION) != 0, "Viewer must have SWT.FULL_SELECTION set"); //$NON-NLS-1$
        // SWTEventUtils.swtListen(control);

        if (viewer instanceof TableViewer) {
            final ObservableListContentProvider contentProvider = new ObservableListContentProvider();
            viewer.setContentProvider(contentProvider);
            setElements(contentProvider.getKnownElements());
        } else if (viewer instanceof TreeViewer) {
            myTreeFactory = new ViewerBindingTreeFactory(getList(), getArgument(ARG_TREE_ID, String.class, null));
            final ObservableListTreeContentProvider contentProvider = new ObservableListTreeContentProvider(
                    myTreeFactory, myTreeFactory);
            viewer.setContentProvider(contentProvider);
            myValidationLabelDecorator = new ValidationLabelDecorator();
            myValidationLabelDecorator.setPropagationAdapter(new ValidationLabelDecorator.IPropagationAdapter() {
                @Override
                public Object getParent(Object object) {
                    if (isDisposed())
                        return null;
                    return contentProvider.getParent(object);
                }
            });
            setElements(contentProvider.getKnownElements());
        } else {
            assertTrue(false, "Viewer not a Table or a Tree?"); //$NON-NLS-1$
        }

        IManager.Factory.getManager().eAdapters().add(myManagerAdapter);
        control.addListener(SWT.PaintItem, myPaintItemListener);
        if ((control.getStyle() & SWT.SINGLE) == SWT.SINGLE) {
            mySelectionChangedListener = new ISelectionChangedListener() {
                @Override
                public void selectionChanged(SelectionChangedEvent event) {
                    myLastReportedSelectedElement = ((IStructuredSelection) event.getSelection()).getFirstElement();
                }
            };
            viewer.addSelectionChangedListener(mySelectionChangedListener);
        }
        registerWidget(control);

        /*
         * More or less adapted (read "stolen") from Snippet026TreeViewerTabEditing...
         * 
         * Actually it is more and more less and less...
         */
        final ColumnViewerEditorActivationStrategy actSupport = new CellEditorActivationStrategy(this);

        final FocusCellOwnerDrawHighlighter focusDrawingDelegate = new FocusCellOwnerDrawHighlighter(viewer);
        final int feature = ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
                | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION;
        try {
            if (viewer instanceof TableViewer) {
                final Class<?> cls = Class.forName("org.eclipse.jface.viewers.MyTableViewerFocusCellManager");
                final Constructor<?> constructor = cls.getConstructor(TableViewer.class, FocusCellHighlighter.class,
                        CellNavigationStrategy.class);
                myViewerFocusCellManager = (IMyViewerFocusCellManager) constructor.newInstance(viewer,
                        focusDrawingDelegate, theCellNavigationStrategy);
                TableViewerEditor.create((TableViewer) viewer,
                        (TableViewerFocusCellManager) myViewerFocusCellManager, actSupport, feature);
            } else if (viewer instanceof TreeViewer) {
                final Class<?> cls = Class.forName("org.eclipse.jface.viewers.MyTreeViewerFocusCellManager");
                final Constructor<?> constructor = cls.getConstructor(TreeViewer.class, FocusCellHighlighter.class,
                        CellNavigationStrategy.class);
                myViewerFocusCellManager = (IMyViewerFocusCellManager) constructor.newInstance(viewer,
                        focusDrawingDelegate, theCellNavigationStrategy);
                TreeViewerEditor.create((TreeViewer) viewer, (TreeViewerFocusCellManager) myViewerFocusCellManager,
                        actSupport, feature);
            } else {
                // Not supported
            }
        } catch (final Exception ex) {
            // Do nothing
        }

        if (getList() instanceof IObserving && getList().getElementType() instanceof EReference) {
            // final EObject baseObject = (EObject) ((IObserving) getList()).getObserved();
            // final EReference elementType = (EReference) getList().getElementType();

            myMessagesOnlyValueBinding = getContext().addBinding()
                    .ui(control, InternalConstants.ATTR_VIEWERS_MESSAGE_ONLY).model(getList())
                    .type(InternalConstants.VIEWERS_MESSAGE_ONLY_TYPE)
                    .arg(Constants.ARG_MODEL_OBJECT_MESSAGES, true);
        }
        ColumnViewerToolTipSupport.enableFor(viewer);
        DoubleClickAdapter.adapt(this);
    }

    /**
     * Listener that will request a re-flow of the context if/when the elements of the viewer
     * changes.
     * 
     * TODO TEST
     */
    private final ISetChangeListener myElementsListener = new ISetChangeListener() {
        @Override
        public void handleSetChange(SetChangeEvent event) {
            // if (event != null) {
            // LogUtils.debug(event, "remove " + event.diff.getRemovals().size() + " add "
            // + event.diff.getAdditions().size());
            // }

            /*
             * Remove rows as needed
             */
            if (event != null) {
                for (final Object o : event.diff.getRemovals()) {
                    for (final IColumnBinding c : getColumns()) {
                        final IColumnBindingCellInformation ci = c.getCellInformation(o, false);
                        if (ci != null) {
                            ci.dispose();
                        }
                    }
                }
            }

            /*
             * SIMA-182: Bug in UIBinding for table cell editor?
             * (http://jira.marintek.sintef.no/jira/browse/SIMA-182)
             * 
             * If a row is updated with a new row element, then item.data is properly updated, but
             * ViewerCell.element is not! This is a fix for that. Note it is only possible if the
             */
            final ViewerCell focusCell = getViewer().getColumnViewerEditor().getFocusCell();
            if (focusCell != null) {
                updateFocusCell();
                if (focusCell.getElement() != focusCell.getViewerRow().getElement()) {
                    LogUtils.debug(this, "FATAL ISSUE\ncell.element=" + focusCell.getElement() + "\nitem.date=" //$NON-NLS-1$ //$NON-NLS-2$
                            + focusCell.getViewerRow().getElement());
                }
            }

            if (getViewer().getSelection().isEmpty() && !getList().isDisposed() && getList().size() > 0) {
                final EObject element = (EObject) getList().get(0);
                getViewer().setSelection(new StructuredSelection(element), true);
                setFocus(0 + getFirstTableColumnOffset(), element);
                // TODO SWTB: setFocusCell(0,0);
            }

            /*
             * Reflow the context if the number of entries has changed
             */
            getContext().reflow();
            // if (event != null && event.diff != null) {
            // final Set<?> additions = event.diff.getAdditions();
            // final Set<?> removals = event.diff.getRemovals();
            // if (additions == null || removals == null || additions.size() != removals.size()) {
            // getContext().reflow();
            // }
            // }
        }
    };

    @Override
    public void finish3() {
        if (getViewer() instanceof TreeViewer) {
            getViewer().setInput(ViewerBindingTreeFactory.ROOT_ELEMENT); // TODO SWTB
        } else {
            getViewer().setInput(getList()); // TODO SWTB
        }

        getElements().addSetChangeListener(myElementsListener);
        myElementsListener.handleSetChange(null);
    }

    /**
     * The last element reported as selected - only used for viewers with style {@link SWT#SINGLE}.
     */
    private Object myLastReportedSelectedElement = null;

    /**
     * Listener to update {@link #myLastReportedSelectedElement}.
     */
    private ISelectionChangedListener mySelectionChangedListener = null;

    /**
     * The {@link SWT#PaintItem} listener is used to synchronize the current focus cell based on the
     * cell that is painted using the detail {@link SWT#SELECTED}.
     * <p>
     * See <a href="http://jira.marintek.sintef.no/jira/browse/SIMA-582">SIMA-582</a>: Selection is
     * not displayed properly in tables
     */
    private final Listener myPaintItemListener = new Listener() {
        @Override
        public void handleEvent(Event event) {
            if ((event.detail & SWT.SELECTED) != SWT.SELECTED)
                return;
            final Object element = event.item.getData();
            /*
             * If the viewer is based on a single selection, then check if the selection is in fact
             * the current element
             * 
             * This happens when the selection is set directly on the control rather than via the
             * viewer.
             */
            if (mySelectionChangedListener != null && myLastReportedSelectedElement != element) {
                getViewer().setSelection(new StructuredSelection(element), false); // TODO SWTB
            }
        }
    };

    @Override
    public IElementParentage getElementParentage(final EObject element) {
        if (getControl() instanceof Table) {
            if (!getList().contains(element))
                return null;
            return new IElementParentage() {
                @Override
                public EReference getReference() {
                    final IObservableList l = getList();
                    if (l.getElementType() instanceof EReference)
                        return (EReference) l.getElementType();
                    return null;
                }

                @Override
                public EObject getParent() {
                    final IObservableList l = getList();
                    if (l instanceof IObserving)
                        return (EObject) ((IObserving) l).getObserved();
                    return null;
                }

                @Override
                public EObject getElement() {
                    return element;
                }
            };
        }
        if (getControl() instanceof Tree)
            return myTreeFactory.getElementParentage(element);
        return null;
    };

    @Override
    public List<IChildCreationSpecification> getPossibleChildObjects(EObject parent, EObject sibling) {
        final Control control = getControl();
        if (control instanceof Table)
            return UIBindingsUtils.getPossibleTopLevelChildObjects(getList(), sibling);
        if (control instanceof Tree) {
            if (parent == null && sibling != null) {
                final IElementParentage parentage = getElementParentage(sibling);
                if (parentage != null) {
                    parent = parentage.getParent();
                }
            }
            if (parent == null)
                return UIBindingsUtils.getPossibleTopLevelChildObjects(getList(), sibling);
            return myTreeFactory.getPossibleChildObjects(parent, sibling);
        }
        return null;
    }

    @Override
    public void setFocus(int column, EObject element) {
        if (getControl().isDisposed())
            return;
        if (myViewerFocusCellManager != null) {
            myViewerFocusCellManager.setFocusCell(element, column);
            return;
        }
    }

    /**
     * Updates the current focus cell of the viewer.
     */
    public void updateFocusCell() {
        if (getControl().isDisposed())
            return;
        if (myViewerFocusCellManager != null) {
            myViewerFocusCellManager.updateFocusCell();
            return;
        }
    }

    @Override
    public void dispose() {
        if (isDisposed())
            return;
        setState(BindingState.DISPOSE_PENDING);
        disposeServices();
        final Control control = getControl();
        if (!control.isDisposed()) {
            unregisterWidget(control);
            control.removeListener(SWT.PaintItem, myPaintItemListener);
        }
        IManager.Factory.getManager().eAdapters().remove(myManagerAdapter);
        if (mySelectionChangedListener != null) {
            getViewer().removeSelectionChangedListener(mySelectionChangedListener);
            // TODO SWTB -

            // change to
            // widget
            // listener
            mySelectionChangedListener = null;
        }

        if (myMessagesOnlyValueBinding != null) {
            myMessagesOnlyValueBinding.dispose();
            myMessagesOnlyValueBinding = null;
        }

        /*
         * Let the viewer clean up before we dispose the input list
         */
        if (getViewer().getContentProvider() != null) { // TODO SWTB
            getViewer().setInput(null);
        }
        /*
         * Need to check the basic list here...
         */
        final IObservableList l = getList();
        if (l != null && myListDispose) {
            /*
             * Need to reset the list first, as we will other wiese refers to the disposed list in
             * the notifiers.
             */
            setList(null);
            l.dispose();
            myListDispose = false;
        }

        if (getElements() != null) {
            getElements().dispose();
        }
        if (eIsSet(IUIBindingsPackage.Literals.CONTAINER_BINDING__SINGLE_SELECTION)) {
            getSingleSelection().dispose();
        }
        if (eIsSet(IUIBindingsPackage.Literals.VIEWER_BINDING__MULTIPLE_SELECTION)) {
            getMultipleSelection().dispose();
        }

        if (myTreeFactory != null) {
            myTreeFactory.dispose();
            myTreeFactory = null;
        }

        for (final IColumnBinding b : getColumns().toArray(new IColumnBinding[getColumns().size()])) {
            b.dispose();
        }

        super.dispose();
    }

    @Override
    public Control getControl() {
        return getViewer().getControl();
    }

    @Override
    public IValueBindingCell getCell(int column, int row, boolean visualModel) {
        if (getList().size() <= row)
            return null;
        if (getColumns().size() <= column)
            return null;
        final IColumnBinding cb = getColumns().get(column);
        return cb.getCellInformation(getList().get(row));
    }

    @Override
    public IColumnBindingCellInformation getCell(int columnNo, Object element) {
        final EList<IColumnBinding> cols = getColumns();
        if (columnNo < 0)
            return null;
        if (columnNo > cols.size())
            return null;
        if (element == null)
            return null;
        // Based on the model column order
        final IColumnBinding column = cols.get(columnNo);
        final IColumnBindingCellInformation ci = column.getCellInformation(element);
        return ci;
    }

    /**
     * The cached value of the '{@link #getColumns() <em>Columns</em>}' reference list. <!--
     * begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getColumns()
     * @generated
     * @ordered
     */
    protected EList<IColumnBinding> columns;

    /**
     * The default value of the '{@link #getList() <em>List</em>}' attribute. <!-- begin-user-doc
     * --> <!-- end-user-doc -->
     * 
     * @see #getList()
     * @generated
     * @ordered
     */
    protected static final IObservableList LIST_EDEFAULT = null;

    /**
     * The cached value of the '{@link #getList() <em>List</em>}' attribute. <!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * 
     * @see #getList()
     * @generated
     * @ordered
     */
    protected IObservableList list = LIST_EDEFAULT;
    /**
     * <code>true</code> if {@link #list} should be disposed by {@link #dispose()}.
     */
    private boolean myListDispose = true;

    /**
     * The default value of the '{@link #getElements() <em>Elements</em>}' attribute. <!--
     * begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getElements()
     * @generated
     * @ordered
     */
    protected static final IObservableSet ELEMENTS_EDEFAULT = null;

    /**
     * The cached value of the '{@link #getElements() <em>Elements</em>}' attribute. <!--
     * begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getElements()
     * @generated
     * @ordered
     */
    protected IObservableSet elements = ELEMENTS_EDEFAULT;

    /**
     * The default value of the '{@link #getMultipleSelection() <em>Multiple Selection</em>}'
     * attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getMultipleSelection()
     * @generated
     * @ordered
     */
    protected static final IObservableList MULTIPLE_SELECTION_EDEFAULT = null;

    /**
     * The cached value of the '{@link #getMultipleSelection() <em>Multiple Selection</em>}'
     * attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getMultipleSelection()
     * @generated
     * @ordered
     */
    protected IObservableList multipleSelection = MULTIPLE_SELECTION_EDEFAULT;

    /**
     * The default value of the '{@link #getViewer() <em>Viewer</em>}' attribute. <!--
     * begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getViewer()
     * @generated
     * @ordered
     */
    protected static final ColumnViewer VIEWER_EDEFAULT = null;

    /**
     * The cached value of the '{@link #getViewer() <em>Viewer</em>}' attribute. <!-- begin-user-doc
     * --> <!-- end-user-doc -->
     * 
     * @see #getViewer()
     * @generated
     * @ordered
     */
    protected ColumnViewer viewer = VIEWER_EDEFAULT;

    /**
     * The default value of the '{@link #getFirstTableColumnOffset()
     * <em>First Table Column Offset</em>}' attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getFirstTableColumnOffset()
     * @generated
     * @ordered
     */
    protected static final int FIRST_TABLE_COLUMN_OFFSET_EDEFAULT = 0;

    /**
     * The cached value of the '{@link #getFirstTableColumnOffset()
     * <em>First Table Column Offset</em>}' attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @see #getFirstTableColumnOffset()
     * @generated
     * @ordered
     */
    protected int firstTableColumnOffset = FIRST_TABLE_COLUMN_OFFSET_EDEFAULT;

    /**
     * Adapter used to track the current cursor to use in the viewer.
     */
    private final Adapter myCursorAdapter = new AdapterImpl() {
        @Override
        public void notifyChanged(Notification msg) {
            if (msg.isTouch())
                return;

            if (msg.getFeature() == IUIBindingsPackage.Literals.VIEWER_BINDING__COLUMNS) {
                switch (msg.getEventType()) {
                case Notification.REMOVE:
                case Notification.SET:
                    final IColumnBinding c = (IColumnBinding) msg.getOldValue();
                    c.eAdapters().remove(this);
                    break;
                default:
                    break;
                }
                switch (msg.getEventType()) {
                case Notification.ADD:
                case Notification.SET:
                    final IColumnBinding c = (IColumnBinding) msg.getNewValue();
                    c.eAdapters().add(this);
                    break;
                default:
                    break;
                }
                updateCursor();
            } else if (msg.getFeature() == IUIBindingsPackage.Literals.COLUMN_BINDING__CURSOR) {
                updateCursor();
            }
        };

        public void updateCursor() {
            getControl().getDisplay().syncExec(new Runnable() {
                @Override
                public void run() {
                    for (final IColumnBinding col : getColumns()) {
                        final Cursor c = col.getCursor();
                        if (c != null) {
                            getControl().setCursor(c);
                            return;
                        }
                    }
                    getControl().setCursor(null);
                }
            });
        }
    };

    private IMyViewerFocusCellManager myViewerFocusCellManager;

    private ViewerBindingTreeFactory myTreeFactory;

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated NOT
     */
    public ViewerBindingImpl() {
        super();

        eAdapters().add(myCursorAdapter);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    protected EClass eStaticClass() {
        return IUIBindingsPackage.Literals.VIEWER_BINDING;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public EList<IColumnBinding> getColumns() {
        if (columns == null) {
            columns = new EObjectWithInverseEList<IColumnBinding>(IColumnBinding.class, this,
                    IUIBindingsPackage.VIEWER_BINDING__COLUMNS, IUIBindingsPackage.COLUMN_BINDING__VIEWER_BINDING);
        }
        return columns;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated NOT
     */
    @Override
    public IObservableList getList() {
        if (list == null) {
            list = WritableList.withElementType(getDataType().getDataType());
        }
        return list;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    public void setList(IObservableList newList) {
        final IObservableList oldList = list;
        list = newList;
        if (eNotificationRequired()) {
            eNotify(new ENotificationImpl(this, Notification.SET, IUIBindingsPackage.VIEWER_BINDING__LIST, oldList,
                    list));
        }
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public IObservableSet getElements() {
        return elements;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    public void setElements(IObservableSet newElements) {
        final IObservableSet oldElements = elements;
        elements = newElements;
        if (eNotificationRequired()) {
            eNotify(new ENotificationImpl(this, Notification.SET, IUIBindingsPackage.VIEWER_BINDING__ELEMENTS,
                    oldElements, elements));
        }
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated NOT
     */
    @Override
    public IObservableValue getSingleSelection() {
        // TODO SWTB
        if (super.getSingleSelection() == null) {
            final IViewerValueProperty property = new MySelectionProviderSingleSelectionProperty() {
                @Override
                public Object getValueType() {
                    return getList().getElementType();
                }
            };
            singleSelection = property.observe(viewer);
        }
        return super.getSingleSelection();
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated NOT
     */
    @Override
    public IObservableList getMultipleSelection() {
        // TODO SWTB
        if (multipleSelection == null) {
            multipleSelection = ViewersObservables.observeMultiSelection(getViewer());
        }
        return multipleSelection;
    }

    @Override
    public Collection<EObject> getSelection() {
        if (getControl() instanceof Table) {
            final Table t = (Table) getControl();
            final Collection<EObject> s = new ArrayList<EObject>(t.getSelectionCount());
            for (final int i : t.getSelectionIndices()) {
                s.add((EObject) getList().get(i));
            }

            return s;
        }
        if (getControl() instanceof Tree) {
            final Tree t = (Tree) getControl();
            final Collection<EObject> s = new ArrayList<EObject>(t.getSelectionCount());
            for (final TreeItem i : t.getSelection()) {
                s.add((EObject) i.getData());
            }

            return s;
        }
        return Collections.EMPTY_LIST;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated NOT
     * @deprecated will be removed
     */
    @Deprecated
    @Override
    public ColumnViewer getViewer() {
        return viewer;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    public void setViewer(ColumnViewer newViewer) {
        final ColumnViewer oldViewer = viewer;
        viewer = newViewer;
        if (eNotificationRequired()) {
            eNotify(new ENotificationImpl(this, Notification.SET, IUIBindingsPackage.VIEWER_BINDING__VIEWER,
                    oldViewer, viewer));
        }
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public int getFirstTableColumnOffset() {
        return firstTableColumnOffset;
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    public void setFirstTableColumnOffset(int newFirstTableColumnOffset) {
        final int oldFirstTableColumnOffset = firstTableColumnOffset;
        firstTableColumnOffset = newFirstTableColumnOffset;
        if (eNotificationRequired()) {
            eNotify(new ENotificationImpl(this, Notification.SET,
                    IUIBindingsPackage.VIEWER_BINDING__FIRST_TABLE_COLUMN_OFFSET, oldFirstTableColumnOffset,
                    firstTableColumnOffset));
        }
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @SuppressWarnings("unchecked")
    @Override
    public NotificationChain eInverseAdd(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
        switch (featureID) {
        case IUIBindingsPackage.VIEWER_BINDING__COLUMNS:
            return ((InternalEList<InternalEObject>) (InternalEList<?>) getColumns()).basicAdd(otherEnd, msgs);
        }
        return super.eInverseAdd(otherEnd, featureID, msgs);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
        switch (featureID) {
        case IUIBindingsPackage.VIEWER_BINDING__COLUMNS:
            return ((InternalEList<?>) getColumns()).basicRemove(otherEnd, msgs);
        }
        return super.eInverseRemove(otherEnd, featureID, msgs);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public Object eGet(int featureID, boolean resolve, boolean coreType) {
        switch (featureID) {
        case IUIBindingsPackage.VIEWER_BINDING__COLUMNS:
            return getColumns();
        case IUIBindingsPackage.VIEWER_BINDING__LIST:
            return getList();
        case IUIBindingsPackage.VIEWER_BINDING__ELEMENTS:
            return getElements();
        case IUIBindingsPackage.VIEWER_BINDING__MULTIPLE_SELECTION:
            return getMultipleSelection();
        case IUIBindingsPackage.VIEWER_BINDING__VIEWER:
            return getViewer();
        case IUIBindingsPackage.VIEWER_BINDING__FIRST_TABLE_COLUMN_OFFSET:
            return getFirstTableColumnOffset();
        }
        return super.eGet(featureID, resolve, coreType);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @SuppressWarnings("unchecked")
    @Override
    public void eSet(int featureID, Object newValue) {
        switch (featureID) {
        case IUIBindingsPackage.VIEWER_BINDING__COLUMNS:
            getColumns().clear();
            getColumns().addAll((Collection<? extends IColumnBinding>) newValue);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__LIST:
            setList((IObservableList) newValue);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__ELEMENTS:
            setElements((IObservableSet) newValue);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__VIEWER:
            setViewer((ColumnViewer) newValue);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__FIRST_TABLE_COLUMN_OFFSET:
            setFirstTableColumnOffset((Integer) newValue);
            return;
        }
        super.eSet(featureID, newValue);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public void eUnset(int featureID) {
        switch (featureID) {
        case IUIBindingsPackage.VIEWER_BINDING__COLUMNS:
            getColumns().clear();
            return;
        case IUIBindingsPackage.VIEWER_BINDING__LIST:
            setList(LIST_EDEFAULT);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__ELEMENTS:
            setElements(ELEMENTS_EDEFAULT);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__VIEWER:
            setViewer(VIEWER_EDEFAULT);
            return;
        case IUIBindingsPackage.VIEWER_BINDING__FIRST_TABLE_COLUMN_OFFSET:
            setFirstTableColumnOffset(FIRST_TABLE_COLUMN_OFFSET_EDEFAULT);
            return;
        }
        super.eUnset(featureID);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated
     */
    @Override
    public boolean eIsSet(int featureID) {
        switch (featureID) {
        case IUIBindingsPackage.VIEWER_BINDING__COLUMNS:
            return columns != null && !columns.isEmpty();
        case IUIBindingsPackage.VIEWER_BINDING__LIST:
            return LIST_EDEFAULT == null ? list != null : !LIST_EDEFAULT.equals(list);
        case IUIBindingsPackage.VIEWER_BINDING__ELEMENTS:
            return ELEMENTS_EDEFAULT == null ? elements != null : !ELEMENTS_EDEFAULT.equals(elements);
        case IUIBindingsPackage.VIEWER_BINDING__MULTIPLE_SELECTION:
            return MULTIPLE_SELECTION_EDEFAULT == null ? multipleSelection != null
                    : !MULTIPLE_SELECTION_EDEFAULT.equals(multipleSelection);
        case IUIBindingsPackage.VIEWER_BINDING__VIEWER:
            return VIEWER_EDEFAULT == null ? viewer != null : !VIEWER_EDEFAULT.equals(viewer);
        case IUIBindingsPackage.VIEWER_BINDING__FIRST_TABLE_COLUMN_OFFSET:
            return firstTableColumnOffset != FIRST_TABLE_COLUMN_OFFSET_EDEFAULT;
        }
        return super.eIsSet(featureID);
    }

    /**
     * <!-- begin-user-doc --> <!-- end-user-doc -->
     * 
     * @generated NOT
     */
    @Override
    public String toString() {
        return super.toString();
    }

    @Override
    protected String getBaseType() {
        final IBindingDataType dt = IBindingDataType.Factory.create(getList());
        return dt.getBaseType();
    }

    @Override
    public Widget getWidget() {
        return getControl();
    }

    @Override
    public IBinding dynamic() {
        // TODO: error?
        return this;
    }

    @Override
    public IBinding label(String label) {
        return this;
    }

    @Override
    public IBinding validValues(IObservableList list) {
        return this;
    }

    @Override
    public IBinding validValues(EObject obj, EReference reference) {
        assertTrue(false, "Cannot set validValues");
        return this;
    }

    @Override
    public void updateSourceProviderState(ISourceProviderStateContext context) {
        final ColumnViewer viewer = getViewer();

        context.putSourceValue(Constants.SOURCES_ACTIVE_CONTAINER_BINDING, this);
        context.putSourceValue(Constants.SOURCES_ACTIVE_CONTAINER_BINDING_NO_CAF,
                (viewer.getComparator() == null && viewer.getFilters().length == 0));

        context.putSourceValue(Constants.SOURCES_ACTIVE_VIEWER_ELEMENT_TYPE, getModelType());

        EObject element = null;
        int columnIndex = -1;
        ContainerCellType type = null;

        ViewerCell cell;
        /*
         * If no specific position is specified in the event (x,y) = (0,0), then try using the
         * current focus cell. This is needed when navigating in the table.
         * 
         * Also do this if the widget of the event is not this viewers control. That happens when
         * extra widgets are mapped to this binding with IBinding.registerWidget()
         */
        final Event event = context.getEvent();
        final Point point = context.getLocation();
        if (event.x == 0 && event.y == 0 || event.widget != getControl()) {
            cell = viewer.getColumnViewerEditor().getFocusCell();
        } else {
            cell = viewer.getCell(point);
        }
        if (cell != null) {
            element = (EObject) cell.getElement();
            columnIndex = cell.getColumnIndex();
            type = ContainerCellType.DATA;
        } else {
            final Control c = viewer.getControl();
            if (c instanceof Table) {
                final Table t = (Table) c;
                final TableItem item = t.getItem(point);
                if (item != null) {
                    element = (EObject) item.getData();
                    type = ContainerCellType.ROW_TRAILER;
                } else {
                    /*
                     * Below or above the table?
                     */
                    if (point.y < 0) {
                        type = ContainerCellType.COLUMN_HEADER;
                    } else {
                        type = ContainerCellType.COLUMN_TRAILER;
                    }
                }
            }
            if (c instanceof Tree) {
                final Tree t = (Tree) c;
                final TreeItem item = t.getItem(point);
                if (item != null) {
                    element = (EObject) item.getData();
                    type = ContainerCellType.ROW_TRAILER;
                } else {
                    /*
                     * Below or above the tree?
                     */
                    if (point.y < 0) {
                        type = ContainerCellType.COLUMN_HEADER;
                    } else {
                        type = ContainerCellType.COLUMN_TRAILER;
                    }
                }
            }
        }

        if (type != null) {
            context.putSourceValue(Constants.SOURCES_ACTIVE_CONTAINER_CELL_TYPE, type.toString());
        }
        if (element != null) {
            context.putSourceValue(Constants.SOURCES_ACTIVE_VIEWER_ELEMENT, element);
            context.putSourceValue(Constants.SOURCES_ACTIVE_VIEWER_ELEMENT_MOVE_UP,
                    UIHandlerUtils.moveElement(this, element, -1, true));
            context.putSourceValue(Constants.SOURCES_ACTIVE_VIEWER_ELEMENT_MOVE_DOWN,
                    UIHandlerUtils.moveElement(this, element, 1, true));
        }

        if (columnIndex >= getFirstTableColumnOffset() && element != null) {
            final IColumnBindingCellInformation ci = getCell(columnIndex - getFirstTableColumnOffset(), element);
            final IObservableValue objectValue = ci.getObjectValue();
            final Object value = objectValue.getValue();

            final IValueBinding labelBinding = ci.getLabelBinding();
            context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING, labelBinding);
            context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_RO, !ci.isChangeable());
            context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_VALUE, value);
            context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_TYPE, ""); //$NON-NLS-1$
            if (labelBinding != null) {
                context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_MODEL_OBJECT,
                        labelBinding.getModelObject());
                context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_FEATURE, labelBinding.getModelFeature());
                context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_UNSETTABLE,
                        labelBinding.getDataType().isUnsettable());
                context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_IS_SET, isSet(labelBinding));
            }
            context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_VALUE_DISPLAY, ci.getDisplayText());

            context.addObservedValue(ci.getLabelUIAttribute().getCurrentValue());
        }

        context.setSelectionProvider(getViewer());
    }

    private boolean isSet(IValueBinding vb) {
        final EObject eObject = vb.getModelObject();
        final EStructuralFeature feature = vb.getModelFeature();
        if (eObject == null || feature == null)
            return false;
        return eObject.eIsSet(feature);
    }

    @Override
    public IContainerDropContext getDropContext(final DropTargetEvent event) {
        final Control control = getControl();
        final Point point = control.toControl(new Point(event.x, event.y));
        final ViewerCell vcell = getViewer().getCell(point);
        if (vcell == null) //
            return null;
        final IColumnBindingCellInformation cell = getCell(vcell.getColumnIndex() - getFirstTableColumnOffset(),
                vcell.getElement());

        return new IContainerDropContext() {
            @Override
            public EObject getDropTargetObject() {
                final IObservableValue valueOV = cell.getSourceValue();
                if (valueOV == null)
                    return null;
                final Object value = valueOV.getValue();
                if (value instanceof EObject)
                    return (EObject) value;
                return null;
                // final Widget item = event.item;
                // if (item == null) return null;
                // if (item.getData() instanceof EObject) return (EObject) item.getData();
                // return null;
            }

            @Override
            public float getDropLocation() {
                final Control control = getControl();
                final Point point = control.toControl(new Point(event.x, event.y));
                final Rectangle bounds;
                if (event.item instanceof TreeItem) {
                    bounds = ((TreeItem) event.item).getBounds();
                } else if (event.item instanceof TableItem) {
                    bounds = ((TableItem) event.item).getBounds(0);
                } else
                    return 0.0F;

                return (float) (point.y - bounds.y) / (float) bounds.height;
            }

            @Override
            public IValueBindingCell getDropCell() {
                return cell;
            }

            @Override
            public List<IChildCreationSpecification> getPossibleChildObjects(EObject parent, EObject sibling) {
                return ViewerBindingImpl.this.getPossibleChildObjects(parent, sibling);
            }
        };
    }

    /**
     * Whether there are an outstanding asyncExec for fireLabelProviderChanged()..
     */
    protected Set<EObject> myHasOutstandingFireLabelProviderChangedSet = new HashSet<EObject>();

    @Override
    public void updateCellsForElement(EObject element) {
        /*
         * No need to do anything more if we already have an outstanding request...
         */
        final Control control = getViewer().getControl();
        if (control.isDisposed())
            return;
        synchronized (myHasOutstandingFireLabelProviderChangedSet) {
            if (myHasOutstandingFireLabelProviderChangedSet.contains(element))
                return;
            myHasOutstandingFireLabelProviderChangedSet.add(element);
        }
        if (Activator.getDefault().TRACE_EVENTS_LABELPROVIDERS) {
            //LogUtils.debug(ci.getLabelBinding(), ci.getLabelBinding() + " label changed"); //$NON-NLS-1$
        }
        IManagerRunnable.Factory.asyncExec("labels", this, new Runnable() {
            @Override
            public void run() {
                if (control.isDisposed())
                    return;
                if (Activator.getDefault().TRACE_EVENTS_LABELPROVIDERS) {
                    //LogUtils.debug(ci.getLabelBinding(), "label changed (fired)"); //$NON-NLS-1$
                }
                // LogUtils.debug(this, "!!fire " + element);

                Object[] elements;
                synchronized (myHasOutstandingFireLabelProviderChangedSet) {
                    elements = myHasOutstandingFireLabelProviderChangedSet.toArray();
                    myHasOutstandingFireLabelProviderChangedSet.clear();
                }
                /*
                 * Find the label provider of the first real column
                 */
                final IColumnBinding cb = getColumns().get(0);
                cb.fireLabelChanged(elements);
            }
        });
    }
} // ViewerBindingImpl