blob: 32c736d16ca294b5aec8029cc6b9efc0d2842ca4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.jface.internal.databinding.viewers;
import java.util.HashMap;
import org.eclipse.jface.databinding.BindingException;
import org.eclipse.jface.databinding.ChangeEvent;
import org.eclipse.jface.databinding.IChangeListener;
import org.eclipse.jface.databinding.IDataBindingContext;
import org.eclipse.jface.databinding.converter.IConverter;
import org.eclipse.jface.databinding.converters.IdentityConverter;
import org.eclipse.jface.databinding.validator.IValidator;
import org.eclipse.jface.databinding.viewers.TreeViewerDescription;
import org.eclipse.jface.databinding.viewers.TableViewerDescription.Column;
import org.eclipse.jface.internal.databinding.beans.PropertyHelper;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerLabel;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Item;
/**
* @since 3.2
*
*/
public class TreeViewerUpdatableTreeExtended extends TreeViewerUpdatableTree {
class ColumnInfo{ // boolean default value is false
boolean converterDefaulted;
boolean validatorDefaulted;
boolean cellEditorDefaulted;
}
class TreeLabelProvider extends LabelProvider implements ITableLabelProvider {
private Object getValue(Object element, Column column) {
Object value = treeViewerDescription.getCellModifier().getValue(
element, Integer.toString(treeViewerDescription.getColumnIndex(element.getClass(), column)));
return value;
}
private Object getConvertedValue(Object element, Column column) {
String propertyName = column.getPropertyName();
Object value;
if (propertyName == null)
value = element;
else
value = getValue(element, column);
Object convertedValue = column.getConverter().convertModelToTarget(
value);
return convertedValue;
}
public Image getColumnImage(Object element, int columnIndex) {
if (columnIndex<treeViewerDescription.getColumnCount(element.getClass()) && columnIndex>=0) {
Column column = getColumn(element.getClass(), columnIndex);
IConverter converter = column.getConverter();
if (converter.getTargetType().equals(ViewerLabel.class)) {
ViewerLabel viewerLabel = (ViewerLabel) getConvertedValue(
element, column);
return viewerLabel.getImage();
}
}
return null;
}
public String getColumnText(Object element, int columnIndex) {
Object convertedValue=null;
if (columnIndex<treeViewerDescription.getColumnCount(element.getClass()) && columnIndex>=0) {
Column column = getColumn(element.getClass(), columnIndex);
convertedValue = getConvertedValue(element, column);
IConverter converter = column.getConverter();
if (converter.getTargetType().equals(ViewerLabel.class)) {
ViewerLabel viewerLabel = (ViewerLabel) convertedValue;
return viewerLabel.getText();
}
}
return convertedValue==null? "": (String) convertedValue; //$NON-NLS-1$
}
// support the case where a TreeColumn() was not placed on the tree
public Image getImage(Object element) {
return getColumnImage(element,0);
}
public String getText(Object element) {
return getColumnText(element, 0);
}
}
private HashMap columnInfos = new HashMap();
private IDataBindingContext dataBindingContext;
private final TreeViewerDescription treeViewerDescription;
private final IChangeListener dummyListener = new IChangeListener() {
public void handleChange(ChangeEvent changeEvent) {
}
};
/**
* @param treeViewerDescription
* @param dataBindingContext
*/
public TreeViewerUpdatableTreeExtended(
TreeViewerDescription treeViewerDescription, IDataBindingContext dataBindingContext) {
super(treeViewerDescription.getTreeViewer(), treeViewerDescription.getClassTypes());
this.treeViewerDescription = treeViewerDescription;
this.dataBindingContext=dataBindingContext;
fillDescriptionDefaults(dataBindingContext);
TreeViewer tableViewer = treeViewerDescription.getTreeViewer();
// TODO synchronize columns on the widget side (create missing columns,
// set name if not already set)
tableViewer.setLabelProvider(new TreeLabelProvider());
tableViewer.setCellModifier(treeViewerDescription.getCellModifier());
int columnCount = getColumnCount();
String[] columnProperties = new String[columnCount];
// TODO need to use the fix for Bug 113713
// It is possible that one column may have multiple cell editors
CellEditor[] cellEditors = new CellEditor[columnCount];
for (int i = 0; i < columnCount; i++) {
columnProperties[i] = Integer.toString(i);
cellEditors[i] = createCellEditor(i);
}
tableViewer.setColumnProperties(columnProperties);
tableViewer.setCellEditors(cellEditors);
}
private int getColumnCount() {
int count=0;
Class[] types = treeViewerDescription.getClassTypes();
for (int i = 0; i < types.length; i++) {
int cc = treeViewerDescription.getColumnCount(types[i]);
if (cc>count)
count = cc;
}
return count;
}
protected CellEditor createCellEditor(final int columnIndex) {
Class[] classTypes = treeViewerDescription.getClassTypes();
CellEditor customEditor = null;
for (int i = 0; i < classTypes.length; i++) {
Column column = treeViewerDescription.getColumn(classTypes[i], columnIndex);
if (column!=null && column.getCellEditor()!=null) {
if (customEditor!=null) {
if (customEditor!=column.getCellEditor()) // Limitation, see Bug 113713
throw new BindingException("Different Cell Editors on Column: "+columnIndex); //$NON-NLS-1$
}
else
customEditor = column.getCellEditor();
}
}
if (customEditor==null)
// Use a default
return new TextCellEditor(treeViewerDescription.getTreeViewer().getTree()) ;
for (int i = 0; i < classTypes.length; i++) {
Column column = treeViewerDescription.getColumn(classTypes[i], columnIndex);
column.setCellEditor(customEditor);
}
return customEditor;
}
protected ICellModifier createCellModifier(final IDataBindingContext dataBindingContext) {
return new ICellModifier() {
private Column findColumn(Class instanceType, String property) {
int index = Integer.parseInt(property);
return treeViewerDescription.getColumn(instanceType, index);
}
public boolean canModify(Object element, String property) {
if (element instanceof Item) {
element = ((Item) element).getData();
}
Column column = findColumn(element.getClass(), property);
if (column!=null && column.getPropertyName()!=null) {
return new PropertyHelper(column.getPropertyName(), element.getClass()).canSet(element);
}
return false;
}
public Object getValue(Object element, String property) {
if (element instanceof Item) {
element = ((Item) element).getData();
}
Column column = findColumn(element.getClass(), property);
if (column == null) {
return null;
}
try {
Object value = new PropertyHelper(column.getPropertyName(), element.getClass()).get(element);
return column.getConverter().convertModelToTarget(value);
} catch (SecurityException e) {
// TODO log
} catch (IllegalArgumentException e) {
// TODO log
}
return null;
}
public void modify(Object element, String property, Object value) {
if (element instanceof Item) {
element = ((Item) element).getData();
}
Column column = findColumn(element.getClass(), property);
if (column == null) {
return;
}
value = column.getConverter().convertTargetToModel(value);
IValidator columnValidator = column.getValidator();
if(columnValidator != null){
String errorMessage = columnValidator.isValid(value);
if(errorMessage != null){
dataBindingContext.updateValidationError(dummyListener, errorMessage);
return;
}
}
new PropertyHelper(column.getPropertyName(), element.getClass()).set(element, value);
viewer.update(element, new String[] { property } );
}
};
}
private void initializeColumnConverter(Column column, Class propertyType){
column.setConverter(dataBindingContext.createConverter(String.class, propertyType, treeViewerDescription));
}
private void initializeColumnValidator(Column column, Class propertyType){
column.setValidator(new IValidator() {
public String isPartiallyValid(Object value) {
return null;
}
public String isValid(Object value) {
return null;
}
});
}
protected CellEditor createCellEditor(final Column column) {
return new TextCellEditor(treeViewerDescription.getTreeViewer().getTree()) {
protected void doSetValue(Object value) {
super.doSetValue( column.getConverter().convertModelToTarget(value));
}
protected Object doGetValue() {
String textValue = (String)super.doGetValue();
return column.getConverter().convertTargetToModel(textValue);
}
};
}
private void fillDescriptionDefaults(final IDataBindingContext dataBindingContext) {
Class[] types = treeViewerDescription.getClassTypes();
if (types==null) return;
for (int i=0; i<types.length; i++) {
int colCount = treeViewerDescription.getColumnCount(types[i]);
for (int j = 0; j < colCount; j++) {
Column column = treeViewerDescription.getColumn(types[i], j);
ColumnInfo info = new ColumnInfo();
columnInfos.put(column, info);
if (column.getConverter() == null) {
info.converterDefaulted = true;
if (column.getPropertyType()!=null)
initializeColumnConverter(column,column.getPropertyType());
else
column.setConverter(new IdentityConverter(String.class));
}
if (column.getValidator() == null) {
info.validatorDefaulted = true;
initializeColumnValidator(column, column.getPropertyType());
}
// TODO need to use this when Bug 113713 is fixed
// if (column.getCellEditor() == null) {
// info.cellEditorDefaulted = true;
// column.setCellEditor(createCellEditor(column));
// }
}
}
if (treeViewerDescription.getCellModifier() == null) {
treeViewerDescription.setCellModifier(createCellModifier(dataBindingContext));
}
if (columnInfos.isEmpty())
columnInfos=null;
}
protected Column getColumn(Class instanceType, int columnIndex) {
return treeViewerDescription.getColumn(instanceType, columnIndex);
}
protected int addElement(final Object parentElement, int index, final Object value, boolean fire) {
// Verify defaults, the first time data cames through
if(columnInfos != null && value!=null){
for (int i = 0; i < treeViewerDescription.getColumnCount(value.getClass()); i++) {
Column column = treeViewerDescription.getColumn(value.getClass(), i);
ColumnInfo columnInfo = (ColumnInfo) columnInfos.remove(column);
if (columnInfo!=null && column.getPropertyName()!=null) {
if(column.getPropertyType() == null && (columnInfo.cellEditorDefaulted || columnInfo.converterDefaulted || columnInfo.validatorDefaulted)){
// Work out the type of the column from the property name from the element type itself
PropertyHelper helper = new PropertyHelper(column.getPropertyName(), value.getClass());
Class columnType =helper.getGetter().getReturnType();
if(columnType != null){
// We have a more explicit property type that was supplied
if(columnInfo.converterDefaulted){
initializeColumnConverter(column,columnType);
}
if(columnInfo.validatorDefaulted){
initializeColumnValidator(column,columnType);
}
}
}
}
}
if (columnInfos.isEmpty())
columnInfos = null; // No More checking
}
return super.addElement(parentElement, index, value, fire);
}
}