/*******************************************************************************
* 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.grid.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListDiffVisitor;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.EMap;
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.EcoreEMap;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.nebula.widgets.grid.Grid;
import org.eclipse.nebula.widgets.grid.GridColumn;
import org.eclipse.nebula.widgets.grid.GridItem;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
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.Listener;
import org.eclipse.swt.widgets.Widget;
import com.rcpcompany.uibindings.BindingState;
import com.rcpcompany.uibindings.Constants;
import com.rcpcompany.uibindings.IBinding;
import com.rcpcompany.uibindings.IBindingContext;
import com.rcpcompany.uibindings.IBindingDataType;
import com.rcpcompany.uibindings.IChildCreationSpecification;
import com.rcpcompany.uibindings.IManager;
import com.rcpcompany.uibindings.ISourceProviderStateContext;
import com.rcpcompany.uibindings.IUIAttribute;
import com.rcpcompany.uibindings.IUIBindingsPackage;
import com.rcpcompany.uibindings.IValueBinding;
import com.rcpcompany.uibindings.IValueBindingCell;
import com.rcpcompany.uibindings.UIBindingsUtils;
import com.rcpcompany.uibindings.bindingMessages.ValidationLabelDecorator;
import com.rcpcompany.uibindings.grid.IGridBinding;
import com.rcpcompany.uibindings.grid.IGridBindingCellEditor;
import com.rcpcompany.uibindings.grid.IGridBindingCellInformation;
import com.rcpcompany.uibindings.grid.IGridBindingColumnInformation;
import com.rcpcompany.uibindings.grid.IGridBindingRowInformation;
import com.rcpcompany.uibindings.grid.IGridFactory;
import com.rcpcompany.uibindings.grid.IGridModel;
import com.rcpcompany.uibindings.grid.IGridPackage;
import com.rcpcompany.uibindings.internal.ContainerBindingImpl;
import com.rcpcompany.uibindings.utils.IManagerRunnable;
import com.rcpcompany.utils.logging.LogUtils;
/**
* <!-- begin-user-doc --> An implementation of the model object '<em><b>Binding</b></em>'. <!--
* end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getNoColumnHeaders <em>No
* Column Headers</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getColumns <em>Columns</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getNoRowHeaders <em>No Row
* Headers</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getRows <em>Rows</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getGrid <em>Grid</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getModel <em>Model</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getColumnIDs <em>Column IDs
* </em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getRowIDs <em>Row IDs</em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getFocusCell <em>Focus Cell
* </em>}</li>
* <li>{@link com.rcpcompany.uibindings.grid.internal.GridBindingImpl#getCellEditor <em>Cell Editor
* </em>}</li>
* </ul>
* </p>
*
* @generated
*/
@SuppressWarnings("restriction")
public class GridBindingImpl extends ContainerBindingImpl implements IGridBinding {
/**
* The default value of the '{@link #getNoColumnHeaders() <em>No Column Headers</em>}'
* attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @see #getNoColumnHeaders()
* @generated
* @ordered
*/
protected static final int NO_COLUMN_HEADERS_EDEFAULT = 0;
/**
* The cached value of the '{@link #getNoColumnHeaders() <em>No Column Headers</em>}' attribute.
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @see #getNoColumnHeaders()
* @generated
* @ordered
*/
protected int noColumnHeaders = NO_COLUMN_HEADERS_EDEFAULT;
/**
* The cached value of the '{@link #getColumns() <em>Columns</em>}' map. <!-- begin-user-doc -->
* <!-- end-user-doc -->
*
* @see #getColumns()
* @generated
* @ordered
*/
protected EMap<Object, IGridBindingColumnInformation> columns;
/**
* The default value of the '{@link #getNoRowHeaders() <em>No Row Headers</em>}' attribute. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @see #getNoRowHeaders()
* @generated
* @ordered
*/
protected static final int NO_ROW_HEADERS_EDEFAULT = 0;
/**
* The cached value of the '{@link #getNoRowHeaders() <em>No Row Headers</em>}' attribute. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @see #getNoRowHeaders()
* @generated
* @ordered
*/
protected int noRowHeaders = NO_ROW_HEADERS_EDEFAULT;
/**
* The cached value of the '{@link #getRows() <em>Rows</em>}' map. <!-- begin-user-doc --> <!--
* end-user-doc -->
*
* @see #getRows()
* @generated
* @ordered
*/
protected EMap<Object, IGridBindingRowInformation> rows;
/**
* The default value of the '{@link #getGrid() <em>Grid</em>}' attribute. <!-- begin-user-doc
* --> <!-- end-user-doc -->
*
* @see #getGrid()
* @generated
* @ordered
*/
protected static final Grid GRID_EDEFAULT = null;
/**
* The cached value of the '{@link #getGrid() <em>Grid</em>}' attribute. <!-- begin-user-doc -->
* <!-- end-user-doc -->
*
* @see #getGrid()
* @generated
* @ordered
*/
protected Grid grid = GRID_EDEFAULT;
/**
* The default value of the '{@link #getModel() <em>Model</em>}' attribute. <!-- begin-user-doc
* --> <!-- end-user-doc -->
*
* @see #getModel()
* @generated
* @ordered
*/
protected static final IGridModel MODEL_EDEFAULT = null;
/**
* The cached value of the '{@link #getModel() <em>Model</em>}' attribute. <!-- begin-user-doc
* --> <!-- end-user-doc -->
*
* @see #getModel()
* @generated
* @ordered
*/
protected IGridModel model = MODEL_EDEFAULT;
/**
* The default value of the '{@link #getColumnIDs() <em>Column IDs</em>}' attribute. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @see #getColumnIDs()
* @generated
* @ordered
*/
protected static final IObservableList COLUMN_IDS_EDEFAULT = null;
/**
* The default value of the '{@link #getRowIDs() <em>Row IDs</em>}' attribute. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @see #getRowIDs()
* @generated
* @ordered
*/
protected static final IObservableList ROW_IDS_EDEFAULT = null;
/**
* The cached value of the '{@link #getFocusCell() <em>Focus Cell</em>}' reference. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @see #getFocusCell()
* @generated
* @ordered
*/
protected IGridBindingCellInformation focusCell;
/**
* The cached value of the '{@link #getCellEditor() <em>Cell Editor</em>}' reference. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @see #getCellEditor()
* @generated
* @ordered
*/
protected IGridBindingCellEditor cellEditor;
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
private static final int EOFFSET_CORRECTION = IGridPackage.Literals.GRID_BINDING
.getFeatureID(IGridPackage.Literals.GRID_BINDING__NO_COLUMN_HEADERS)
- IGridPackage.GRID_BINDING__NO_COLUMN_HEADERS;
/**
* List with all column IDs.
*/
protected IObservableList myColumnIDs;
/**
* List with all row IDs.
*/
protected IObservableList myRowIDs;
/**
* Listener that handles changes to the columns and rows
*/
private final IChangeListener myStructureChangeListener = new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
asyncUpdateGridStructure();
}
};
/**
* Forwards events for grid cells.
*/
protected Listener myCellEventListener = new Listener() {
@Override
public void handleEvent(Event event) {
// LogUtils.debug(this, "e=" + ToStringUtils.toString(event));
switch (event.type) {
case SWT.Selection:
updateFocusCellFromGrid();
break;
case SWT.KeyDown:
/*
* Special handling
*/
switch (event.keyCode) {
case SWT.TAB:
final Point p = getGrid().getFocusCell();
p.x++;
if (p.x == getColumns().size()) {
p.x = 0;
p.y++;
}
final IGridBindingCellInformation c = (IGridBindingCellInformation) getCell(p.x, p.y, true);
if (c != null) {
setFocusCell(c);
}
break;
}
}
final IGridBindingCellInformation cell;
/*
* Find the target cell. For some event - like KEY_DOWN - the location is (0, 0), so
* there we use the current focus cell (if set).
*/
if (event.x == 0 && event.y == 0) {
cell = getFocusCell();
} else {
cell = getCell(new Point(event.x, event.y));
}
// LogUtils.debug(this, "cell=" + cell);
if (cell != null) {
cell.handleEvent(event);
}
}
};
private final MySelectionProvider mySelectionProvider = new MySelectionProvider();
/**
* Dummy {@link ISelectionProvider} for use in
* {@link GridBindingImpl#updateSourceProviderState(ISourceProviderStateContext)}.
* <p>
* Can handle exactly one listener.
*/
private class MySelectionProvider implements ISelectionProvider {
private ISelectionChangedListener myListener = null;
@Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
if (myListener != null) {
LogUtils.error(listener, "Multiple listeners added!");
}
myListener = listener;
}
@Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
if (myListener != listener) {
LogUtils.error(listener, "Wrong listener removed!");
return;
}
myListener = null;
}
public void fireSelectionChange() {
if (myListener != null) {
try {
myListener.selectionChanged(null);
} catch (final Exception ex) {
LogUtils.error(myListener, ex);
}
}
}
@Override
public ISelection getSelection() {
return null;
}
@Override
public void setSelection(ISelection selection) {
}
}
/**
* Updates the focus cell based on the current focus cell of the grid itself.
*/
protected void updateFocusCellFromGrid() {
final Point p = getGrid().getFocusCell();
if (p == null) return;
if (p.x < 0 || p.y < 0) return;
final IGridBindingCellInformation cell = (IGridBindingCellInformation) getCell(p.x + getNoRowHeaders(), p.y
+ getNoColumnHeaders(), true);
if (cell == null) return;
setFocusCell(cell);
mySelectionProvider.fireSelectionChange();
}
/**
* Adds a new column at the specified index.
*
* @param columnID the ID of the new column
* @param index the index of the new column
*/
protected void addColumn(Object columnID, int index) {
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: addColumn(" + columnID + ", " + index
+ ")");
}
IGridFactory.eINSTANCE.createGridBindingColumnInformation(this, columnID, index);
getContext().reflow();
if (getFocusCell() == null) {
setFocusCellDelayed(getNoRowHeaders(), getNoColumnHeaders());
}
};
/**
* Removes an existing column.
*
* @param columnID the column ID of the column to remove
*/
protected void removeColumn(Object columnID) {
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: removeColumn(" + columnID + ")");
}
final IGridBindingColumnInformation column = getColumns().get(columnID);
column.dispose();
getContext().reflow();
}
/**
* Adds a new row at the specified index.
*
* @param rowID the ID of the new row
* @param index the index of the new row
*/
protected void addRow(Object rowID, int index) {
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: addRow(" + rowID + ", " + index + ")");
}
IGridFactory.eINSTANCE.createGridBindingRowInformation(this, rowID, index);
getContext().reflow();
if (getFocusCell() == null) {
setFocusCellDelayed(getNoRowHeaders(), getNoColumnHeaders());
}
};
/**
* Removes an existing row.
*
* @param rowID the row ID of the row to remove
*/
protected void removeRow(Object rowID) {
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: removeRow(" + rowID + ")");
}
final IGridBindingRowInformation row = getRows().get(rowID);
row.dispose();
getContext().reflow();
}
@Override
public boolean isChangeable() {
if (getArgument(Constants.ARG_READONLY, Boolean.class, Boolean.FALSE) == Boolean.TRUE) return false;
return true;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
private GridBindingImpl() {
super();
}
/**
* Constructs and return a new binding.
*
* @param context the context
*/
public GridBindingImpl(IBindingContext context) {
setContext(context);
}
@Override
public void dispose() {
if (isDisposed()) return;
setState(BindingState.DISPOSE_PENDING);
IManagerRunnable.Factory.cancelAsyncExec("initialSetup", this);
IManagerRunnable.Factory.cancelAsyncExec("structure", this);
getGrid().removeListener(SWT.MouseDown, myCellEventListener);
getGrid().removeListener(SWT.MouseDoubleClick, myCellEventListener);
getGrid().removeListener(SWT.KeyDown, myCellEventListener);
getGrid().removeListener(SWT.Selection, myCellEventListener);
if (eIsSet(IUIBindingsPackage.Literals.CONTAINER_BINDING__SINGLE_SELECTION)) {
getSingleSelection().dispose();
}
if (getModel() != null) {
try {
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: dispose");
}
getModel().dispose();
setModel(null);
} catch (final Exception ex) {
LogUtils.error(getModel(), ex);
}
}
super.dispose();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
protected EClass eStaticClass() {
return IGridPackage.Literals.GRID_BINDING;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public int getNoColumnHeaders() {
return noColumnHeaders;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
@Override
public IGridBindingCellEditor getCellEditor() {
if (cellEditor == null) {
setCellEditor(IGridFactory.eINSTANCE.createGridBindingCellEditor());
}
return cellEditor;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public IGridBindingCellEditor basicGetCellEditor() {
return cellEditor;
}
@Override
public void editCell(IGridBindingCellInformation cell, ColumnViewerEditorActivationEvent event) {
if (!cell.isChangeable()) return;
if (!IManager.Factory.getManager().isEditorActivationEvent(event, cell)) return;
setFocusCell(cell);
getCellEditor().editCell(cell, event);
}
@Override
public boolean isEditing() {
return cellEditor != null && cellEditor.getActiveEditCell() != null;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public NotificationChain basicSetCellEditor(IGridBindingCellEditor newCellEditor, NotificationChain msgs) {
final IGridBindingCellEditor oldCellEditor = cellEditor;
cellEditor = newCellEditor;
if (eNotificationRequired()) {
final ENotificationImpl notification = new ENotificationImpl(this, Notification.SET,
IGridPackage.GRID_BINDING__CELL_EDITOR + EOFFSET_CORRECTION, oldCellEditor, newCellEditor);
if (msgs == null) {
msgs = notification;
} else {
msgs.add(notification);
}
}
return msgs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setCellEditor(IGridBindingCellEditor newCellEditor) {
if (newCellEditor != cellEditor) {
NotificationChain msgs = null;
if (cellEditor != null) {
msgs = ((InternalEObject) cellEditor).eInverseRemove(this, IGridPackage.GRID_BINDING_CELL_EDITOR__GRID,
IGridBindingCellEditor.class, msgs);
}
if (newCellEditor != null) {
msgs = ((InternalEObject) newCellEditor).eInverseAdd(this, IGridPackage.GRID_BINDING_CELL_EDITOR__GRID,
IGridBindingCellEditor.class, msgs);
}
msgs = basicSetCellEditor(newCellEditor, msgs);
if (msgs != null) {
msgs.dispatch();
}
} else if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET, IGridPackage.GRID_BINDING__CELL_EDITOR
+ EOFFSET_CORRECTION, newCellEditor, newCellEditor));
}
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public EMap<Object, IGridBindingRowInformation> getRows() {
if (rows == null) {
rows = new EcoreEMap<Object, IGridBindingRowInformation>(IGridPackage.Literals.OBJECT_TO_ROW_MAP_ENTRY,
ObjectToRowMapEntryImpl.class, this, IGridPackage.GRID_BINDING__ROWS + EOFFSET_CORRECTION);
}
return rows;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public Grid getGrid() {
return grid;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setGrid(Grid newGrid) {
final Grid oldGrid = grid;
grid = newGrid;
if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET, IGridPackage.GRID_BINDING__GRID + EOFFSET_CORRECTION,
oldGrid, grid));
}
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public IGridModel getModel() {
return model;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setModel(IGridModel newModel) {
final IGridModel oldModel = model;
model = newModel;
if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET,
IGridPackage.GRID_BINDING__MODEL + EOFFSET_CORRECTION, oldModel, model));
}
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
@Override
public IObservableList getColumnIDs() {
return myColumnIDs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
@Override
public IObservableList getRowIDs() {
return myRowIDs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public IGridBindingCellInformation getFocusCell() {
return focusCell;
}
@Override
public void setFocusCellDelayed(final int column, final int row) {
IManagerRunnable.Factory.asyncExec("setFocus", this, new Runnable() {
@Override
public void run() {
int c = column;
int r = row;
if (c >= getColumns().size()) {
c = getColumns().size() - 1;
}
if (r >= getRows().size()) {
r = getRows().size() - 1;
}
if (c <= 0 || r <= 0) {
setFocusCell((IGridBindingCellInformation) null);
return;
}
setFocusCell((IGridBindingCellInformation) getCell(c, r, true));
}
});
}
@Override
public void updateFocusCellDelayed() {
final IGridBindingCellInformation cell = getFocusCell();
if (cell == null) {
setFocusCellDelayed(getNoRowHeaders(), getNoColumnHeaders());
return;
}
final Point position = cell.getPosition(true);
setFocusCellDelayed(position.x, position.y);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
@Override
public void setFocusCell(IGridBindingCellInformation newFocusCell) {
if (newFocusCell == null) {
if (getColumnIDs().size() > 0 && getRowIDs().size() > 0) {
newFocusCell = (IGridBindingCellInformation) getCell(getNoRowHeaders(), getNoColumnHeaders(), true);
}
}
setFocusCellGen(newFocusCell);
if (newFocusCell == null) return;
if (newFocusCell.getColumn().getGridColumn() == null || newFocusCell.getRow().getGridItem() == null) return;
getGrid().setFocusColumn(newFocusCell.getColumn().getGridColumn());
getGrid().setFocusItem(newFocusCell.getRow().getGridItem());
getSingleSelection().setValue(newFocusCell.getObjectValue());
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
@Override
public IObservableValue getSingleSelection() {
if (super.getSingleSelection() == null) {
singleSelection = WritableValue.withValueType(null);
}
return super.getSingleSelection();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setFocusCellGen(IGridBindingCellInformation newFocusCell) {
final IGridBindingCellInformation oldFocusCell = focusCell;
focusCell = newFocusCell;
if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET, IGridPackage.GRID_BINDING__FOCUS_CELL
+ EOFFSET_CORRECTION, oldFocusCell, focusCell));
}
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public NotificationChain eInverseAdd(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__CELL_EDITOR:
if (cellEditor != null) {
msgs = ((InternalEObject) cellEditor).eInverseRemove(this, IGridPackage.GRID_BINDING_CELL_EDITOR__GRID,
IGridBindingCellEditor.class, msgs);
}
return basicSetCellEditor((IGridBindingCellEditor) otherEnd, msgs);
}
return super.eInverseAdd(otherEnd, featureID, msgs);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public EMap<Object, IGridBindingColumnInformation> getColumns() {
if (columns == null) {
columns = new EcoreEMap<Object, IGridBindingColumnInformation>(
IGridPackage.Literals.OBJECT_TO_COLUMN_MAP_ENTRY, ObjectToColumnMapEntryImpl.class, this,
IGridPackage.GRID_BINDING__COLUMNS + EOFFSET_CORRECTION);
}
return columns;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public int getNoRowHeaders() {
return noRowHeaders;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__COLUMNS:
return ((InternalEList<?>) getColumns()).basicRemove(otherEnd, msgs);
case IGridPackage.GRID_BINDING__ROWS:
return ((InternalEList<?>) getRows()).basicRemove(otherEnd, msgs);
case IGridPackage.GRID_BINDING__CELL_EDITOR:
return basicSetCellEditor(null, 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 - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__NO_COLUMN_HEADERS:
return getNoColumnHeaders();
case IGridPackage.GRID_BINDING__COLUMNS:
if (coreType)
return getColumns();
else
return getColumns().map();
case IGridPackage.GRID_BINDING__NO_ROW_HEADERS:
return getNoRowHeaders();
case IGridPackage.GRID_BINDING__ROWS:
if (coreType)
return getRows();
else
return getRows().map();
case IGridPackage.GRID_BINDING__GRID:
return getGrid();
case IGridPackage.GRID_BINDING__MODEL:
return getModel();
case IGridPackage.GRID_BINDING__COLUMN_IDS:
return getColumnIDs();
case IGridPackage.GRID_BINDING__ROW_IDS:
return getRowIDs();
case IGridPackage.GRID_BINDING__FOCUS_CELL:
return getFocusCell();
case IGridPackage.GRID_BINDING__CELL_EDITOR:
if (resolve) return getCellEditor();
return basicGetCellEditor();
}
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 - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__COLUMNS:
((EStructuralFeature.Setting) getColumns()).set(newValue);
return;
case IGridPackage.GRID_BINDING__ROWS:
((EStructuralFeature.Setting) getRows()).set(newValue);
return;
case IGridPackage.GRID_BINDING__GRID:
setGrid((Grid) newValue);
return;
case IGridPackage.GRID_BINDING__MODEL:
setModel((IGridModel) newValue);
return;
case IGridPackage.GRID_BINDING__FOCUS_CELL:
setFocusCell((IGridBindingCellInformation) newValue);
return;
case IGridPackage.GRID_BINDING__CELL_EDITOR:
setCellEditor((IGridBindingCellEditor) newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__COLUMNS:
getColumns().clear();
return;
case IGridPackage.GRID_BINDING__ROWS:
getRows().clear();
return;
case IGridPackage.GRID_BINDING__GRID:
setGrid(GRID_EDEFAULT);
return;
case IGridPackage.GRID_BINDING__MODEL:
setModel(MODEL_EDEFAULT);
return;
case IGridPackage.GRID_BINDING__FOCUS_CELL:
setFocusCell((IGridBindingCellInformation) null);
return;
case IGridPackage.GRID_BINDING__CELL_EDITOR:
setCellEditor((IGridBindingCellEditor) null);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__NO_COLUMN_HEADERS:
return noColumnHeaders != NO_COLUMN_HEADERS_EDEFAULT;
case IGridPackage.GRID_BINDING__COLUMNS:
return columns != null && !columns.isEmpty();
case IGridPackage.GRID_BINDING__NO_ROW_HEADERS:
return noRowHeaders != NO_ROW_HEADERS_EDEFAULT;
case IGridPackage.GRID_BINDING__ROWS:
return rows != null && !rows.isEmpty();
case IGridPackage.GRID_BINDING__GRID:
return GRID_EDEFAULT == null ? grid != null : !GRID_EDEFAULT.equals(grid);
case IGridPackage.GRID_BINDING__MODEL:
return MODEL_EDEFAULT == null ? model != null : !MODEL_EDEFAULT.equals(model);
case IGridPackage.GRID_BINDING__COLUMN_IDS:
return COLUMN_IDS_EDEFAULT == null ? getColumnIDs() != null : !COLUMN_IDS_EDEFAULT.equals(getColumnIDs());
case IGridPackage.GRID_BINDING__ROW_IDS:
return ROW_IDS_EDEFAULT == null ? getRowIDs() != null : !ROW_IDS_EDEFAULT.equals(getRowIDs());
case IGridPackage.GRID_BINDING__FOCUS_CELL:
return focusCell != null;
case IGridPackage.GRID_BINDING__CELL_EDITOR:
return cellEditor != null;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public int eDerivedStructuralFeatureID(int baseFeatureID, Class<?> baseClass) {
if (baseClass == IGridBinding.class) {
switch (baseFeatureID - EOFFSET_CORRECTION) {
case IGridPackage.GRID_BINDING__NO_COLUMN_HEADERS:
return IGridPackage.GRID_BINDING__NO_COLUMN_HEADERS + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__COLUMNS:
return IGridPackage.GRID_BINDING__COLUMNS + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__NO_ROW_HEADERS:
return IGridPackage.GRID_BINDING__NO_ROW_HEADERS + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__ROWS:
return IGridPackage.GRID_BINDING__ROWS + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__GRID:
return IGridPackage.GRID_BINDING__GRID + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__MODEL:
return IGridPackage.GRID_BINDING__MODEL + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__COLUMN_IDS:
return IGridPackage.GRID_BINDING__COLUMN_IDS + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__ROW_IDS:
return IGridPackage.GRID_BINDING__ROW_IDS + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__FOCUS_CELL:
return IGridPackage.GRID_BINDING__FOCUS_CELL + EOFFSET_CORRECTION;
case IGridPackage.GRID_BINDING__CELL_EDITOR:
return IGridPackage.GRID_BINDING__CELL_EDITOR + EOFFSET_CORRECTION;
default:
return -1;
}
}
return super.eDerivedStructuralFeatureID(baseFeatureID, baseClass);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public String toString() {
if (eIsProxy()) return super.toString();
final StringBuffer result = new StringBuffer(super.toString());
result.append(" (noColumnHeaders: ");
result.append(noColumnHeaders);
result.append(", noRowHeaders: ");
result.append(noRowHeaders);
result.append(", grid: ");
result.append(grid);
result.append(", model: ");
result.append(model);
result.append(')');
return result.toString();
}
@Override
public void finish1() {
try {
final Grid g = getGrid();
assertTrue(g != null, "Grid control not set");
assertTrue(getModel() != null, "Model not set");
registerWidget(g);
g.setHeaderVisible(true);
// g.setCellHeaderSelectionBackground(JFaceResources.getColorRegistry().get(
// "com.rcpcompany.uibindings.colorDefinitions.EvenRowBackground")); // TODO
g.setCellSelectionEnabled(true);
g.setRowHeaderVisible(true);
g.setAutoHeight(true);
g.setAutoWidth(true);
g.setLinesVisible(true);
g.addListener(SWT.MouseDown, myCellEventListener);
g.addListener(SWT.MouseDoubleClick, myCellEventListener);
g.addListener(SWT.KeyDown, myCellEventListener);
g.addListener(SWT.Selection, myCellEventListener);
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: getColumnIDs");
}
myColumnIDs = getModel().getColumnIDs();
myColumnIDs.addChangeListener(myStructureChangeListener);
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model: >>> " + myColumnIDs);
}
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model[" + getGrid().hashCode() + "]: getColumnIDs");
}
myRowIDs = getModel().getRowIDs();
myRowIDs.addChangeListener(myStructureChangeListener);
if (Activator.getDefault().TRACE_SOURCE_MODEL) {
LogUtils.debug(getModel(), "Model: >>> " + myRowIDs);
}
/*
* Query the model for the number of column and row headers
*
* TODO: query model
*/
noColumnHeaders = 1;
noRowHeaders = 1;
/*
* Create the column and row headers
*/
IManagerRunnable.Factory.asyncExec("initialSetup", this, new Runnable() {
@Override
public void run() {
addColumn(IGridModel.HEADER1, 0);
addRow(IGridModel.HEADER1, 0);
}
});
asyncUpdateGridStructure();
} catch (final Exception ex) {
dispose();
LogUtils.error(this, ex);
}
}
/**
* Runnable used to update the structure of a grid.
*/
protected final Runnable asyncUpdateGridStructureRunnable = new Runnable() {
protected final ListDiffVisitor columnVisitor = new ListDiffVisitor() {
@Override
public void handleRemove(int index, Object element) {
removeColumn(element);
}
@Override
public void handleAdd(int index, Object element) {
addColumn(element, index);
}
@Override
public void handleMove(int oldIndex, int newIndex, Object element) {
// TODO: use grid methods
removeColumn(element);
addColumn(element, newIndex);
}
@Override
public void handleReplace(int index, Object oldElement, Object newElement) {
removeColumn(oldElement);
addColumn(newElement, index);
}
};
protected final ListDiffVisitor rowVisitor = new ListDiffVisitor() {
@Override
public void handleRemove(int index, Object element) {
removeRow(element);
}
@Override
public void handleAdd(int index, Object element) {
addRow(element, index);
}
@Override
public void handleMove(int oldIndex, int newIndex, Object element) {
// TODO: use grid methods
removeRow(element);
addRow(element, newIndex);
}
@Override
public void handleReplace(int index, Object oldElement, Object newElement) {
removeRow(oldElement);
addRow(newElement, index);
}
};
protected List<Object> myOldColumns = Collections.emptyList();
protected List<Object> myOldRows = Collections.emptyList();
@Override
public void run() {
/*
* Strategy:
*
* 1) copy the current column and row IDs
*
* 2) add/remove columns and rows
*
* 3) set the "old" columns and rows to the copied ones
*/
final List<Object> newColumns = new ArrayList<Object>(myColumnIDs);
final List<Object> newRows = new ArrayList<Object>(myRowIDs);
Diffs.computeListDiff(myOldColumns, newColumns).accept(columnVisitor);
Diffs.computeListDiff(myOldRows, newRows).accept(rowVisitor);
myOldColumns = newColumns;
myOldRows = newRows;
}
};
/**
* Asynchronously updates the structure of the grid.
*/
protected void asyncUpdateGridStructure() {
if (getGrid().isDisposed()) {
LogUtils.debug(this, "Grid is disposed");
return;
}
IManagerRunnable.Factory.asyncExec("structure", this, asyncUpdateGridStructureRunnable);
}
@Override
public Control getControl() {
return getGrid();
}
@Override
public Class<?> getUIType() {
// Not used
return null;
}
@Override
public Widget getWidget() {
return getGrid();
}
@Override
public IBinding arg(String name, Object value) {
assertTrue(name != null, "name must be non-null"); //$NON-NLS-1$
getArguments().put(name, value);
return this;
}
@Override
public IBinding args(Map<String, Object> arguments) {
setArguments(arguments);
return this;
}
@Override
public IBinding dynamic() {
return this;
}
@Override
public IBinding id(String id) {
setId(id);
return this;
}
@Override
public IBinding label(String label) {
return this;
}
@Override
public IBinding readonly() {
return arg(Constants.ARG_READONLY, true);
}
@Override
public IBinding type(String type) {
return arg(Constants.ARG_TYPE, type);
}
@Override
public IBinding validValues(IObservableList list) {
assertTrue(false, "Cannot set validValues");
return this;
}
@Override
public IBinding validValues(EObject obj, EReference reference) {
assertTrue(false, "Cannot set validValues");
return this;
}
@Override
public IGridBinding grid(Grid grid) {
assertTrue(this.grid == null, "grid already set");
assertTrue(grid != null, "grid must be non-null");
this.grid = grid;
return this;
}
@Override
public IGridBinding model(IGridModel model) {
assertTrue(getModel() == null, "model already set");
assertTrue(model != null, "model must be non-null");
setModel(model);
return this;
}
@Override
public void updateSourceProviderState(ISourceProviderStateContext context) {
context.putSourceValue(Constants.SOURCES_ACTIVE_CONTAINER_BINDING, this);
// state.put(Constants.ACTIVE_VIEWER_BINDING_NO_CAF, (viewer.getComparator() == null &&
// viewer.getFilters().length == 0));
// state.put(Constants.ACTIVE_VIEWER_ELEMENT_TYPE, getModelType());
// TODO: find an ISelectionProvider
context.setSelectionProvider(null);
IGridBindingCellInformation currentCell;
/*
* If a specific position is specified in the event (x,y) then use this to focus - will only
* succeed if the cell is inside the grid (not a header).
*/
final Event event = context.getEvent();
if ((event.x != 0 || event.y != 0) && event.widget == getControl()) {
setFocusCell(new Point(event.x, event.y));
}
currentCell = getFocusCell();
if (currentCell != null) {
final IBindingDataType dataType = currentCell.getDataType();
final IObservableValue objectValue = currentCell.getObjectValue();
final IValueBinding labelBinding = currentCell.getLabelBinding();
if (labelBinding != null) {
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING, labelBinding);
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_TYPE, labelBinding.getType());
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_MODEL_OBJECT, dataType.getDataType());
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_FEATURE, labelBinding.getModelFeature());
}
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_RO, !currentCell.isChangeable());
if (dataType != null) {
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_UNSETTABLE, dataType.isUnsettable());
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_MODEL_OBJECT, dataType.getDataType());
}
if (objectValue != null) {
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_VALUE, objectValue.getValue());
}
context.putSourceValue(Constants.SOURCES_ACTIVE_BINDING_VALUE_DISPLAY, currentCell.getDisplayText());
final IUIAttribute la = currentCell.getLabelUIAttribute();
if (la != null) {
context.addObservedValue(la.getCurrentValue());
}
}
}
@Override
public void setFocusCell(Point point) {
final IGridBindingCellInformation cell = getCell(point);
if (cell != null) {
setFocusCell(cell);
}
}
@Override
public IGridBindingCellInformation getCell(Point point) {
final GridColumn gColumn = getGrid().getColumn(point);
IGridBindingColumnInformation ci = null;
if (gColumn != null) {
for (final IGridBindingColumnInformation c : getColumns().values()) {
if (c.getGridColumn() == gColumn) {
ci = c;
break;
}
}
}
if (ci == null) {
for (final IGridBindingColumnInformation c : getColumns().values()) {
if (c.getId() == IGridModel.HEADER1) {
ci = c;
break;
}
}
}
if (ci == null) return null;
final GridItem gItem = getGrid().getItem(point);
IGridBindingRowInformation ri = null;
if (gItem != null) {
for (final IGridBindingRowInformation r : getRows().values()) {
if (r.getGridItem() == gItem) {
ri = r;
break;
}
}
}
if (ri == null) {
for (final IGridBindingRowInformation r : getRows().values()) {
if (r.getId() == IGridModel.HEADER1) {
ri = r;
break;
}
}
}
if (ri == null) return null;
for (final IGridBindingCellInformation cell : ci.getRowCells()) {
if (cell.getRow() == ri) return cell;
}
LogUtils.throwException(this, "Cell not found - inconsistency", getCreationPoint());
return null;
}
@Override
public IGridBindingCellInformation getCell(Object columnID, Object rowID) {
IGridBindingColumnInformation ci = null;
IGridBindingRowInformation ri = null;
for (final IGridBindingColumnInformation c : getColumns().values()) {
if (c.getId() == columnID) {
ci = c;
break;
}
}
if (ci == null) return null;
for (final IGridBindingRowInformation r : getRows().values()) {
if (r.getId() == rowID) {
ri = r;
break;
}
}
if (ri == null) return null;
for (final IGridBindingCellInformation cell : ci.getRowCells()) {
if (cell.getRow() == ri) return cell;
}
LogUtils.throwException(this, "Cell not found - inconsistency", getCreationPoint());
return null;
}
private Object getColumnID(int column, boolean visualModel) {
if (column == getNoRowHeaders() - 2) return IGridModel.HEADER2;
if (column == getNoRowHeaders() - 3) return IGridModel.HEADER3;
if (column == getNoRowHeaders() - 4) return IGridModel.HEADER4;
if (column == getNoRowHeaders() - 5) return IGridModel.HEADER5;
column -= getNoRowHeaders();
if (visualModel) {
final int[] columnOrder = getGrid().getColumnOrder();
if (column < columnOrder.length) {
column = columnOrder[column];
}
}
return getColumnIDs().get(column);
}
private Object getRowID(int row, boolean visualModel) {
if (row == getNoColumnHeaders() - 2) return IGridModel.HEADER2;
if (row == getNoColumnHeaders() - 3) return IGridModel.HEADER3;
if (row == getNoColumnHeaders() - 4) return IGridModel.HEADER4;
if (row == getNoColumnHeaders() - 5) return IGridModel.HEADER5;
row -= getNoRowHeaders();
return getRowIDs().get(row);
}
@Override
public IValueBindingCell getCell(int column, int row, boolean visualModel) {
final Object columnID = getColumnID(column, visualModel);
final Object rowID = getRowID(row, visualModel);
final IGridBindingColumnInformation ci = getColumns().get(columnID);
final IGridBindingRowInformation ri = getRows().get(rowID);
if (ci == null) return null;
if (ri == null) return null;
for (final IGridBindingCellInformation cell : ci.getRowCells()) {
if (cell.getRow() == ri) return cell;
}
LogUtils.throwException(this, "Cell not found - inconsistency", getCreationPoint());
return null;
}
@Override
public IGridBindingCellInformation getCell(int column, int row) {
return (IGridBindingCellInformation) getCell(column, row, true);
}
@Override
public ValidationLabelDecorator getValidationLabelDecorator() {
return null;
}
@Override
public Collection<EObject> getSelection() {
final Point[] cellSelection = getGrid().getCellSelection();
final Collection<EObject> selection = new ArrayList<EObject>(cellSelection.length);
for (final Point p : cellSelection) {
final IGridBindingCellInformation cell = getCell(p.x + getNoColumnHeaders(), p.y + getNoRowHeaders());
if (cell == null) {
continue;
}
final IObservableValue valueOV = cell.getObjectValue();
if (valueOV == null) {
continue;
}
final Object value = valueOV.getValue();
if (!(value instanceof EObject)) {
continue;
}
selection.add((EObject) valueOV.getValue());
}
return selection;
}
@Override
public IContainerDropContext getDropContext(DropTargetEvent event) {
final Control control = getControl();
final Point point = control.toControl(new Point(event.x, event.y));
final IGridBindingCellInformation cell = getCell(point);
if (cell == null) return null;
return new IContainerDropContext() {
@Override
public EObject getDropTargetObject() {
final IObservableValue valueOV = cell.getObjectValue();
if (valueOV == null) return null;
final Object value = valueOV.getValue();
if (value instanceof EObject) return (EObject) value;
return null;
}
@Override
public float getDropLocation() {
if (cell.getColumn().getId() == IGridModel.HEADER1) {
final GridItem gridItem = cell.getRow().getGridItem();
if (gridItem != null) {
final Rectangle bounds = gridItem.getBounds(0);
return (float) (point.y - bounds.y) / (float) bounds.height;
}
}
if (cell.getRow().getId() == IGridModel.HEADER1) {
final GridColumn column = cell.getColumn().getGridColumn();
if (column != null) {
final int x = getColumnHeaderXPosition(column);
final int width = column.getWidth();
return (float) (point.x - x) / width;
}
}
/*
* OK... then we assume we are in the center of the cell
*/
return 0.5f;
}
/**
* Returns the x position of the given column.
*
* @param column given column
* @return x position
*/
private int getColumnHeaderXPosition(GridColumn column) {
final Grid grid = getGrid();
int x = 0;
// x -= grid.getHScrollSelectionInPixels();
x += grid.getRowHeaderWidth();
final int[] columnOrder = grid.getColumnOrder();
for (final int i : columnOrder) {
final GridColumn c = grid.getColumn(i);
if (c == column) return x;
if (!c.isVisible()) {
continue;
}
x += c.getWidth();
}
return x;
}
@Override
public IValueBindingCell getDropCell() {
return cell;
}
@Override
public List<IChildCreationSpecification> getPossibleChildObjects(EObject parent, EObject sibling) {
if (cell.getColumn().getId() == IGridModel.HEADER1)
return UIBindingsUtils.getPossibleTopLevelChildObjects(getRowIDs(), parent);
if (cell.getRow().getId() == IGridModel.HEADER1)
return UIBindingsUtils.getPossibleTopLevelChildObjects(getColumnIDs(), parent);
return null;
}
};
}
}