X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2FcomponentTypeEditor%2FComponentTypeViewerData.java;h=e1f17996505f6d34ec2131f489f97552f0743327;hp=6a3e7f1482e81a54166eda050ea3f9438bfa2bae;hb=6bf51de1941aa1dc5ee0a3aa8c50d53168b0c068;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/ComponentTypeViewerData.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/ComponentTypeViewerData.java index 6a3e7f148..e1f179965 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/ComponentTypeViewerData.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/ComponentTypeViewerData.java @@ -1,564 +1,593 @@ -package org.simantics.modeling.ui.componentTypeEditor; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.layout.GridLayoutFactory; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.custom.TableEditor; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.Form; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.simantics.Simantics; -import org.simantics.databoard.type.NumberType; -import org.simantics.databoard.units.internal.library.UnitLibrary; -import org.simantics.databoard.util.Limit; -import org.simantics.databoard.util.Range; -import org.simantics.databoard.util.RangeException; -import org.simantics.db.RequestProcessor; -import org.simantics.db.Resource; -import org.simantics.db.WriteGraph; -import org.simantics.db.common.NamedResource; -import org.simantics.db.common.request.WriteRequest; -import org.simantics.db.exception.DatabaseException; -import org.simantics.layer0.Layer0; -import org.simantics.modeling.userComponent.ComponentTypeCommands; -import org.simantics.scl.runtime.function.Function4; -import org.simantics.utils.ui.ErrorLogger; - -public class ComponentTypeViewerData { - /** - * Used to validate property names. - */ - public static final Pattern PROPERTY_NAME_PATTERN = - Pattern.compile("([a-z]|_[0-9a-zA-Z_])[0-9a-zA-Z_]*"); - - public static final String[] PROPERTY_TYPE_SUGGESTIONS = new String[] { - "Double", - "Integer", - "Float", - "String", - "Boolean", - "Long", - "[Double]", - "[Integer]", - "[Float]", - "[String]", - "[Boolean]", - "[Long]", - "Vector Double", - "Vector Integer", - "Vector Float", - "Vector String", - "Vector Boolean", - "Vector Long" - }; - - public Resource componentType; - public FormToolkit tk; - public Form form; - public UnitLibrary unitLibrary = UnitLibrary.createDefault(); - public boolean readOnly; - public NamedResource[] connectionPoints; - public ComponentTypeViewerPropertyInfo[] properties; - - public ComponentTypeViewerData(FormToolkit tk, Resource componentType, Form form) { - this.tk = tk; - this.componentType = componentType; - this.form = form; - } - - public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, - Pattern namePattern) { - int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; - final Text text = new Text(table, SWT.NONE | extraStyle); - org.eclipse.swt.widgets.Listener listener = - new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event e) { - if (e.type == SWT.Dispose) { - form.setMessage(null); - return; - } - - if (e.type == SWT.Modify) { - // validate current name - String error = validatePropertyName(propertyInfo, text.getText(), namePattern); - if (error != null) { - text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED)); - form.setMessage(error, IMessageProvider.ERROR); - } else { - text.setBackground(null); - form.setMessage(null); - } - return; - } - - if (e.type == SWT.Traverse) { - if (e.detail == SWT.TRAVERSE_ESCAPE) { - text.dispose(); - e.doit = false; - return; - } - if (e.detail == SWT.TRAVERSE_ARROW_NEXT || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS || e.detail == SWT.TRAVERSE_MNEMONIC) - return; - e.doit = false; - } - final String newValue = text.getText(); - text.dispose(); - - String error = validatePropertyName(propertyInfo, newValue, namePattern); - if (error != null) - return; - - if (propertyInfo.immutable) - return; - - Simantics.getSession().async(new WriteRequest() { - @Override - public void perform(WriteGraph graph) - throws DatabaseException { - graph.markUndoPoint(); - Layer0 L0 = Layer0.getInstance(graph); - String prevName = graph.getPossibleRelatedValue2(propertyInfo.resource, L0.HasName); - String oldCamelCasedLabel = prevName != null ? ComponentTypeCommands.camelCaseNameToLabel(prevName) : ""; - String oldLabel = graph.getPossibleRelatedValue(propertyInfo.resource, L0.HasLabel); - boolean setLabel = oldLabel == null - || oldLabel.isEmpty() - || oldCamelCasedLabel.isEmpty() - || oldCamelCasedLabel.equals(oldLabel); - - ComponentTypeCommands.rename(graph, propertyInfo.resource, newValue); - if (setLabel) - ComponentTypeCommands.setLabel(graph, propertyInfo.resource, ComponentTypeCommands.camelCaseNameToLabel(newValue)); - } - }); - } - }; - text.addListener(SWT.Modify, listener); - text.addListener(SWT.Deactivate, listener); - text.addListener(SWT.Traverse, listener); - text.addListener(SWT.Dispose, listener); - - text.setText(selectedItem.getText(column)); - text.selectAll(); - text.setFocus(); - - editor.setEditor(text, selectedItem, column); - } - - public void editType(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, final boolean convertDefaultValue) { - int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; - final Combo combo = new Combo(table, SWT.NONE | extraStyle); - combo.setText(selectedItem.getText(column)); - for(String suggestion : PROPERTY_TYPE_SUGGESTIONS) - combo.add(suggestion); - org.eclipse.swt.widgets.Listener listener = - new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event e) { - if(e.type == SWT.Traverse) { - if (e.detail == SWT.TRAVERSE_ESCAPE) { - combo.dispose(); - e.doit = false; - return; - } - if (e.detail == SWT.TRAVERSE_ARROW_NEXT - || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS - || e.detail == SWT.TRAVERSE_MNEMONIC) - return; - } - final String newValue = combo.getText(); - if (e.type == SWT.Traverse) { - e.doit = false; - } - combo.dispose(); - - if (propertyInfo.immutable) - return; - - Simantics.getSession().async(new WriteRequest() { - @Override - public void perform(WriteGraph graph) - throws DatabaseException { - graph.markUndoPoint(); - ComponentTypeCommands.editType(graph, componentType, propertyInfo.resource, convertDefaultValue, newValue); - } - }); - } - }; - combo.setFocus(); - editor.setEditor(combo, selectedItem, column); - combo.addListener(SWT.FocusOut, listener); - combo.addListener(SWT.Traverse, listener); - } - - protected void editUnit(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column) { - // Disallow unit editing for non-numeric configuration properties - if (propertyInfo.numberType == null && propertyInfo.sectionSpecificData == null) - return; - - int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; - final Combo combo = new Combo(table, SWT.NONE | extraStyle); - String initialValue = selectedItem.getText(column); - List units = new ArrayList<>( unitLibrary.getUnits() ); - Collections.sort(units, String.CASE_INSENSITIVE_ORDER); - int i = -1; - int selected = -1; - for (String unit : units) { - combo.add(unit); - if (unit.equals(initialValue)) - combo.select(i); - } - if (selected == -1) - combo.setText(initialValue); - - org.eclipse.swt.widgets.Listener listener = - new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event e) { - if(e.type == SWT.Traverse) { - if (e.detail == SWT.TRAVERSE_ESCAPE) { - combo.dispose(); - e.doit = false; - return; - } - if (e.detail == SWT.TRAVERSE_ARROW_NEXT - || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS - || e.detail == SWT.TRAVERSE_MNEMONIC) - return; - } - final String newValue = combo.getText(); - if(e.type == SWT.Traverse) { - e.doit = false; - } - combo.dispose(); - - if (propertyInfo.immutable) - return; - - Simantics.getSession().async(new WriteRequest() { - @Override - public void perform(WriteGraph graph) - throws DatabaseException { - graph.markUndoPoint(); - ComponentTypeCommands.setUnit(graph, componentType, propertyInfo.resource, newValue); - } - }); - } - }; - combo.setFocus(); - editor.setEditor(combo, selectedItem, column); - combo.addListener(SWT.Deactivate, listener); - combo.addListener(SWT.Traverse, listener); - } - - public void editValue(Table table, TableEditor editor, - final ComponentTypeViewerPropertyInfo propertyInfo, - TableItem selectedItem, int column, - final StringWriter writer, - final Function4 validator) - { - int extraStyle = writer == null ? SWT.READ_ONLY : 0; - final Text text = new Text(table, SWT.NONE | extraStyle); - text.setText(selectedItem.getText(column)); - org.eclipse.swt.widgets.Listener listener = - new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event e) { - if(e.type == SWT.Traverse) { - if (e.detail == SWT.TRAVERSE_ESCAPE) { - text.dispose(); - e.doit = false; - return; - } - if (e.detail == SWT.TRAVERSE_ARROW_NEXT - || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS - || e.detail == SWT.TRAVERSE_MNEMONIC) - return; - } - final String newValue = text.getText(); - if(e.type == SWT.Traverse) { - e.doit = false; - } - text.dispose(); - - if (writer != null) { - Simantics.getSession().async(new WriteRequest() { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - writer.perform(graph, newValue); - } - }); - } - } - }; - text.selectAll(); - text.setFocus(); - editor.setEditor(text, selectedItem, column); - text.addListener(SWT.FocusOut, listener); - text.addListener(SWT.Traverse, listener); - - if (validator != null) { - org.eclipse.swt.widgets.Listener validationListener = new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event e) { - final String newValue = text.getText(); - String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue); - if (error != null) { - text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED)); - text.setToolTipText(error); - return; - } else { - text.setBackground(null); - text.setToolTipText(null); - } - } - }; - text.addListener(SWT.Modify, validationListener); - } - } - - private Range parseRange(NumberType numberType, String minStr, String maxStr, boolean lowInclusive, boolean highInclusive) throws RangeException { - try { - String rangeStr = (lowInclusive ? "[" : "(") + minStr + ".." + maxStr + (highInclusive ? "]" : ")"); - return Range.valueOf(rangeStr); - } catch (IllegalArgumentException e) { - // Limits are invalid - throw new RangeException(e.getMessage(), e); - } - } - - private static Combo createRangeInclusionCombo(Composite parent, boolean inclusive) { - Combo rng = new Combo(parent, SWT.READ_ONLY); - rng.add("Inclusive"); - rng.add("Exclusive"); - rng.select(inclusive ? 0 : 1); - return rng; - } - - protected void editRange(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, Rectangle selectedItemBounds, int column) { - // Disallow range editing when the property is not numeric - if (propertyInfo.numberType == null) - return; - - int extraTextStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; - - // Parse initial range value - Range range = null; - String rangeStr = selectedItem.getText(column); - try { - range = Range.valueOf(rangeStr); - } catch (RangeException ex) { - range = new Range(Limit.nolimit(), Limit.nolimit()); - } - - final Shell shell = new Shell(table.getShell(), SWT.ON_TOP); - GridLayoutFactory.fillDefaults().applyTo(shell); - - Composite composite = new Composite(shell, SWT.NONE); - GridDataFactory.fillDefaults().grab(true, true).applyTo(composite); - GridLayoutFactory.swtDefaults().numColumns(3).applyTo(composite); - - Label low = new Label(composite, SWT.NONE); - low.setText("Minimum Value:"); - final Text lowText = new Text(composite, SWT.BORDER | extraTextStyle); - GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(lowText); - final Combo lowSelector = createRangeInclusionCombo(composite, !range.getLower().isExclusive()); - Label high = new Label(composite, SWT.NONE); - high.setText("Maximum Value:"); - final Text highText = new Text(composite, SWT.BORDER | extraTextStyle); - GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(highText); - final Combo highSelector = createRangeInclusionCombo(composite, !range.getUpper().isExclusive()); - - Composite buttonComposite = new Composite(shell, SWT.NONE); - GridDataFactory.fillDefaults().grab(true, false).align(SWT.TRAIL, SWT.FILL).applyTo(buttonComposite); - GridLayoutFactory.swtDefaults().numColumns(2).equalWidth(true).applyTo(buttonComposite); - - Button ok = new Button(buttonComposite, SWT.NONE); - ok.setText("&OK"); - GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(ok); - Button cancel = new Button(buttonComposite, SWT.NONE); - cancel.setText("&Cancel"); - GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(ok); - - if (range.getLower().getValue() != null) - lowText.setText(range.getLower().getValue().toString()); - if (range.getUpper().getValue() != null) - highText.setText(range.getUpper().getValue().toString()); - - shell.addListener(SWT.Deactivate, new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event event) { - shell.dispose(); - } - }); - - ok.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent e) { - try { - final Range newRange = parseRange(propertyInfo.numberType, - lowText.getText().trim(), - highText.getText().trim(), - lowSelector.getSelectionIndex() == 0 ? true : false, - highSelector.getSelectionIndex() == 0 ? true : false); - - shell.dispose(); - - if (propertyInfo.immutable) - return; - - Simantics.getSession().async(new WriteRequest() { - @Override - public void perform(WriteGraph graph) - throws DatabaseException { - graph.markUndoPoint(); - ComponentTypeCommands.setRange(graph, componentType, propertyInfo.resource, newRange == null ? null : newRange.toString()); - } - }); - } catch (RangeException ex) { - ErrorLogger.defaultLogError(ex); - } - } - }); - cancel.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent e) { - shell.dispose(); - } - }); - - shell.pack(); - Point size = shell.getSize(); - - Display display = table.getDisplay(); - Rectangle clientArea = display.getClientArea(); - Point bt = table.toDisplay(selectedItemBounds.x, selectedItemBounds.y); - Rectangle b = selectedItemBounds; - b.x = bt.x; - b.y = bt.y; - b.width = size.x; - b.height = size.y; - if ((b.x + b.width) > clientArea.width) - b.x -= b.x + b.width - clientArea.width; - if (b.height > clientArea.height) - b.height = clientArea.height; - if ((b.y + b.height) > clientArea.height) - b.y -= b.y + b.height - clientArea.height; - - shell.setBounds(selectedItemBounds); - shell.open(); - } - - protected void editMultilineText(Table table, TableEditor editor, - final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, - Rectangle selectedItemBounds, int column, final StringWriter writer) - { - final Shell shell = new Shell(table.getShell(), SWT.ON_TOP); - GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(shell); - final StyledText text = new StyledText(shell, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | (propertyInfo.immutable ? SWT.READ_ONLY : 0)); - GridDataFactory.fillDefaults().grab(true, true).applyTo(text); - text.setText(selectedItem.getText(column)); - org.eclipse.swt.widgets.Listener listener = - new org.eclipse.swt.widgets.Listener() { - @Override - public void handleEvent(Event e) { - final String newValue = text.getText(); - - if (e.type == SWT.Traverse) { - if (e.detail == SWT.TRAVERSE_ESCAPE) { - shell.dispose(); - e.doit = false; - return; - } - if (e.detail == SWT.TRAVERSE_ARROW_NEXT - || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS - || e.detail == SWT.TRAVERSE_MNEMONIC) - return; - if ((e.stateMask & SWT.CTRL) == 0) - return; - e.doit = false; - } - - shell.dispose(); - - if (propertyInfo.immutable) - return; - - if (writer != null) { - Simantics.getSession().async(new WriteRequest() { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - writer.perform(graph, newValue); - } - }); - } - } - }; - - String helpText = propertyInfo.immutable ? "ESC to close." : "Ctrl+Enter to apply changes, ESC to cancel."; - Label help = tk.createLabel(shell, helpText, SWT.BORDER | SWT.FLAT); - GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(help); - help.setForeground( tk.getColors().createColor( "fg", tk.getColors().getSystemColor(SWT.COLOR_LIST_SELECTION) ) ); - - Display display = table.getDisplay(); - Rectangle clientArea = display.getClientArea(); - Point bt = table.toDisplay(selectedItemBounds.x, selectedItemBounds.y); - Rectangle b = selectedItemBounds; - b.x = bt.x; - b.y = bt.y; - b.height = 200; - if ((b.x + b.width) > clientArea.width) - b.x -= b.x + b.width - clientArea.width; - if (b.height > clientArea.height) - b.height = clientArea.height; - if ((b.y + b.height) > clientArea.height) - b.y -= b.y + b.height - clientArea.height; - - shell.setBounds(selectedItemBounds); - shell.open(); - - text.selectAll(); - text.setFocus(); - - text.addListener(SWT.Traverse, listener); - shell.addListener(SWT.Deactivate, listener); - } - - private String validatePropertyName(ComponentTypeViewerPropertyInfo propertyInfo, String propertyName, Pattern namePattern) { - if (propertyName.equals(propertyInfo.name)) - return null; - for (ComponentTypeViewerPropertyInfo info : properties) { - if (propertyName.equals(info.name)) - return "Property name '" + propertyName + "' is already in use."; - } - for (NamedResource cp : connectionPoints) { - if (propertyName.equals(cp.getName())) - return "Name '" + propertyName + "' is already used for a terminal."; - } - Matcher m = namePattern.matcher(propertyName); - if (!m.matches()) - return "Property name '" + propertyName + "' contains invalid characters, does not match pattern " - + namePattern.pattern() + "."; - return null; - } - -} +package org.simantics.modeling.ui.componentTypeEditor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.simantics.Simantics; +import org.simantics.databoard.type.NumberType; +import org.simantics.databoard.units.internal.library.UnitLibrary; +import org.simantics.databoard.util.Limit; +import org.simantics.databoard.util.Range; +import org.simantics.databoard.util.RangeException; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.NamedResource; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.function.DbConsumer; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.userComponent.ComponentTypeCommands; +import org.simantics.scl.runtime.function.Function2; +import org.simantics.scl.runtime.function.Function4; +import org.simantics.utils.ui.ErrorLogger; + +public class ComponentTypeViewerData { + /** + * Used to validate property names. + */ + public static final Pattern PROPERTY_NAME_PATTERN = + Pattern.compile("([a-z]|_[0-9a-zA-Z_])[0-9a-zA-Z_]*"); + + public static final String[] PROPERTY_TYPE_SUGGESTIONS = new String[] { + "Double", + "Integer", + "Float", + "String", + "Boolean", + "Long", + "[Double]", + "[Integer]", + "[Float]", + "[String]", + "[Boolean]", + "[Long]", + "Vector Double", + "Vector Integer", + "Vector Float", + "Vector String", + "Vector Boolean", + "Vector Long" + }; + + public Resource componentType; + public FormToolkit tk; + public Form form; + public UnitLibrary unitLibrary = UnitLibrary.createDefault(); + public boolean readOnly; + public NamedResource[] connectionPoints; + public ComponentTypeViewerPropertyInfo[] properties; + + public ComponentTypeViewerData(FormToolkit tk, Resource componentType, Form form) { + this.tk = tk; + this.componentType = componentType; + this.form = form; + } + + public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, + Pattern namePattern) { + editName(table, editor, propertyInfo, selectedItem, column, namePattern, null); + } + + public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, + Pattern namePattern, DbConsumer extraWriter) { + editName(table, editor, propertyInfo, selectedItem, column, + (pInfo, name) -> validatePropertyName(pInfo, name, namePattern), + extraWriter); + } + + public void editName(Table table, TableEditor editor, ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, + Function2 nameValidator) + { + editName(table, editor, propertyInfo, selectedItem, column, nameValidator, null); + } + + public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, + Function2 nameValidator, DbConsumer extraWriter) { + int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; + final Text text = new Text(table, SWT.NONE | extraStyle); + org.eclipse.swt.widgets.Listener listener = + new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event e) { + if (e.type == SWT.Dispose) { + form.setMessage(null); + return; + } + + if (e.type == SWT.Modify) { + // validate current name + String error = nameValidator.apply(propertyInfo, text.getText()); + if (error != null) { + text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED)); + form.setMessage(error, IMessageProvider.ERROR); + } else { + text.setBackground(null); + form.setMessage(null); + } + return; + } + + if (e.type == SWT.Traverse) { + if (e.detail == SWT.TRAVERSE_ESCAPE) { + text.dispose(); + e.doit = false; + return; + } + if (e.detail == SWT.TRAVERSE_ARROW_NEXT || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS || e.detail == SWT.TRAVERSE_MNEMONIC) + return; + e.doit = false; + } + final String newValue = text.getText(); + text.dispose(); + + String error = nameValidator.apply(propertyInfo, newValue); + if (error != null) + return; + + if (propertyInfo.immutable) + return; + + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) + throws DatabaseException { + graph.markUndoPoint(); + Layer0 L0 = Layer0.getInstance(graph); + String prevName = graph.getPossibleRelatedValue2(propertyInfo.resource, L0.HasName); + String oldCamelCasedLabel = prevName != null ? ComponentTypeCommands.camelCaseNameToLabel(prevName) : ""; + String oldLabel = graph.getPossibleRelatedValue(propertyInfo.resource, L0.HasLabel); + boolean setLabel = oldLabel == null + || oldLabel.isEmpty() + || oldCamelCasedLabel.isEmpty() + || oldCamelCasedLabel.equals(oldLabel); + + ComponentTypeCommands.rename(graph, propertyInfo.resource, newValue); + if (setLabel) + ComponentTypeCommands.setLabel(graph, propertyInfo.resource, ComponentTypeCommands.camelCaseNameToLabel(newValue)); + + if (extraWriter != null) + extraWriter.accept(graph); + } + }); + } + }; + text.addListener(SWT.Modify, listener); + text.addListener(SWT.Deactivate, listener); + text.addListener(SWT.Traverse, listener); + text.addListener(SWT.Dispose, listener); + + text.setText(selectedItem.getText(column)); + text.selectAll(); + text.setFocus(); + + editor.setEditor(text, selectedItem, column); + } + + public void editType(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, final boolean convertDefaultValue) { + int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; + final Combo combo = new Combo(table, SWT.NONE | extraStyle); + combo.setText(selectedItem.getText(column)); + for(String suggestion : PROPERTY_TYPE_SUGGESTIONS) + combo.add(suggestion); + org.eclipse.swt.widgets.Listener listener = + new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event e) { + if(e.type == SWT.Traverse) { + if (e.detail == SWT.TRAVERSE_ESCAPE) { + combo.dispose(); + e.doit = false; + return; + } + if (e.detail == SWT.TRAVERSE_ARROW_NEXT + || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS + || e.detail == SWT.TRAVERSE_MNEMONIC) + return; + } + final String newValue = combo.getText(); + if (e.type == SWT.Traverse) { + e.doit = false; + } + combo.dispose(); + + if (propertyInfo.immutable) + return; + + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) + throws DatabaseException { + graph.markUndoPoint(); + ComponentTypeCommands.editType(graph, componentType, propertyInfo.resource, convertDefaultValue, newValue); + } + }); + } + }; + combo.setFocus(); + editor.setEditor(combo, selectedItem, column); + combo.addListener(SWT.FocusOut, listener); + combo.addListener(SWT.Traverse, listener); + } + + protected void editUnit(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column) { + // Disallow unit editing for non-numeric configuration properties + if (propertyInfo.numberType == null && propertyInfo.sectionSpecificData == null) + return; + + int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; + final Combo combo = new Combo(table, SWT.NONE | extraStyle); + String initialValue = selectedItem.getText(column); + List units = new ArrayList<>( unitLibrary.getUnits() ); + Collections.sort(units, String.CASE_INSENSITIVE_ORDER); + int i = -1; + int selected = -1; + for (String unit : units) { + combo.add(unit); + if (unit.equals(initialValue)) + combo.select(i); + } + if (selected == -1) + combo.setText(initialValue); + + org.eclipse.swt.widgets.Listener listener = + new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event e) { + if(e.type == SWT.Traverse) { + if (e.detail == SWT.TRAVERSE_ESCAPE) { + combo.dispose(); + e.doit = false; + return; + } + if (e.detail == SWT.TRAVERSE_ARROW_NEXT + || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS + || e.detail == SWT.TRAVERSE_MNEMONIC) + return; + } + final String newValue = combo.getText(); + if(e.type == SWT.Traverse) { + e.doit = false; + } + combo.dispose(); + + if (propertyInfo.immutable) + return; + + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) + throws DatabaseException { + graph.markUndoPoint(); + ComponentTypeCommands.setUnit(graph, componentType, propertyInfo.resource, newValue); + } + }); + } + }; + combo.setFocus(); + editor.setEditor(combo, selectedItem, column); + combo.addListener(SWT.Deactivate, listener); + combo.addListener(SWT.Traverse, listener); + } + + public void editValue(Table table, TableEditor editor, + final ComponentTypeViewerPropertyInfo propertyInfo, + TableItem selectedItem, int column, + final StringWriter writer, + final Function4 validator) + { + int extraStyle = writer == null ? SWT.READ_ONLY : 0; + final Text text = new Text(table, SWT.NONE | extraStyle); + text.setText(selectedItem.getText(column)); + org.eclipse.swt.widgets.Listener listener = + new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event e) { + if(e.type == SWT.Traverse) { + if (e.detail == SWT.TRAVERSE_ESCAPE) { + text.dispose(); + e.doit = false; + return; + } + if (e.detail == SWT.TRAVERSE_ARROW_NEXT + || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS + || e.detail == SWT.TRAVERSE_MNEMONIC) + return; + } + final String newValue = text.getText(); + if(e.type == SWT.Traverse) { + e.doit = false; + } + text.dispose(); + + if (validator != null) { + String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue); + if (error != null) + return; + } + + if (writer != null) { + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + writer.perform(graph, newValue); + } + }); + } + } + }; + text.selectAll(); + text.setFocus(); + editor.setEditor(text, selectedItem, column); + text.addListener(SWT.FocusOut, listener); + text.addListener(SWT.Traverse, listener); + + if (validator != null) { + org.eclipse.swt.widgets.Listener validationListener = new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event e) { + final String newValue = text.getText(); + String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue); + if (error != null) { + text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED)); + text.setToolTipText(error); + return; + } else { + text.setBackground(null); + text.setToolTipText(null); + } + } + }; + text.addListener(SWT.Modify, validationListener); + } + } + + private Range parseRange(NumberType numberType, String minStr, String maxStr, boolean lowInclusive, boolean highInclusive) throws RangeException { + try { + String rangeStr = (lowInclusive ? "[" : "(") + minStr + ".." + maxStr + (highInclusive ? "]" : ")"); + return Range.valueOf(rangeStr); + } catch (IllegalArgumentException e) { + // Limits are invalid + throw new RangeException(e.getMessage(), e); + } + } + + private static Combo createRangeInclusionCombo(Composite parent, boolean inclusive) { + Combo rng = new Combo(parent, SWT.READ_ONLY); + rng.add("Inclusive"); + rng.add("Exclusive"); + rng.select(inclusive ? 0 : 1); + return rng; + } + + protected void editRange(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, Rectangle selectedItemBounds, int column) { + // Disallow range editing when the property is not numeric + if (propertyInfo.numberType == null) + return; + + int extraTextStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0; + + // Parse initial range value + Range range = null; + String rangeStr = selectedItem.getText(column); + try { + range = Range.valueOf(rangeStr); + } catch (RangeException ex) { + range = new Range(Limit.nolimit(), Limit.nolimit()); + } + + final Shell shell = new Shell(table.getShell(), SWT.ON_TOP); + GridLayoutFactory.fillDefaults().applyTo(shell); + + Composite composite = new Composite(shell, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(composite); + GridLayoutFactory.swtDefaults().numColumns(3).applyTo(composite); + + Label low = new Label(composite, SWT.NONE); + low.setText("Minimum Value:"); + final Text lowText = new Text(composite, SWT.BORDER | extraTextStyle); + GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(lowText); + final Combo lowSelector = createRangeInclusionCombo(composite, !range.getLower().isExclusive()); + Label high = new Label(composite, SWT.NONE); + high.setText("Maximum Value:"); + final Text highText = new Text(composite, SWT.BORDER | extraTextStyle); + GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(highText); + final Combo highSelector = createRangeInclusionCombo(composite, !range.getUpper().isExclusive()); + + Composite buttonComposite = new Composite(shell, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).align(SWT.TRAIL, SWT.FILL).applyTo(buttonComposite); + GridLayoutFactory.swtDefaults().numColumns(2).equalWidth(true).applyTo(buttonComposite); + + Button ok = new Button(buttonComposite, SWT.NONE); + ok.setText("&OK"); + GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(ok); + Button cancel = new Button(buttonComposite, SWT.NONE); + cancel.setText("&Cancel"); + GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(ok); + + if (range.getLower().getValue() != null) + lowText.setText(range.getLower().getValue().toString()); + if (range.getUpper().getValue() != null) + highText.setText(range.getUpper().getValue().toString()); + + shell.addListener(SWT.Deactivate, new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event event) { + shell.dispose(); + } + }); + + ok.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + try { + final Range newRange = parseRange(propertyInfo.numberType, + lowText.getText().trim(), + highText.getText().trim(), + lowSelector.getSelectionIndex() == 0 ? true : false, + highSelector.getSelectionIndex() == 0 ? true : false); + + shell.dispose(); + + if (propertyInfo.immutable) + return; + + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) + throws DatabaseException { + graph.markUndoPoint(); + ComponentTypeCommands.setRange(graph, componentType, propertyInfo.resource, newRange == null ? null : newRange.toString()); + } + }); + } catch (RangeException ex) { + ErrorLogger.defaultLogError(ex); + } + } + }); + cancel.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + shell.dispose(); + } + }); + + shell.pack(); + Point size = shell.getSize(); + + Display display = table.getDisplay(); + Rectangle clientArea = display.getClientArea(); + Point bt = table.toDisplay(selectedItemBounds.x, selectedItemBounds.y); + Rectangle b = selectedItemBounds; + b.x = bt.x; + b.y = bt.y; + b.width = size.x; + b.height = size.y; + if ((b.x + b.width) > clientArea.width) + b.x -= b.x + b.width - clientArea.width; + if (b.height > clientArea.height) + b.height = clientArea.height; + if ((b.y + b.height) > clientArea.height) + b.y -= b.y + b.height - clientArea.height; + + shell.setBounds(selectedItemBounds); + shell.open(); + } + + protected void editMultilineText(Table table, TableEditor editor, + final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, + Rectangle selectedItemBounds, int column, final StringWriter writer) + { + final Shell shell = new Shell(table.getShell(), SWT.ON_TOP); + GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(shell); + final StyledText text = new StyledText(shell, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | (propertyInfo.immutable ? SWT.READ_ONLY : 0)); + GridDataFactory.fillDefaults().grab(true, true).applyTo(text); + text.setText(selectedItem.getText(column)); + org.eclipse.swt.widgets.Listener listener = + new org.eclipse.swt.widgets.Listener() { + @Override + public void handleEvent(Event e) { + final String newValue = text.getText(); + + if (e.type == SWT.Traverse) { + if (e.detail == SWT.TRAVERSE_ESCAPE) { + shell.dispose(); + e.doit = false; + return; + } + if (e.detail == SWT.TRAVERSE_ARROW_NEXT + || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS + || e.detail == SWT.TRAVERSE_MNEMONIC) + return; + if ((e.stateMask & SWT.CTRL) == 0) + return; + e.doit = false; + } + + shell.dispose(); + + if (propertyInfo.immutable) + return; + + if (writer != null) { + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + writer.perform(graph, newValue); + } + }); + } + } + }; + + String helpText = propertyInfo.immutable ? "ESC to close." : "Ctrl+Enter to apply changes, ESC to cancel."; + Label help = tk.createLabel(shell, helpText, SWT.BORDER | SWT.FLAT); + GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(help); + help.setForeground( tk.getColors().createColor( "fg", tk.getColors().getSystemColor(SWT.COLOR_LIST_SELECTION) ) ); + + Display display = table.getDisplay(); + Rectangle clientArea = display.getClientArea(); + Point bt = table.toDisplay(selectedItemBounds.x, selectedItemBounds.y); + Rectangle b = selectedItemBounds; + b.x = bt.x; + b.y = bt.y; + b.height = 200; + if ((b.x + b.width) > clientArea.width) + b.x -= b.x + b.width - clientArea.width; + if (b.height > clientArea.height) + b.height = clientArea.height; + if ((b.y + b.height) > clientArea.height) + b.y -= b.y + b.height - clientArea.height; + + shell.setBounds(selectedItemBounds); + shell.open(); + + text.selectAll(); + text.setFocus(); + + text.addListener(SWT.Traverse, listener); + shell.addListener(SWT.Deactivate, listener); + } + + private String validatePropertyName(ComponentTypeViewerPropertyInfo propertyInfo, String propertyName, Pattern namePattern) { + if (propertyName.equals(propertyInfo.name)) + return null; + for (ComponentTypeViewerPropertyInfo info : properties) { + if (propertyName.equals(info.name)) + return "Property name '" + propertyName + "' is already in use."; + } + for (NamedResource cp : connectionPoints) { + if (propertyName.equals(cp.getName())) + return "Name '" + propertyName + "' is already used for a terminal."; + } + Matcher m = namePattern.matcher(propertyName); + if (!m.matches()) + return "Property name '" + propertyName + "' contains invalid characters, does not match pattern " + + namePattern.pattern() + "."; + return null; + } + +}