/*
* Copyright (c) 2008 Stiftung Deutsches Elektronen-Synchrotron,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
*
* THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
* WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
* CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
* DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
* THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
* USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
* PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
* AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
*/
package org.csstudio.sds.ui.internal.dynamicswizard;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.csstudio.dal.ui.dnd.rfc.IProcessVariableAdressReceiver;
import org.csstudio.dal.ui.dnd.rfc.IShowControlSystemDialogStrategy;
import org.csstudio.dal.ui.dnd.rfc.ProcessVariableExchangeUtil;
import org.csstudio.domain.common.LayoutUtil;
import org.csstudio.platform.model.pvs.DalPropertyTypes;
import org.csstudio.platform.model.pvs.IProcessVariableAddress;
import org.csstudio.platform.model.pvs.IProcessVariableAdressProvider;
import org.csstudio.platform.model.pvs.ProcessVariableAdressFactory;
import org.csstudio.sds.internal.rules.NullRule;
import org.csstudio.sds.internal.rules.ParameterDescriptor;
import org.csstudio.sds.internal.rules.RuleDescriptor;
import org.csstudio.sds.internal.rules.RuleService;
import org.csstudio.sds.model.DynamicsDescriptor;
import org.csstudio.sds.model.PropertyTypesEnum;
import org.csstudio.sds.ui.SdsUiPlugin;
import org.csstudio.sds.ui.properties.IPropertyDescriptor;
import org.csstudio.sds.util.ChannelReferenceValidationException;
import org.csstudio.sds.util.ChannelReferenceValidationUtil;
import org.csstudio.sds.util.SelectionUtil;
import org.csstudio.ui.util.CustomMediaFactory;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TableViewerEditor;
import org.eclipse.jface.viewers.TableViewerFocusCellManager;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
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.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
/**
* WizardPage implementation, which enables the user to configure a simple
* channel.
*
* @author Sven Wende
*/
public final class SimpleChannelPage extends WizardPage {
/**
* A table viewer, which is used to configure input parameters.
*/
private TableViewer _channelTableViewer;
/**
* A table viewer, which is used to configure output parameters.
*/
private TableViewer _outputChannelTableViewer;
/**
* Flag that signals if the definition of output channels should
* automatically lead to the definition of an input channel.
*/
private final boolean _isLinkOutput = true;
/**
* The dynamics descriptor that is edited.
*/
private final DynamicsDescriptor _dynamicsDescriptor;
/**
* The model for the channel table.
*/
private InputChannelTableModel _inputChannelTableModel;
/**
* Names of existing aliases that can be used in channel names.
*/
private final Map<String, String> _aliases;
/**
* A tree viewer, which shows the available rules.
*/
private TreeViewer _rulesViewer;
/**
* Checkbox for using only the connection states.
*/
private Button _useOnlyConnectionsCheckBox;
/**
* The selected rule.
*/
private RuleDescriptor _selectedRule;
private Text _rulePattern;
private final PropertyTypesEnum _propertyType;
private Text _ruleDescriptionText;
/**
* An action, which removes an input channel from the configuration.
*
* @author Sven Wende
*/
private final class RemoveChannelAction extends Action {
/**
* Constructor.
*/
public RemoveChannelAction() {
super("Remove Parameter", CustomMediaFactory.getInstance()
.getImageDescriptorFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/parameter_remove.gif"));
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
final IStructuredSelection sel = (IStructuredSelection) _channelTableViewer
.getSelection();
if (sel != null && sel.getFirstElement() != null) {
_inputChannelTableModel.removeRow((InputChannelTableRow) sel
.getFirstElement());
_channelTableViewer.refresh();
}
}
}
/**
* An action, which adds a type hint to the selected channel parameter.
*
* @author Sven Wende
*/
protected final class AppendTypeHintAction extends Action {
/**
* The {@link DalPropertyTypes}.
*/
private final DalPropertyTypes _typeHint;
/**
* Constructor.
*
* @param typeHint
* The {@link DalPropertyTypes}
*/
protected AppendTypeHintAction(final DalPropertyTypes typeHint) {
super(typeHint.toString(), CustomMediaFactory.getInstance()
.getImageDescriptorFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/getas.gif"));
assert typeHint != null;
_typeHint = typeHint;
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
final IStructuredSelection sel = (IStructuredSelection) _channelTableViewer
.getSelection();
if (sel != null && sel.getFirstElement() != null && !sel.isEmpty()) {
for (final Object o : sel.toArray()) {
final InputChannelTableRow row = (InputChannelTableRow) o;
final String rowValue = row.getChannel();
if (rowValue != null && rowValue.length() > 0) {
row.setChannel(applyTypeHint(rowValue));
}
}
_channelTableViewer.refresh();
}
}
/**
* Adds the type hint to the channel url.
*
* @param channel
* the existing channel url
* @return a enriched channel url
*/
private String applyTypeHint(final String channel) {
String result = null;
// try to replace existing type hint
final String newPattern = ", " + _typeHint.toPortableString();
for (final DalPropertyTypes dalType : DalPropertyTypes.values()) {
final String oldPattern = ", " + dalType.toPortableString();
if (dalType != _typeHint && channel.indexOf(oldPattern) > 0) {
result = channel.replace(oldPattern, newPattern);
}
}
// if there was no existing type hint, just add the new one
if (result == null) {
result = channel + newPattern;
}
return result;
}
}
/**
* An action, which adds an input channel to the configuration.
*
* @author Sven Wende
*/
protected final class AddInputChannelAction extends Action {
/**
* Constructor.
*/
protected AddInputChannelAction() {
super("Add Parameter", CustomMediaFactory.getInstance()
.getImageDescriptorFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/parameter_in.gif"));
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
addInputChannel("<<Channel>>");
}
}
/**
* An action, which adds an output channel to the configuration.
*
* @author Alexander Will
*/
protected final class AddOutputChannelAction extends Action {
/**
* Constructor.
*/
protected AddOutputChannelAction() {
super("Add Output Channel", CustomMediaFactory.getInstance()
.getImageDescriptorFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/parameter_out.gif"));
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
addOutputChannel("<<Channel>>");
}
}
/**
* Label provider for the channel tables.
*
* @author Sven Wende
*
*/
protected final class ChannelTableLabelProvider extends ColumnLabelProvider {
/**
* FIXME: Momentan ist update() nur wegen eines Workarrounds
* �berschrieben. Umstellen des Labelproviders auf
* TableColumnViewerLabelProvider.class, sobald diese public ist.
* {@inheritDoc}
*/
@Override
public void update(final ViewerCell cell) {
final Object element = cell.getElement();
final int index = cell.getColumnIndex();
cell.setText(getText(element, index));
final Image image = getImage(element, index);
cell.setImage(image);
cell.setBackground(getBackground(element));
cell.setForeground(getForeground(element, index));
cell.setFont(getFont(element, index));
}
/**
* Returns the text to display.
*
* @param element
* the current element
* @param columnIndex
* the current column index
* @return The text to display in the viewer
*/
private String getText(final Object element, final int columnIndex) {
final InputChannelTableRow row = (InputChannelTableRow) element;
String result = "";
switch (columnIndex) {
case 0:
result = row.getDescription();
break;
case 1:
result = row.getChannel();
break;
case 2:
result = row.getDefaultValueAsString();
break;
default:
break;
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public String getToolTipText(final Object element) {
String tooltip = "";
final InputChannelTableRow row = (InputChannelTableRow) element;
final String rawChannel = row.getChannel();
try {
// try to resolve the name (this should replace all aliases)
final String channel = ChannelReferenceValidationUtil
.createCanonicalName(rawChannel, _aliases);
tooltip = channel + " [STRING]";
} catch (final ChannelReferenceValidationException e) {
tooltip = e.getMessage();
}
return tooltip;
}
/**
* {@inheritDoc}
*/
@Override
public Point getToolTipShift(final Object object) {
return new Point(5, 5);
}
/**
* {@inheritDoc}
*/
@Override
public int getToolTipDisplayDelayTime(final Object object) {
return 100;
}
/**
* {@inheritDoc}
*/
@Override
public int getToolTipTimeDisplayed(final Object object) {
return 10000;
}
/**
* Returns the font, which is used to display the channel informations.
*
* @param element
* The current element
* @param column
* The current column index
* @return The font
*/
private Font getFont(final Object element, final int column) {
int style = SWT.BOLD;
final InputChannelTableRow row = (InputChannelTableRow) element;
if (column == 1) {
if (row.getDescription() == null
|| row.getDescription().equals("")) {
style = SWT.ITALIC;
} else {
style = SWT.NONE;
}
}
return CustomMediaFactory.getInstance().getDefaultFont(style);
}
/**
* returns the foreground color for a cell.
*
* @param element
* The current element
* @param column
* The current column index
* @return The foreground color
*/
private Color getForeground(final Object element, final int column) {
RGB rgb = new RGB(0, 0, 0);
if (column == 1) {
final InputChannelTableRow row = (InputChannelTableRow) element;
if (row.getDescription() == null
|| row.getDescription().equals("")) {
rgb = new RGB(200, 200, 200);
} else {
if (!ChannelReferenceValidationUtil.testValidity(row
.getChannel())) {
rgb = new RGB(255, 160, 160);
}
}
}
return CustomMediaFactory.getInstance().getColor(rgb);
}
/**
* Returns the Image for a cell.
*
* @param element
* The current element
* @param index
* The current column index
* @return The Image for the cell
*/
private Image getImage(final Object element, final int index) {
Image result = null;
if (index == 0) {
final InputChannelTableRow row = (InputChannelTableRow) element;
if (row.getParameterType() == ParameterType.IN) {
result = CustomMediaFactory.getInstance()
.getImageFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/parameter_in.gif"); //$NON-NLS-1$
} else if (row.getParameterType() == ParameterType.OUT) {
result = CustomMediaFactory.getInstance()
.getImageFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/parameter_out.gif"); //$NON-NLS-1$
}
}
return result;
}
}
/**
* Content provider for the input channel table.
*
* @author Sven Wende
*
*/
protected final class ChannelTableContentProvider implements
IStructuredContentProvider {
/**
* {@inheritDoc}
*/
@Override
public void inputChanged(final Viewer viewer, final Object oldInput,
final Object newInput) {
}
/**
* {@inheritDoc}
*/
@Override
public Object[] getElements(final Object parent) {
return _inputChannelTableModel.getAllRows().toArray();
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
}
}
/**
* Cell modifier for the channel tables.
*
* @author Sven Wende
*
*/
protected class ChannelTableCellModifier implements ICellModifier {
/**
* Constructor.
*/
protected ChannelTableCellModifier() {
}
/**
* {@inheritDoc}
*/
@Override
public final boolean canModify(final Object element,
final String property) {
return true;
}
/**
* {@inheritDoc}
*/
@Override
public final Object getValue(final Object element, final String property) {
Object result = null;
final InputChannelTableRow row = (InputChannelTableRow) element;
switch (findColumnIndex(property)) {
case 0:
result = row.getChannel();
break;
case 1:
result = row.getChannel();
break;
default:
break;
}
assert result != null : "result!=null"; //$NON-NLS-1$;
return result;
}
/**
* {@inheritDoc}
*/
@Override
public final void modify(final Object element, final String property,
final Object value) {
InputChannelTableRow row;
// @see ICellModifier#modify(element, property, value)
if (element instanceof Item) {
row = (InputChannelTableRow) ((Item) element).getData();
} else {
row = (InputChannelTableRow) element;
}
switch (findColumnIndex(property)) {
case 1:
final String rawInput = (String) value;
String channel = "";
// We take the plain raw input by default. If the entered name
// does not reference any aliases, we try to
// validate it using the process variable name parsers, which
// might automatically add a control system prefix.
final boolean valid = ChannelReferenceValidationUtil
.testValidity(rawInput);
if (valid) {
final List<String> requiredAliasNames = ChannelReferenceValidationUtil
.getRequiredAliasNames(rawInput);
if (requiredAliasNames.isEmpty()) {
final IProcessVariableAddress pv = ProcessVariableExchangeUtil
.parseProcessVariableAdress(rawInput, true);
if (pv != null) {
channel = pv.getFullName();
}
} else {
channel = rawInput;
}
} else {
channel = rawInput;
}
// setChannelHook(row, channel);
row.setChannel(channel);
break;
default:
break;
}
_channelTableViewer.refresh();
_channelTableViewer.setSelection(null);
}
/**
* Hook method that is called before the channel name is actually set.
* Subclasses may overwrite in order to perform custom actions.
*
* @param descriptor
* the parameter descriptor.
* @param channel
* the new channel name.
*/
protected void setChannelHook(final ParameterDescriptor descriptor,
final String channel) {
}
/**
* Gets the colunmn index for the specified property.
*
* @param property
* the property
*
* @return the column index
*/
private int findColumnIndex(final String property) {
int result = 0;
// Find the index of the column
final Object[] columnHeaders = _channelTableViewer.getColumnProperties();
for (int i = 0; i < columnHeaders.length; i++) {
if (columnHeaders[i].equals(property)) {
result = i;
}
}
return result;
}
}
/**
* The {@link EditingSupport} for the columns of the property table.
*
* @author Kai Meyer
*
*/
private final class CustomEditingSupport extends EditingSupport {
/**
* The {@link Table} where this {@link EditingSupport} is embedded.
*/
private final Table _table;
/**
* Determines if this {@link EditingSupport} is for the <i>Channel</i>
* column.
*/
private final boolean _channelColumn;
/**
* Constructor.
*
* @param viewer
* The {@link ColumnViewer} for this {@link EditingSupport}.
* @param table
* The {@link Table}
* @param channelColumn
* True if this {@link EditingSupport} is for the <i>Channel</i>
* column
*/
private CustomEditingSupport(final ColumnViewer viewer,
final Table table, final boolean channelColumn) {
super(viewer);
_table = table;
_channelColumn = channelColumn;
}
/**
* {@inheritDoc}
*/
@Override
protected boolean canEdit(final Object element) {
return true;
}
/**
* {@inheritDoc}
*/
@Override
protected CellEditor getCellEditor(final Object element) {
return new TextCellEditor(_table);
}
/**
* {@inheritDoc}
*/
@Override
protected Object getValue(final Object element) {
if (element instanceof InputChannelTableRow) {
final InputChannelTableRow row = (InputChannelTableRow) element;
if (_channelColumn) {
return row.getChannel();
}
return row.getDefaultValue();
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
protected void setValue(final Object element, final Object value) {
if (element instanceof InputChannelTableRow) {
if (_channelColumn) {
((InputChannelTableRow) element).setChannel(value
.toString());
_channelTableViewer.getCellModifier().modify(element,
"PROP_NAME", value);
} else {
String newValue = "";
if (value != null) {
newValue = value.toString();
}
((InputChannelTableRow) element).setDefaultValue(newValue);
}
}
this.getViewer().refresh();
}
}
/**
* Constructor.
*
* @param pageName
* the name of the page
* @param dynamicsDescriptor
* the {@link DynamicsDescriptor}
* @param propertyDescriptor
* the {@link IPropertyDescriptor}
* @param aliases
* the aliases
*/
public SimpleChannelPage(final String pageName,
final DynamicsDescriptor dynamicsDescriptor,
final PropertyTypesEnum propertyType,
final Map<String, String> aliases) {
super(pageName);
assert dynamicsDescriptor != null;
assert aliases != null;
assert propertyType != null : "propertyType != null";
_propertyType = propertyType;
setTitle("Dynamics Wizard");
setDescription("Use this wizard to configure the dynamic behaviour of your properties");
_dynamicsDescriptor = dynamicsDescriptor;
_aliases = aliases;
}
/**
* {@inheritDoc}
*/
@Override
public void createControl(final Composite parent) {
final Composite c = new Composite(parent, SWT.None);
c.setLayout(new GridLayout(1, false));
_useOnlyConnectionsCheckBox = new Button(c, SWT.CHECK);
_useOnlyConnectionsCheckBox.setText("Use only connection states");
_useOnlyConnectionsCheckBox
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
executeCheckBoxStateChange(_useOnlyConnectionsCheckBox
.getSelection());
}
});
_rulePattern = new Text(c, SWT.SEARCH);
_rulePattern.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
_rulePattern.setMessage("Rule Pattern");
_rulesViewer = createRuleControl(c);
_channelTableViewer = createInputChannelsTable(c);
createAliasInformation(c);
// initialize the widgets
if (_dynamicsDescriptor.getRuleId() != null) {
_selectedRule = RuleService.getInstance().getRuleDescriptor(
_dynamicsDescriptor.getRuleId());
if (_selectedRule != null) {
_rulesViewer
.setSelection(new StructuredSelection(_selectedRule));
}
updateChannelTableModel();
}
_useOnlyConnectionsCheckBox.setSelection(_dynamicsDescriptor
.isUsingOnlyConnectionStates());
this.executeCheckBoxStateChange(_useOnlyConnectionsCheckBox
.getSelection());
// important for wizards -> set the control
setControl(c);
}
/**
* @param c
* @return
*/
private Text createDescriptionControl(final Composite c) {
final Text text = new Text(c, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER|SWT.READ_ONLY);
// text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
text.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
text.setText("");
return text;
}
/**
* Updates the viewer for the rules depending on given choice.
*
* @param choice
* <code>true</code> if the viewer should be disabled,
* <code>false</code> otherwise.
*/
private void executeCheckBoxStateChange(final boolean choice) {
_rulesViewer.getTree().setEnabled(!choice);
if (choice) {
_selectedRule = RuleService.getInstance().getRuleDescriptor(
NullRule.ID);
} else {
_selectedRule = RuleService.getInstance().getRuleDescriptor(
_dynamicsDescriptor.getRuleId());
}
updateChannelTableModel();
}
/**
* Creates a control, which contains a filtered list of rules.
*
* @param parent
* the parent composite
* @return the control
*/
private TreeViewer createRuleControl(final Composite parent) {
final Group group = new Group(parent, SWT.NONE);
group.setLayout(new GridLayout(2, false));
group.setText("Rules / Scripts");
group.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.CENTER).hint(SWT.DEFAULT, 120).create());
final TreeViewer viewer = new TreeViewer(group, SWT.DROP_DOWN | SWT.READ_ONLY
| SWT.SCROLL_LINE | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
viewer.getControl().setLayoutData(GridDataFactory.fillDefaults().grab(false, true).create());
_ruleDescriptionText = createDescriptionControl(group);
viewer.setLabelProvider(new WorkbenchLabelProvider());
viewer.setContentProvider(new BaseWorkbenchContentProvider() {
@SuppressWarnings("unchecked")
@Override
public Object[] getElements(final Object element) {
return ((Collection<RuleDescriptor>) element).toArray();
}
});
ColumnViewerToolTipSupport.enableFor(viewer);
final List<RuleDescriptor> rules = RuleService.getInstance()
.getRegisteredRuleDescriptors();
Collections.sort(rules, new Comparator<RuleDescriptor>() {
@Override
public int compare(final RuleDescriptor r1, final RuleDescriptor r2) {
return r1.getDescription().compareTo(r2.getDescription());
}
});
viewer.setInput(rules);
// setup a filter for the rules
viewer.addFilter(new ViewerFilter() {
@Override
public boolean select(final Viewer viewer,
final Object parentElement, final Object element) {
final RuleDescriptor ruleDescriptor = (RuleDescriptor) element;
final PropertyTypesEnum[] ruleReturnType = ruleDescriptor.getCompatiblePropertyTypes();
for (final PropertyTypesEnum type : ruleReturnType) {
if (type.equals(_propertyType)) {
return true;
}
}
return false;
}
});
// Filter for Pattern set by User.
viewer.addFilter(new ViewerFilter() {
@Override
public boolean select(final Viewer viewer, final Object parentElement, final Object element) {
final RuleDescriptor ruleDescriptor = (RuleDescriptor) element;
final String pattern = _rulePattern.getText();
if (pattern == null || pattern.length() < 1) {
return true;
}
return ruleDescriptor.getDescription().toLowerCase().matches(
pattern.replace("$", "\\$").replace(".", "\\.").replace("*", ".*").replace(
"?", ".?").toLowerCase()
+ ".*");
}
});
// listener to update rule list for new rule patterns set by user.
_rulePattern.addKeyListener(new KeyListener() {
@Override
public void keyPressed(final KeyEvent e) {
}
@Override
public void keyReleased(final KeyEvent e) {
viewer.refresh();
}
});
// add a selection listener that updates the channel table when the rule
// changes
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
final IStructuredSelection sel = (IStructuredSelection) event
.getSelection();
if (sel.getFirstElement() != null) {
final RuleDescriptor descriptor = (RuleDescriptor) sel
.getFirstElement();
_selectedRule = descriptor;
String description = descriptor.getRule().getDescription();
if(description == null || description.isEmpty()) {
description = "no description available";
}
_ruleDescriptionText.setText(description);
updateChannelTableModel();
}
}
});
return viewer;
}
/**
* Creates a table viewer, which enables the user to enter typed input
* channels.
*
* @param parent
* the parent composite
*
* @return the created viewer
*/
private TableViewer createInputChannelsTable(final Composite parent) {
final Group group = new Group(parent, SWT.NONE);
group.setLayout(LayoutUtil.createGridLayout(1, 0, 0, 0));
group.setText("Input Channels");
group.setLayoutData(LayoutUtil
.createGridDataForHorizontalFillingCell(300));
final TableViewer viewer = createChannelTable(group);
// enable Tooltip support
ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
// cell modifiers
final ICellModifier cellModifier = new ChannelTableCellModifier() {
@Override
protected void setChannelHook(final ParameterDescriptor descriptor,
final String channel) {
if (_isLinkOutput) {
if (_dynamicsDescriptor.getOutputChannel() != null
&& _dynamicsDescriptor.getOutputChannel().equals(
descriptor)) {
_dynamicsDescriptor.getOutputChannel().setChannel(
channel);
}
}
viewer.setSelection(null);
}
};
viewer.setCellModifier(cellModifier);
viewer.setContentProvider(new ChannelTableContentProvider());
viewer.setLabelProvider(new ChannelTableLabelProvider());
// Input aufbereiten
_inputChannelTableModel = createChannelTableModel(_dynamicsDescriptor);
viewer.setInput(_inputChannelTableModel);
createPopupMenu(viewer.getControl());
return viewer;
}
/**
* Creates the widgets to display the alias informations.
*
* @param parent
* The parent for the widgets
*/
private void createAliasInformation(final Composite parent) {
final Composite c = new Composite(parent, SWT.NONE);
c.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
c.setLayout(new GridLayout(2, false));
final Label header = new Label(c, SWT.NONE);
final GridData gd = GridDataFactory.fillDefaults().grab(true, true).create();
gd.horizontalSpan = 2;
header.setLayoutData(gd);
header.setFont(CustomMediaFactory.getInstance()
.getDefaultFont(SWT.BOLD));
header.setText("Available Aliases / Macros");
for (final String alias : _aliases.keySet()) {
final Label left = new Label(c, SWT.NONE);
left.setLayoutData(GridDataFactory.fillDefaults().create());
left.setForeground(CustomMediaFactory.getInstance().getColor(
new RGB(0, 0, 255)));
left.setText("$" + alias + "$");
final Label right = new Label(c, SWT.NONE);
right.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
right.setText("--> " + _aliases.get(alias));
}
}
/**
* Creates the popup menu.
*
* @param control
* The parent control for the menu
* @return The {@link Menu}
*/
private Menu createPopupMenu(final Control control) {
final MenuManager popupMenu = new MenuManager();
// channel actions
IAction a = new AddInputChannelAction();
popupMenu.add(a);
a = new AddOutputChannelAction();
popupMenu.add(a);
a = new RemoveChannelAction();
popupMenu.add(a);
// "get as [TYPE]" actions
final MenuManager subMenu = new MenuManager("Get As");
popupMenu.add(subMenu);
for (final DalPropertyTypes type : DalPropertyTypes.values()) {
a = new AppendTypeHintAction(type);
subMenu.add(a);
}
final Menu menu = popupMenu.createContextMenu(control);
control.setMenu(menu);
return menu;
}
/**
* Creates the model for the channel table.
*
* @param dynamicsDescriptor
* The {@link DynamicsDescriptor}
* @return the created {@link InputChannelTableModel}
*/
private static InputChannelTableModel createChannelTableModel(
final DynamicsDescriptor dynamicsDescriptor) {
final InputChannelTableModel model = new InputChannelTableModel();
// input channels
for (final ParameterDescriptor descriptor : dynamicsDescriptor
.getInputChannels()) {
final String inputChannel = new String(descriptor.getChannel());
model.addRowForInputChannel(new InputChannelTableRow(
ParameterType.IN, "", inputChannel));
}
// output channel
if (dynamicsDescriptor.getOutputChannel() != null) {
final String outputChannel = new String(dynamicsDescriptor
.getOutputChannel().getChannel());
if (outputChannel != null && outputChannel.length() > 0) {
model.addRowForOutputChannel(new InputChannelTableRow(
ParameterType.OUT, "Output Channel", outputChannel));
}
}
return model;
}
/**
* Updates the model.
*/
private void updateChannelTableModel() {
if (_selectedRule != null) {
_inputChannelTableModel.clearInputChannelDescriptions();
for (int i = 0; i < _selectedRule.getParameterDescriptions().length; i++) {
_inputChannelTableModel.setInputChannelDescription(i,
_selectedRule.getParameterDescriptions()[i]);
if (_selectedRule.getRuleId().equals(
_dynamicsDescriptor.getRuleId())
&& _dynamicsDescriptor.getInputChannels().length > i) {
_inputChannelTableModel.setInputChannelValue(i,
_dynamicsDescriptor.getInputChannels()[i]
.getValue());
} else {
_inputChannelTableModel.setInputChannelValue(i, "");
}
}
_channelTableViewer.refresh();
}
}
/**
* Creates a table viewer for managing channels.
*
* @param parent
* The parent composite.
*
* @return The created viewer.
*/
private TableViewer createChannelTable(final Composite parent) {
// define column names
final String[] columnNames = new String[] {
"PROP_DESCRIPTION", "PROP_NAME", "PROP_VALUE" }; //$NON-NLS-1$ //$NON-NLS-2$
// create table
final Table table = new Table(parent, SWT.FULL_SELECTION
| SWT.HIDE_SELECTION | SWT.DOUBLE_BUFFERED | SWT.SCROLL_PAGE);
table.setLinesVisible(true);
table.setLayoutData(LayoutUtil.createGridDataForFillingCell());
table.setHeaderVisible(true);
// create viewer
final TableViewer viewer = new TableViewer(table);
TableViewerColumn tvColumn;
tvColumn = new TableViewerColumn(viewer, SWT.NONE);
tvColumn.getColumn().setText("Description");
tvColumn.getColumn().setMoveable(false);
tvColumn.getColumn().setWidth(200);
tvColumn = new TableViewerColumn(viewer, SWT.NONE);
tvColumn.getColumn().setText("Channel");
tvColumn.getColumn().setMoveable(false);
tvColumn.getColumn().setWidth(300);
EditingSupport editingSupport = new CustomEditingSupport(viewer, table,
true);
tvColumn.setEditingSupport(editingSupport);
tvColumn = new TableViewerColumn(viewer, SWT.NONE);
tvColumn.getColumn().setText("Default Value");
tvColumn.getColumn().setMoveable(false);
tvColumn.getColumn().setWidth(200);
editingSupport = new CustomEditingSupport(viewer, table, false);
tvColumn.setEditingSupport(editingSupport);
viewer.setUseHashlookup(true);
// define column properties
viewer.setColumnProperties(columnNames);
// configure keyboard support
final TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(
viewer, new FocusCellOwnerDrawHighlighter(viewer));
final ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(
viewer) {
@Override
protected boolean isEditorActivationEvent(
final ColumnViewerEditorActivationEvent event) {
return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
|| event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
|| event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.F2
|| event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
}
};
TableViewerEditor.create(viewer, focusCellManager, actSupport,
ColumnViewerEditor.TABBING_HORIZONTAL
| ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
| ColumnViewerEditor.TABBING_VERTICAL
| ColumnViewerEditor.KEYBOARD_ACTIVATION);
// DnD
ProcessVariableExchangeUtil.addProcessVariableAddressDropSupport(viewer
.getControl(), DND.DROP_MOVE | DND.DROP_COPY,
new IProcessVariableAdressReceiver() {
@Override
public void receive(final IProcessVariableAddress[] pvs,
final DropTargetEvent event) {
for (final IProcessVariableAddress pv : pvs) {
addInputChannel(pv.getFullName());
}
}
}, new IShowControlSystemDialogStrategy() {
@Override
public boolean showControlSystem(final String rawName) {
// only popup the dialog if there are no aliases used
// within the raw string
final boolean show = ChannelReferenceValidationUtil
.getRequiredAliasNames(rawName).isEmpty();
return show;
}
});
ProcessVariableExchangeUtil.addProcessVariableAdressDragSupport(viewer
.getControl(), DND.DROP_MOVE | DND.DROP_COPY,
new IProcessVariableAdressProvider() {
@Override
public List<IProcessVariableAddress> getProcessVariableAdresses() {
final List<ParameterDescriptor> parameterDescriptors = SelectionUtil
.getInstance().getObjectsFromSelection(
viewer.getSelection());
final List<IProcessVariableAddress> result = new ArrayList<IProcessVariableAddress>();
for (final ParameterDescriptor d : parameterDescriptors) {
final IProcessVariableAddress pv = ProcessVariableAdressFactory
.getInstance().createProcessVariableAdress(
d.getChannel());
result.add(pv);
}
return result;
}
@Override
public IProcessVariableAddress getPVAdress() {
final List<IProcessVariableAddress> all = getProcessVariableAdresses();
if (all.size() > 0) {
return all.get(0);
}
return null;
}
});
return viewer;
}
/**
* Add a output channel.
*
* @param channelName
* The output channel name.
*/
private void addOutputChannel(final String channelName) {
final ParameterDescriptor descriptor = new ParameterDescriptor();
descriptor.setChannel(channelName);
_dynamicsDescriptor.setOutputChannel(descriptor);
final InputChannelTableRow row = new InputChannelTableRow(ParameterType.OUT,
"OUT", channelName);
_inputChannelTableModel.addRowForOutputChannel(row);
_channelTableViewer.refresh();
_outputChannelTableViewer.refresh();
}
/**
* Add a input channel.
*
* @param channelName
* The input channel name.
*/
private void addInputChannel(final String channelName) {
final IProcessVariableAddress pv = ProcessVariableAdressFactory.getInstance()
.createProcessVariableAdress(channelName);
final InputChannelTableRow row = new InputChannelTableRow(ParameterType.IN,
"", pv.getFullName());
_inputChannelTableModel.addRowForInputChannel(row);
_channelTableViewer.refresh();
}
/**
* Finishes the editing.
*
* @param dynamicsDescriptor
* The {@link DynamicsDescriptor}
*/
public void performFinish(final DynamicsDescriptor dynamicsDescriptor) {
// setup rule
if (_selectedRule != null) {
dynamicsDescriptor.setRuleId(_selectedRule.getRuleId());
}
final boolean selection = _useOnlyConnectionsCheckBox.getSelection();
dynamicsDescriptor.setUsingOnlyConnectionStates(selection);
// setup IN channels
for (final InputChannelTableRow row : _inputChannelTableModel
.getRowsWithContent(ParameterType.IN)) {
dynamicsDescriptor.addInputChannel(new ParameterDescriptor(row
.getChannel(), row.getDefaultValue()));
}
// setup OUT channels
final List<InputChannelTableRow> outParameter = _inputChannelTableModel
.getRowsWithContent(ParameterType.OUT);
if (outParameter.size() > 0) {
final InputChannelTableRow row = outParameter.get(0);
dynamicsDescriptor.setOutputChannel(new ParameterDescriptor(row
.getChannel(), row.getDefaultValue()));
}
}
}