/*******************************************************************************
* 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.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.Assert;
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.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import com.rcpcompany.uibindings.Constants;
import com.rcpcompany.uibindings.IBindingContext;
import com.rcpcompany.uibindings.IColumnAdapter;
import com.rcpcompany.uibindings.IColumnBinding;
import com.rcpcompany.uibindings.IManager;
import com.rcpcompany.uibindings.IViewerBinding;
import com.rcpcompany.uibindings.SpecialBinding;
import com.rcpcompany.uibindings.UIBindingsUtils;
import com.rcpcompany.uibindings.observables.EListKeyedElementObservableValue;
import com.rcpcompany.uibindings.utils.IBindingSpec;
import com.rcpcompany.uibindings.utils.IBindingSpec.BaseType;
import com.rcpcompany.uibindings.utils.IBindingSpec.SpecContext;
import com.rcpcompany.uibindings.utils.IFilteringTableAdapter;
import com.rcpcompany.uibindings.utils.ISortableTableAdapter;
import com.rcpcompany.uibindings.utils.ITableCreator;
import com.rcpcompany.utils.logging.LogUtils;
/**
* Implementation of {@link ITableCreator}.
*
* @author Tonny Madsen, The RCP Company
*/
public class TableCreator implements ITableCreator {
/**
* The context used for the bindings.
*/
protected final IBindingContext myContext;
/**
* The created table.
*/
protected final Table myTable;
/**
* The viewer binding used for the table.
*/
protected final IViewerBinding myViewerBinding;
/**
* A filter Text field if wanted.
*/
protected Text myFilter = null;
/**
* The table layout used - controlled by the {@link ITableCreator#RESIZE} style.
*/
protected TableColumnLayout myTableLayout = null;
/**
* Constructs and returns a new table creator.
* <p>
* Use the style {@link ITableCreator#FILTER} to add a filter box on top of the table.
* <p>
* The following styles are passed to the
*
* @param context the context
* @param parent the parent composite of the new table - expected to have a {@link FillLayout}
* @param style the style for the new table
*/
public TableCreator(IBindingContext context, Composite parent, int style) {
final IManager manager = IManager.Factory.getManager();
Composite p = parent;
// TODO TEST
if ((style & (SWT.V_SCROLL | SWT.H_SCROLL)) == 0) {
style |= SWT.NO_SCROLL;
}
if ((style & ITableCreator.FILTER) == ITableCreator.FILTER) {
style &= ~ITableCreator.FILTER;
p = manager.getFormToolkit(parent).createComposite(p);
final GridLayout l = new GridLayout();
l.marginHeight = 0;
l.marginWidth = 0;
p.setLayout(l);
myFilter = IFilteringTableAdapter.Factory.createFilter(p);
}
if ((style & ITableCreator.RESIZE) == ITableCreator.RESIZE) {
style &= ~ITableCreator.RESIZE;
p = manager.getFormToolkit(p).createComposite(p);
myTableLayout = new TableColumnLayout();
p.setLayout(myTableLayout);
if (myFilter != null) {
p.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
}
myTable = manager.getFormToolkit(p).createTable(p, style | SWT.FULL_SELECTION);
if (p != parent) {
myTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
myContext = context;
myTable.setLinesVisible(true);
myTable.setHeaderVisible(true);
myViewerBinding = myContext.addViewer().viewer(myTable);
ISortableTableAdapter.Factory.adapt(getBinding());
if (myFilter != null) {
IFilteringTableAdapter.Factory.adapt(getBinding(), myFilter);
}
}
@Override
public void setFocus() {
(myFilter != null ? myFilter : myTable).setFocus();
}
@Override
public void dispose() {
}
@Override
public IViewerBinding setContent(IObservableList list) {
// TODO check type
// if (list.getElementType() instanceof EClass)
return myViewerBinding.model(list);
}
@Override
public IViewerBinding setContent(EObject object, EReference reference) {
return myViewerBinding.model(object, reference);
}
@Override
public IViewerBinding setContent(IObservableValue object, EReference reference) {
return myViewerBinding.model(object, reference);
}
@Override
public Table getTable() {
return myTable;
}
@Override
public IViewerBinding getBinding() {
return myViewerBinding;
}
@Override
public IColumnBinding addColumn(EStructuralFeature feature, int width) {
Assert.isNotNull(myViewerBinding);
final TableColumn column = createTableColumn(width, SWT.NONE);
return myViewerBinding.addColumn(column, feature);
}
@Override
public IColumnBinding addColumn(SpecialBinding columnType, int width) {
Assert.isNotNull(myViewerBinding);
final TableColumn column = createTableColumn(width, SWT.RIGHT);
return myViewerBinding.addColumn().column(column).model(columnType);
}
@Override
public IColumnBinding addColumn(IColumnBinding baseColumn, EStructuralFeature feature, int width) {
Assert.isNotNull(myViewerBinding);
final TableColumn column = createTableColumn(width, SWT.NONE);
return myViewerBinding.addColumn().column(column).model(baseColumn, feature);
}
@Override
public IColumnBinding addColumn(String spec) {
final List<IBindingSpec> bspecs = IBindingSpec.Factory.parseSingleSpec(
(EClass) myViewerBinding.getModelEType(), spec, SpecContext.TABLE_COLUMN);
if (bspecs == null) return null;
/*
* Construct a list of all top-level columns
*/
IColumnBinding parentColumn = null;
List<IColumnBinding> subColumns = new ArrayList<IColumnBinding>(myViewerBinding.getColumns());
for (final IColumnBinding c : subColumns.toArray(new IColumnBinding[subColumns.size()])) {
if (c.getBaseColumn() != null) {
subColumns.remove(c);
}
}
for (final IBindingSpec s : bspecs) {
/*
* Firste create the new column
*/
IColumnBinding foundColumn = null;
final EStructuralFeature feature;
switch (s.getType()) {
case NONE:
final TableColumn column = createTableColumn(0, SWT.NONE);
foundColumn = myViewerBinding.addColumn().column(column);
break;
case ROW_NO:
foundColumn = addColumn(SpecialBinding.ROW_NO, 0);
foundColumn.getColumnAdapter().setAlignment(SWT.RIGHT);
break;
case ROW_ELEMENT:
foundColumn = addColumn(SpecialBinding.ROW_ELEMENT, 0);
break;
case FEATURE:
/*
* See if a column already exists for the feature
*/
feature = s.getFeature();
for (final IColumnBinding c : subColumns) {
if (feature == c.getDataType().getValueType()) {
foundColumn = c;
break;
}
}
if (foundColumn == null) {
if (parentColumn == null) {
foundColumn = addColumn(feature, 0);
} else {
foundColumn = addColumn(parentColumn, feature, 0);
}
foundColumn.getColumnAdapter().setResizable(false);
final int alignment = UIBindingsUtils.defaultAlignment(foundColumn.getDataType().getValueType());
if (alignment != SWT.NONE) {
foundColumn.getColumnAdapter().setAlignment(alignment);
}
}
break;
case KEY_VALUE:
/*
* TODO See if a column already exists for the feature
*/
feature = s.getFeature();
// for (final IColumnBinding c : subColumns) {
// if (feature == c.getDataType().getValueType()) {
// foundColumn = c;
// break;
// }
// }
if (foundColumn == null) {
final IObservableFactory factory = new IObservableFactory() {
@Override
public IObservable createObservable(Object target) {
return new EListKeyedElementObservableValue<EObject>(getBinding().getContext()
.getEditingDomain(), (EObject) target, (EReference) feature, s.getKeyFeature(),
s.getKeyValue(), s.getValueFeature());
}
};
Assert.isNotNull(myViewerBinding);
final TableColumn newColumn = createTableColumn(0, SWT.RIGHT);
if (parentColumn == null) {
foundColumn = myViewerBinding.addColumn().column(newColumn).model(factory, s.getValueFeature());
} else {
foundColumn = myViewerBinding.addColumn().column(newColumn)
.model(parentColumn, factory, s.getValueFeature());
}
foundColumn.getColumnAdapter().setResizable(false);
final int alignment = UIBindingsUtils.defaultAlignment(foundColumn.getDataType().getValueType());
if (alignment != SWT.NONE) {
foundColumn.getColumnAdapter().setAlignment(alignment);
}
}
break;
default:
LogUtils.error(this, "Unknown special binding: " + s.getType());
continue;
}
final IColumnAdapter adapter = foundColumn.getColumnAdapter();
/*
* Then apply any arguments
*/
final Map<String, Object> arguments = s.getArguments();
for (final Entry<String, Object> entry : arguments.entrySet()) {
if (Constants.ARG_WIDTH.equals(entry.getKey())) {
adapter.setResizable(true);
final Integer width = (Integer) entry.getValue();
adapter.setWidth(width);
if (myTableLayout != null) {
Integer wwi = (Integer) arguments.get(IBindingSpec.WIDTH_WEIGHT);
if (wwi == null) {
wwi = s.getType() == BaseType.ROW_NO ? 0 : 100;
}
myTableLayout.setColumnData(adapter.getWidget(), new ColumnWeightData(wwi, width, true));
}
} else if (Constants.ARG_ALIGNMENT.equals(entry.getKey())) {
final String a = (String) entry.getValue();
if ("l".equals(a)) {
adapter.setAlignment(SWT.LEAD);
} else if ("c".equals(a)) {
adapter.setAlignment(SWT.CENTER);
} else if ("r".equals(a)) {
adapter.setAlignment(SWT.TRAIL);
} else {
LogUtils.throwException(this, "Alignment must be one of 'l', 'c' or 'r', got '" + a + "'", null);
}
} else {
foundColumn.arg(entry.getKey(), entry.getValue());
}
}
parentColumn = foundColumn;
subColumns = parentColumn.getSubColumns();
}
return parentColumn;
}
@Override
public TableColumn createTableColumn(int width, int style) {
final TableColumn column = new TableColumn(myTable, style);
column.setWidth(width);
column.setMoveable(true);
if (myTableLayout != null) {
if (width == 0) {
myTableLayout.setColumnData(column, new ColumnPixelData(0));
} else {
myTableLayout.setColumnData(column, new ColumnWeightData(100, width, true));
}
}
return column;
}
}