Java tutorial
/* * Copyright (c) 2012 Diamond Light Source Ltd. * * 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 */ package org.dawnsci.common.widgets.gda.function; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import org.dawb.common.ui.plot.function.FunctionType; import org.dawnsci.common.richbeans.components.cell.FieldComponentCellEditor; import org.dawnsci.common.richbeans.components.wrappers.BooleanWrapper; import org.dawnsci.common.richbeans.components.wrappers.FloatSpinnerWrapper; import org.dawnsci.common.richbeans.components.wrappers.SpinnerWrapper; import org.eclipse.dawnsci.analysis.api.fitting.functions.IFunction; import org.eclipse.dawnsci.analysis.api.fitting.functions.IParameter; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.ToolTip; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Spinner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.ac.diamond.scisoft.analysis.fitting.functions.FunctionFactory; /** * A table widget for editing any Function * * */ public class FunctionEditTable { private static final Logger logger = LoggerFactory.getLogger(FunctionEditTable.class); private TableViewer functionTable; private IFunction function; private IFunction originalFunction; private FunctionType functionType; private List<FunctionRow> rows; public Control createPartControl(Composite parent) { this.functionTable = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER); GridData tableData = new GridData(SWT.FILL, SWT.FILL, true, false, 4, 1); tableData.heightHint = 200; functionTable.getTable().setLayoutData(tableData); createColumns(functionTable); final Label clickToEdit = new Label(parent, SWT.WRAP); clickToEdit.setText("* Click to change"); clickToEdit.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false, 4, 1)); return functionTable.getTable(); } public void addSelectionChangedListener(ISelectionChangedListener listener) { functionTable.addSelectionChangedListener(listener); } public void removeSelectionChangedListener(ISelectionChangedListener listener) { functionTable.removeSelectionChangedListener(listener); } /** * Can be called also to change to editing a different function. * @param function * @param functionType - may be null */ public void setFunction(final IFunction function, final FunctionType functionType) { this.setFunctionType(functionType); this.originalFunction = function != null ? function : null; this.function = function != null ? function : null; this.rows = createFunctionRows(function); functionTable.setContentProvider(new IStructuredContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } @Override public Object[] getElements(Object inputElement) { return rows.toArray(new FunctionRow[rows.size()]); } }); functionTable.setInput(rows.get(0)); } private void createColumns(TableViewer viewer) { ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE); viewer.getTable().setLinesVisible(true); viewer.getTable().setHeaderVisible(true); viewer.setColumnProperties(new String[] { "Name", "value", "min", "max", "Fixed" }); TableViewerColumn var = new TableViewerColumn(viewer, SWT.LEFT, 0); var.getColumn().setText("Name"); var.getColumn().setWidth(100); var.setLabelProvider(new FunctionLabelProvider(0)); var = new TableViewerColumn(viewer, SWT.LEFT, 1); var.getColumn().setText("value"); var.getColumn().setWidth(120); FunctionEditingSupport functionEditor = new FunctionEditingSupport(viewer, 1); var.setEditingSupport(functionEditor); var.setLabelProvider(new DelegatingStyledCellLabelProvider(new FunctionLabelProvider(1, functionEditor))); var = new TableViewerColumn(viewer, SWT.LEFT, 2); var.getColumn().setText("min"); var.getColumn().setWidth(120); functionEditor = new FunctionEditingSupport(viewer, 2); var.setEditingSupport(functionEditor); var.setLabelProvider(new DelegatingStyledCellLabelProvider(new FunctionLabelProvider(2, functionEditor))); var = new TableViewerColumn(viewer, SWT.LEFT, 3); var.getColumn().setText("max"); var.getColumn().setWidth(120); functionEditor = new FunctionEditingSupport(viewer, 3); var.setEditingSupport(functionEditor); var.setLabelProvider(new DelegatingStyledCellLabelProvider(new FunctionLabelProvider(3, functionEditor))); // column 4 = checkbox var = new TableViewerColumn(viewer, SWT.LEFT, 4); var.getColumn().setText("Fixed"); var.getColumn().setWidth(120); functionEditor = new FunctionEditingSupport(viewer, 4); var.setEditingSupport(functionEditor); var.setLabelProvider(new DelegatingStyledCellLabelProvider(new FunctionLabelProvider(4, functionEditor))); //functionTable.getTable().setHeaderVisible(false); } public void cancelEditing() { this.functionTable.cancelEditing(); } public class FunctionEditingSupport extends EditingSupport { private int column; public FunctionEditingSupport(ColumnViewer viewer, int col) { super(viewer); this.column = col; } @Override protected CellEditor getCellEditor(final Object element) { FieldComponentCellEditor ed = null; if (column < 4) { try { ed = new FieldComponentCellEditor(((TableViewer) getViewer()).getTable(), FloatSpinnerWrapper.class.getName(), SWT.RIGHT); } catch (ClassNotFoundException e) { logger.error("Cannot get FieldComponentCellEditor for " + SpinnerWrapper.class.getName(), e); return null; } final FloatSpinnerWrapper rb = (FloatSpinnerWrapper) ed.getFieldWidget(); if (rb.getPrecision() < 5) rb.setFormat(rb.getWidth(), 5); rb.setMaximum(Double.MAX_VALUE); rb.setMinimum(-Double.MAX_VALUE); rb.setButtonVisible(false); rb.setActive(true); // rb.setFormat(10, 5); ((Spinner) rb.getControl()).addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setValue(element, rb.getValue(), false); } }); } else { try { ed = new FieldComponentCellEditor(((TableViewer) getViewer()).getTable(), BooleanWrapper.class.getName(), SWT.LEFT); } catch (ClassNotFoundException e) { logger.error("Cannot get FieldComponentCellEditor for " + BooleanWrapper.class.getName(), e); return null; } final BooleanWrapper bw = (BooleanWrapper) ed.getFieldWidget(); bw.setVisible(true); bw.setActive(true); ((Button) bw.getControl()).addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setValue(element, bw.getValue(), false); } }); } return ed; } @Override protected boolean canEdit(Object element) { final FunctionRow row = (FunctionRow) element; if (column < 4) { double val = 0; if (!row.isEnabled()) return false; val = row.getParameter(column - 1); return !Double.isNaN(val); } else { return true; } } @Override protected Object getValue(Object element) { final FunctionRow row = (FunctionRow) element; if (column < 4) { return (double) row.getParameter(column - 1); } else { return row.isFixed(); } } @Override protected void setValue(Object element, Object value) { this.setValue(element, value, true); } protected void setValue(Object element, Object value, boolean tableRefresh) { final FunctionRow row = (FunctionRow) element; if (column < 4) { final Number val = (Number) value; row.setParameter(val.doubleValue(), column - 1); if (tableRefresh) { getViewer().refresh(); } function = createFunction(rows, row); } else { // for the last column (checkbox) final boolean fixed = (Boolean) value; row.setIsFixed(fixed); if (tableRefresh) { getViewer().refresh(); } function = createFunction(rows, row); } } } public class FunctionLabelProvider extends ColumnLabelProvider implements IStyledLabelProvider { private int column; private NumberFormat format; private FunctionEditingSupport editor; public FunctionLabelProvider(int col) { this(col, null); } public FunctionLabelProvider(int col, final FunctionEditingSupport editor) { this.column = col; this.format = NumberFormat.getNumberInstance(); this.editor = editor; } @Override public String getText(Object element) { final FunctionRow row = (FunctionRow) element; switch (column) { case 0: return row.getParamName(); case 1: if (Double.isNaN(row.getParameter(0))) return "-"; return format.format(row.getParameter(0)); case 2: if (Double.isNaN(row.getParameter(1))) return "-"; return format.format(row.getParameter(1)); case 3: if (Double.isNaN(row.getParameter(2))) return "-"; return format.format(row.getParameter(2)); case 4: if (row.isFixed()) return "true"; else return "false"; } return ""; } @Override public String getToolTipText(Object element) { final FunctionRow row = (FunctionRow) element; return row.getDescription(); } @Override public StyledString getStyledText(Object element) { final StyledString ret = new StyledString(getText(element)); if (editor != null && editor.canEdit(element)) { ret.append(new StyledString("*", StyledString.QUALIFIER_STYLER)); } return ret; } } private List<FunctionRow> createFunctionRows(IFunction function) { final List<FunctionRow> ret = new ArrayList<FunctionEditTable.FunctionRow>(); int numberParam = function.getNoOfParameters(); for (int i = 0; i < numberParam; i++) { IParameter p = function.getParameter(i); String functionDescription = function.getDescription(); ret.add(new FunctionRow(p.getName(), functionDescription, p.isFixed(), p.getValue(), p.getLowerLimit(), p.getUpperLimit())); } return ret; } public IFunction createFunction(List<FunctionRow> rows, FunctionRow changed) { try { IFunction ret = FunctionFactory.getFunction(function.getName()); final int count = function.getNoOfParameters(); for (int i = 0; i < count; i++) { ret.getParameter(i).setValue(rows.get(i).getParameter(0)); ret.getParameter(i).setLowerLimit(rows.get(i).getParameter(1)); ret.getParameter(i).setUpperLimit(rows.get(i).getParameter(2)); ret.getParameter(i).setFixed(rows.get(i).isFixed()); } return ret; } catch (Exception ne) { ne.printStackTrace(); //logger.error("Unable to create function "+function.getName(), ne); } return null; } public void dispose() { function = null; originalFunction = null; setFunctionType(null); rows.clear(); rows = null; } private final static class FunctionRow { private String name; private String paramName; private String description; private double[] params; private boolean enabled = true; private boolean fixed = false; public FunctionRow(String name, String description, boolean fixed, double... parameters) { this.paramName = name; this.description = description; this.fixed = fixed; this.params = parameters; } @SuppressWarnings("unused") public String getName() { return name; } public String getDescription() { return description; } public String getParamName() { return paramName; } @SuppressWarnings("unused") public double[] getParameters() { return params; } public boolean isFixed() { return fixed; } public void setIsFixed(boolean value) { fixed = value; } public double getParameter(int index) { return params[index]; } public void setParameter(double value, int index) { params[index] = value; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((description == null) ? 0 : description.hashCode()); result = prime * result + ((paramName == null) ? 0 : paramName.hashCode()); for (int i = 0; i < params.length; i++) { long temp = Double.doubleToLongBits(params[i]); result = prime * result + (int) (temp ^ (temp >>> 32)); } return result; } @Override public boolean equals(Object obj) { // if (this == obj) // return true; // if (obj == null) // return false; // if (getClass() != obj.getClass()) // return false; // FunctionRow other = (FunctionRow) obj; // if (name == null) { // if (other.name != null) // return false; // } else if (!name.equals(other.name)) // return false; // if (unit == null) { // if (other.unit != null) // return false; // } else if (!unit.equals(other.unit)) // return false; // if (Double.doubleToLongBits(xLikeVal) != Double // .doubleToLongBits(other.xLikeVal)) // return false; // if (Double.doubleToLongBits(yLikeVal) != Double // .doubleToLongBits(other.yLikeVal)) // return false; return true; } public boolean isEnabled() { return enabled; } @SuppressWarnings("unused") public void setEnabled(boolean enabled) { this.enabled = enabled; } } public IFunction getOriginalFunction() { return originalFunction; } public IFunction getFunction() { return function; } public FunctionType getFunctionType() { return functionType; } public void setFunctionType(FunctionType functionType) { this.functionType = functionType; } }