package org.archstudio.swtutils;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
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.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
public class NameValuePairTable {
public interface Controller<T> {
public String getNameColumnHeader();
public String getValueColumnHeader();
public boolean getAllowChangingRows();
public List<Map.Entry<String, String>> getEntries(T input);
public void setPropertyValue(T input, String propertyName, String propertyValue);
public void clearPropertyValue(T input, String propertyName);
public void removeProperty(T input, String propertyName);
}
public static <T> TableViewer createTableViewer(Composite parent, final T input, final Controller<T> controller) {
final TableViewer tv = new TableViewer(parent, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.NO_FOCUS);
tv.setContentProvider(new ViewContentProvider<T>(controller));
tv.setLabelProvider(new ViewLabelProvider());
tv.setInput(input);
Table table = tv.getTable();
TableColumn column = new TableColumn(table, SWT.LEFT);
column.setText(controller.getNameColumnHeader());
TableColumn column2 = new TableColumn(table, SWT.LEFT);
column2.setText(controller.getValueColumnHeader());
TableLayout tableLayout = new AutoResizeTableLayout(table);
tableLayout.addColumnData(new ColumnWeightData(30, true));
tableLayout.addColumnData(new ColumnWeightData(70, true));
table.setLayout(tableLayout);
table.setHeaderVisible(true);
table.setLinesVisible(true);
table.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
tv.setColumnProperties(new String[] { controller.getNameColumnHeader(), controller.getValueColumnHeader() });
CellEditor tce = new TextCellEditor(table);
tv.setCellEditors(new CellEditor[] { null, tce });
tv.setCellModifier(new ViewCellModifier<T>(parent, controller, input));
if (controller.getAllowChangingRows()) {
Composite cChangeRows = new Composite(parent, SWT.NONE);
cChangeRows.setLayout(new GridLayout(6, false));
Label lName = new Label(cChangeRows, SWT.NONE);
lName.setText("Name: ");
final Text tfName = new Text(cChangeRows, SWT.SINGLE | SWT.BORDER);
tfName.setEditable(true);
tfName.setLayoutData(new GridData(150, SWT.DEFAULT));
Label lValue = new Label(cChangeRows, SWT.NONE);
lValue.setText("Value: ");
final Text tfValue = new Text(cChangeRows, SWT.SINGLE | SWT.BORDER);
tfValue.setEditable(true);
tfValue.setLayoutData(new GridData(150, SWT.DEFAULT));
SelectionListener slAddRow = new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
@Override
public void widgetSelected(SelectionEvent e) {
String name = tfName.getText().trim();
String value = tfValue.getText().trim();
if (name.length() > 0 && value.length() > 0) {
controller.setPropertyValue(input, tfName.getText(), tfValue.getText());
}
}
};
tfValue.addSelectionListener(slAddRow);
final Button bAddRow = new Button(cChangeRows, SWT.PUSH);
bAddRow.setText("Add");
bAddRow.addSelectionListener(slAddRow);
final Button bRemoveRow = new Button(cChangeRows, SWT.PUSH);
bRemoveRow.setText("Remove Selected");
bRemoveRow.setEnabled(!tv.getSelection().isEmpty());
tv.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
bRemoveRow.setEnabled(!tv.getSelection().isEmpty());
}
});
SelectionListener slRemoveRow = new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
@Override
public void widgetSelected(SelectionEvent e) {
ISelection selection = tv.getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
Object element = structuredSelection.getFirstElement();
if (element instanceof String[]) {
String propertyName = ((String[]) element)[0];
controller.removeProperty(input, propertyName);
}
}
}
};
bRemoveRow.addSelectionListener(slRemoveRow);
}
tv.refresh();
return tv;
}
protected static class ViewContentProvider<T> implements IStructuredContentProvider {
private final Controller<T> controller;
public ViewContentProvider(Controller<T> controller) {
this.controller = controller;
}
@Override
@SuppressWarnings("unchecked")
public Object[] getElements(Object inputElement) {
List<Map.Entry<String, String>> nameValuePairList = controller.getEntries((T) inputElement);
Object[] entryArray = new Object[nameValuePairList.size()];
for (int i = 0; i < nameValuePairList.size(); i++) {
Map.Entry<String, String> entry = nameValuePairList.get(i);
entryArray[i] = new String[] { entry.getKey(), entry.getValue() };
}
return entryArray;
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
protected static class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
@Override
public String getColumnText(Object obj, int index) {
return ((String[]) obj)[index];
}
@Override
public Image getColumnImage(Object obj, int index) {
return null;
}
@Override
public Image getImage(Object obj) {
return null;
}
}
protected static class ViewCellModifier<T> implements ICellModifier {
protected final Composite parent;
protected final Controller<T> controller;
protected final Object input;
public ViewCellModifier(Composite parent, Controller<T> controller, Object input) {
this.parent = parent;
this.controller = controller;
this.input = input;
}
@Override
public boolean canModify(Object element, String property) {
return true;
}
@Override
public Object getValue(Object element, String property) {
if (element == null) {
return "";
}
if (element instanceof String[]) {
String[] elts = (String[]) element;
if (elts[1] == null) {
return "";
}
return elts[1].toString();
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public void modify(Object element, String property, Object value) {
//SWT bug workaround
if (element instanceof Item) {
element = ((Item) element).getData();
}
if (element instanceof String[]) {
String[] elts = (String[]) element;
String propertyName = elts[0].toString();
String oldValue = null;
if (elts[1] != null) {
oldValue = elts[1].toString();
}
String newValue = null;
if (value != null) {
newValue = value.toString();
}
if (oldValue == null && newValue == null) {
//Do nothing
}
else if (oldValue != null && newValue == null) {
controller.clearPropertyValue((T) input, propertyName);
}
else if (oldValue == null && newValue != null) {
set(propertyName, newValue);
}
else {
//Both non-null:
if (!oldValue.equals(newValue)) {
set(propertyName, newValue);
}
}
}
}
@SuppressWarnings("unchecked")
private void set(String propertyName, String propertyValue) {
if (propertyName != null) {
try {
controller.setPropertyValue((T) input, propertyName, propertyValue);
}
catch (IllegalArgumentException iae) {
MessageBox messageBox = new MessageBox(parent.getShell(), SWT.OK | SWT.ICON_ERROR);
messageBox.setMessage("Invalid value for this field.");
messageBox.setText("Error");
messageBox.open();
}
}
}
}
}