/*
* Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org
* Use is subject to license terms. See license.txt.
*/
package org.beanfabrics.swt.table;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.beanfabrics.IModelProvider;
import org.beanfabrics.Link;
import org.beanfabrics.ModelSubscriber;
import org.beanfabrics.Path;
import org.beanfabrics.PathEvaluation;
import org.beanfabrics.View;
import org.beanfabrics.event.ElementChangedEvent;
import org.beanfabrics.event.ElementsAddedEvent;
import org.beanfabrics.event.ElementsDeselectedEvent;
import org.beanfabrics.event.ElementsRemovedEvent;
import org.beanfabrics.event.ElementsReplacedEvent;
import org.beanfabrics.event.ElementsSelectedEvent;
import org.beanfabrics.event.ListListener;
import org.beanfabrics.event.WeakListListener;
import org.beanfabrics.event.WeakPropertyChangeListener;
import org.beanfabrics.log.Logger;
import org.beanfabrics.log.LoggerFactory;
import org.beanfabrics.model.IListPM;
import org.beanfabrics.model.ITextPM;
import org.beanfabrics.model.PresentationModel;
import org.beanfabrics.swt.AbstractDecorator;
import org.beanfabrics.swt.model.IImagePM;
import org.beanfabrics.swt.table.ViewConfig.Column;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
/**
* This is a Beanfabrics view on a {@link IListPM} using an SWT {@link Table}.
*
* @author Michael Karneim
*/
public class BnTableDecorator extends AbstractDecorator<Table> implements View<IListPM<? extends PresentationModel>>, ModelSubscriber {
private static Logger LOG = LoggerFactory.getLogger(BnTableDecorator.class);
private final Link link = new Link(this);
private final PropertyChangeListener listener = new WeakPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (LOG.isDebugEnabled()) {
LOG.debug(".propertyChange()");
}
//refreshUI();
}
};
private final ListListener listListener = new WeakListListener() {
public void elementsSelected(ElementsSelectedEvent evt) {
int start = evt.getBeginIndex();
int end = start + evt.getLength() - 1;
if (LOG.isDebugEnabled()) {
LOG.debug(".elementsSelected() " + start + "-" + end);
}
table.select(start, end);
table.showSelection(); // scroll to first selected index
}
public void elementsReplaced(ElementsReplacedEvent evt) {
int start = evt.getBeginIndex();
int end = start + evt.getLength() - 1;
if (LOG.isDebugEnabled()) {
LOG.debug(".elementsReplaced() " + start + "-" + end);
}
table.remove(start, end);
for (int idx = start; idx <= end; ++idx) {
PresentationModel rowModel = pModel.getAt(idx);
addTableItem(rowModel, idx);
if (pModel.getSelection().contains(idx)) {
table.select(idx);
}
}
}
public void elementsRemoved(ElementsRemovedEvent evt) {
int start = evt.getBeginIndex();
int end = start + evt.getLength() - 1;
table.remove(start, end);
}
public void elementsDeselected(ElementsDeselectedEvent evt) {
int start = evt.getBeginIndex();
int end = start + evt.getLength() - 1;
if (LOG.isDebugEnabled()) {
LOG.debug(".elementsDeselected() " + start + "-" + end);
}
table.deselect(start, end);
}
public void elementsAdded(ElementsAddedEvent evt) {
int start = evt.getBeginIndex();
int end = start + evt.getLength() - 1;
for (int idx = start; idx <= end; ++idx) {
PresentationModel rowModel = pModel.getAt(idx);
addTableItem(rowModel, idx);
if (pModel.getSelection().contains(idx)) {
table.select(idx);
}
}
}
public void elementChanged(ElementChangedEvent evt) {
int index = evt.getIndex();
if (LOG.isDebugEnabled()) {
LOG.debug(".elementChanged() " + index);
}
if (index >= table.getItemCount()) {
// this happens when rarely when an event listener has changed the element
// during the process of adding the element.
return;
}
refreshTableItem(index);
}
};
private final SelectionListener uiSelectionListener = new SelectionListener() {
public void widgetSelected(SelectionEvent evt) {
if (LOG.isDebugEnabled()) {
LOG.debug(".widgetSelected() evt=" + evt);
}
updateModelSelection();
}
public void widgetDefaultSelected(SelectionEvent evt) {
if (LOG.isDebugEnabled()) {
LOG.debug(".widgetDefaultSelected() evt=" + evt);
}
updateModelSelection();
}
};
private final Table table;
private IListPM<? extends PresentationModel> pModel;
private ViewConfig config;
private Collection<TableColumn> columns;
/**
* Create the BnTable
*
* @param parent
* @param style
*/
public BnTableDecorator(Table table) {
super(table);
this.table = table;
hookControl(this.table);
}
/**
* Create the BnTable
*
* @param parent
* @param style
*/
public BnTableDecorator(Composite parent, int style) {
this(new Table(parent, style));
}
/**
* Create the BnTable
*
* @param parent
*/
public BnTableDecorator(Composite parent) {
this(new Table(parent, SWT.SINGLE | SWT.FULL_SELECTION));
}
protected void hookControl(Table table) {
table.addSelectionListener(uiSelectionListener);
}
public void dispose() {
table.removeSelectionListener(uiSelectionListener);
table.dispose();
}
/** {@inheritDoc} */
public IListPM getPresentationModel() {
return pModel;
}
/** {@inheritDoc} */
public void setPresentationModel(IListPM pModel) {
if (this.pModel != null) {
this.pModel.removePropertyChangeListener(listener);
this.pModel.removeListListener(listListener);
}
this.pModel = pModel;
if (this.pModel != null) {
this.pModel.addPropertyChangeListener(listener);
this.pModel.addListListener(listListener);
}
refreshUI();
}
public void setViewConfig(ViewConfig aConfig) {
this.config = aConfig;
refreshUI();
}
/** {@inheritDoc} */
public void setModelProvider(IModelProvider provider) {
this.link.setModelProvider(provider);
}
/** {@inheritDoc} */
public IModelProvider getModelProvider() {
return link.getModelProvider();
}
/** {@inheritDoc} */
public void setPath(Path path) {
this.link.setPath(path);
}
/** {@inheritDoc} */
public Path getPath() {
return link.getPath();
}
public Table getTable() {
return table;
}
protected void refreshUI() {
if (LOG.isDebugEnabled()) {
LOG.debug("BnTable.refreshUI()");
}
// clear UI
dropColumns();
table.removeAll(); // remove rows
// init UI
if (pModel != null && config != null) {
createColumns();
createRows();
refreshUISelection();
}
}
protected void updateModelSelection() {
int[] selIndices = table.getSelectionIndices();
pModel.getSelection().setIndexes(selIndices);
}
protected void refreshUISelection() {
int[] selIndices = pModel.getSelection().getIndexes();
table.setSelection(selIndices);
}
private void dropColumns() {
if (this.columns != null) {
for (TableColumn col : this.columns) {
col.dispose();
}
}
this.columns = null;
}
private void createColumns() {
this.columns = new ArrayList<TableColumn>();
for (ViewConfig.Column col : config.getColumns()) {
TableColumn newCol = new TableColumn(getTable(), SWT.NULL);
newCol.setMoveable(true);
newCol.setResizable(true);
newCol.setText(col.header);
newCol.setWidth(col.width);
this.columns.add(newCol);
}
}
private void createRows() {
int rowIndex = 0;
for (Iterator<? extends PresentationModel> it = pModel.iterator(); it.hasNext(); rowIndex++) {
PresentationModel rowModel = it.next();
addTableItem(rowModel, rowIndex);
}
}
private TableItem addTableItem(PresentationModel rowModel, int rowIndex) {
TableItem result = new TableItem(table, SWT.NULL, rowIndex);
result.setData(rowModel);
int colIndex = -1;
for (ViewConfig.Column col : config.getColumns()) {
colIndex++;
result.setText(colIndex, getText(rowModel, col));
result.setImage(colIndex, getImage(rowModel, col));
}
return result;
}
private String getText(PresentationModel rowModel, ViewConfig.Column col) {
Path path = col.path;
PresentationModel target = PathEvaluation.evaluateOrNull(rowModel, path);
if (target != null && target instanceof ITextPM) {
ITextPM textModel = (ITextPM)target;
return textModel.getText();
} else {
// unsupported target type
return "";
}
}
private Image getImage(PresentationModel rowModel, Column col) {
Path path = col.path;
PresentationModel target = PathEvaluation.evaluateOrNull(rowModel, path);
if (target != null && target instanceof IImagePM) {
IImagePM imgModel = (IImagePM)target;
return imgModel.getImage();
} else {
// unsupported target type
return null;
}
}
protected void refreshTableItem(int index) {
TableItem item = table.getItem(index);
PresentationModel rowModel = (PresentationModel)item.getData();
int colIndex = -1;
for (ViewConfig.Column col : config.getColumns()) {
colIndex++;
item.setText(colIndex, getText(rowModel, col));
item.setImage(colIndex, getImage(rowModel, col));
}
}
}