]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/ComponentTypeViewerData.java
Externalize strings
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / componentTypeEditor / ComponentTypeViewerData.java
1 package org.simantics.modeling.ui.componentTypeEditor;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
8
9 import org.eclipse.jface.dialogs.IDialogConstants;
10 import org.eclipse.jface.dialogs.IMessageProvider;
11 import org.eclipse.jface.layout.GridDataFactory;
12 import org.eclipse.jface.layout.GridLayoutFactory;
13 import org.eclipse.osgi.util.NLS;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.StyledText;
16 import org.eclipse.swt.custom.TableEditor;
17 import org.eclipse.swt.events.SelectionAdapter;
18 import org.eclipse.swt.events.SelectionEvent;
19 import org.eclipse.swt.graphics.Point;
20 import org.eclipse.swt.graphics.Rectangle;
21 import org.eclipse.swt.widgets.Button;
22 import org.eclipse.swt.widgets.Combo;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Display;
25 import org.eclipse.swt.widgets.Event;
26 import org.eclipse.swt.widgets.Label;
27 import org.eclipse.swt.widgets.Shell;
28 import org.eclipse.swt.widgets.Table;
29 import org.eclipse.swt.widgets.TableItem;
30 import org.eclipse.swt.widgets.Text;
31 import org.eclipse.ui.forms.widgets.Form;
32 import org.eclipse.ui.forms.widgets.FormToolkit;
33 import org.simantics.Simantics;
34 import org.simantics.databoard.type.NumberType;
35 import org.simantics.databoard.units.internal.library.UnitLibrary;
36 import org.simantics.databoard.util.Limit;
37 import org.simantics.databoard.util.Range;
38 import org.simantics.databoard.util.RangeException;
39 import org.simantics.db.RequestProcessor;
40 import org.simantics.db.Resource;
41 import org.simantics.db.WriteGraph;
42 import org.simantics.db.common.NamedResource;
43 import org.simantics.db.common.request.WriteRequest;
44 import org.simantics.db.exception.DatabaseException;
45 import org.simantics.db.function.DbConsumer;
46 import org.simantics.layer0.Layer0;
47 import org.simantics.modeling.userComponent.ComponentTypeCommands;
48 import org.simantics.scl.runtime.function.Function2;
49 import org.simantics.scl.runtime.function.Function4;
50 import org.simantics.utils.ui.ErrorLogger;
51
52 public class ComponentTypeViewerData {
53     /**
54      * Used to validate property names.
55      */
56     public static final Pattern PROPERTY_NAME_PATTERN =
57             Pattern.compile("([a-z]|_[0-9a-zA-Z_])[0-9a-zA-Z_]*"); //$NON-NLS-1$
58
59     public static final String[] PROPERTY_TYPE_SUGGESTIONS = new String[] {
60         "Double", //$NON-NLS-1$
61         "Integer", //$NON-NLS-1$
62         "Float", //$NON-NLS-1$
63         "String", //$NON-NLS-1$
64         "Boolean", //$NON-NLS-1$
65         "Long", //$NON-NLS-1$
66         "[Double]", //$NON-NLS-1$
67         "[Integer]", //$NON-NLS-1$
68         "[Float]", //$NON-NLS-1$
69         "[String]", //$NON-NLS-1$
70         "[Boolean]", //$NON-NLS-1$
71         "[Long]", //$NON-NLS-1$
72         "Vector Double", //$NON-NLS-1$
73         "Vector Integer", //$NON-NLS-1$
74         "Vector Float", //$NON-NLS-1$
75         "Vector String", //$NON-NLS-1$
76         "Vector Boolean", //$NON-NLS-1$
77         "Vector Long" //$NON-NLS-1$
78     };
79
80     public Resource componentType;
81     public FormToolkit tk;
82     public Form form;
83     public UnitLibrary unitLibrary = UnitLibrary.createDefault();
84     public boolean readOnly;
85     public NamedResource[] connectionPoints;
86     public ComponentTypeViewerPropertyInfo[] properties;
87
88     public ComponentTypeViewerData(FormToolkit tk, Resource componentType, Form form) {
89         this.tk = tk;
90         this.componentType = componentType;
91         this.form = form;
92     }
93
94     public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column,
95             Pattern namePattern) {
96         editName(table, editor, propertyInfo, selectedItem, column, namePattern, null);
97     }
98
99     public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column,
100             Pattern namePattern, DbConsumer<WriteGraph> extraWriter) {
101         editName(table, editor, propertyInfo, selectedItem, column,
102                 null,
103                 (pInfo, name) -> validatePropertyName(pInfo, name, namePattern),
104                 extraWriter);
105     }
106
107     public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column,
108             Function2<ComponentTypeViewerPropertyInfo, String, String> nameFilter, Pattern namePattern, DbConsumer<WriteGraph> extraWriter) {
109         editName(table, editor, propertyInfo, selectedItem, column, nameFilter,
110                 (pInfo, name) -> validatePropertyName(pInfo, name, namePattern),
111                 extraWriter);
112     }
113
114     public void editName(Table table, TableEditor editor, ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column,
115             Function2<ComponentTypeViewerPropertyInfo, String, String> nameValidator)
116     {
117         editName(table, editor, propertyInfo, selectedItem, column, nameValidator, null);
118     }
119
120     public void editName(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column,
121             Function2<ComponentTypeViewerPropertyInfo, String, String> nameValidator, DbConsumer<WriteGraph> extraWriter) {
122         editName(table, editor, propertyInfo, selectedItem, column, null, nameValidator, extraWriter);
123     }
124
125     public void editName(
126             Table table,
127             TableEditor editor,
128             final ComponentTypeViewerPropertyInfo propertyInfo,
129             TableItem selectedItem,
130             int column,
131             Function2<ComponentTypeViewerPropertyInfo, String, String> nameFilter,
132             Function2<ComponentTypeViewerPropertyInfo, String, String> nameValidator,
133             DbConsumer<WriteGraph> extraWriter) {
134         int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0;
135         final Text text = new Text(table, SWT.NONE | extraStyle);
136         org.eclipse.swt.widgets.Listener listener = 
137                 new org.eclipse.swt.widgets.Listener() {
138             @Override
139             public void handleEvent(Event e) {
140                 if (e.type == SWT.Dispose) {
141                     form.setMessage(null);
142                     return;
143                 } else if (e.type == SWT.Verify) {
144                     // Filter input if necessary
145                     e.text = nameFilter != null ? nameFilter.apply(propertyInfo, e.text) : e.text;
146                     return;
147                 } else if (e.type == SWT.Modify) {
148                     // validate current name
149                     String error = nameValidator.apply(propertyInfo, text.getText());
150                     if (error != null) {
151                         text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
152                         form.setMessage(error, IMessageProvider.ERROR);
153                     } else {
154                         text.setBackground(null);
155                         form.setMessage(null);
156                     }
157                     return;
158                 } else if (e.type == SWT.Traverse) {
159                     if (e.detail == SWT.TRAVERSE_ESCAPE) {
160                         text.dispose();
161                         e.doit = false;
162                         return;
163                     }
164                     if (e.detail == SWT.TRAVERSE_ARROW_NEXT || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS || e.detail == SWT.TRAVERSE_MNEMONIC)
165                         return;
166                     e.doit = false;
167                 }
168                 final String newValue = text.getText();
169                 text.dispose();
170
171                 String error = nameValidator.apply(propertyInfo, newValue);
172                 if (error != null)
173                     return;
174
175                 if (propertyInfo.immutable)
176                     return;
177
178                 Simantics.getSession().async(new WriteRequest() {
179                     @Override
180                     public void perform(WriteGraph graph)
181                             throws DatabaseException {
182                         graph.markUndoPoint();
183                         Layer0 L0 = Layer0.getInstance(graph);
184                         String prevName = graph.getPossibleRelatedValue2(propertyInfo.resource, L0.HasName);
185                         String oldCamelCasedLabel = prevName != null ? ComponentTypeCommands.camelCaseNameToLabel(prevName) : ""; //$NON-NLS-1$
186                         String oldLabel = graph.getPossibleRelatedValue(propertyInfo.resource, L0.HasLabel);
187                         boolean setLabel = oldLabel == null
188                                 || oldLabel.isEmpty()
189                                 || oldCamelCasedLabel.isEmpty()
190                                 || oldCamelCasedLabel.equals(oldLabel);
191
192                         ComponentTypeCommands.rename(graph, propertyInfo.resource, newValue);
193                         if (setLabel)
194                             ComponentTypeCommands.setLabel(graph, propertyInfo.resource, ComponentTypeCommands.camelCaseNameToLabel(newValue));
195
196                         if (extraWriter != null)
197                             extraWriter.accept(graph);
198                     }
199                 });
200             }
201         };
202         if (nameFilter != null)
203             text.addListener(SWT.Verify, listener);
204         text.addListener(SWT.Modify, listener);
205         text.addListener(SWT.Deactivate, listener);
206         text.addListener(SWT.Traverse, listener);
207         text.addListener(SWT.Dispose, listener);
208
209         text.setText(selectedItem.getText(column));
210         text.selectAll();
211         text.setFocus();
212
213         editor.setEditor(text, selectedItem, column);
214     }
215
216     public void editType(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column, final boolean convertDefaultValue) {
217         int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0;
218         final Combo combo = new Combo(table, SWT.NONE | extraStyle);
219         combo.setText(selectedItem.getText(column));
220         for(String suggestion : PROPERTY_TYPE_SUGGESTIONS)
221             combo.add(suggestion);
222         org.eclipse.swt.widgets.Listener listener = 
223                 new org.eclipse.swt.widgets.Listener() {
224             @Override
225             public void handleEvent(Event e) {
226                 if(e.type == SWT.Traverse) {
227                     if (e.detail == SWT.TRAVERSE_ESCAPE) {
228                         combo.dispose();
229                         e.doit = false;
230                         return;
231                     }
232                     if (e.detail == SWT.TRAVERSE_ARROW_NEXT
233                             || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS
234                             || e.detail == SWT.TRAVERSE_MNEMONIC)
235                         return;
236                 }
237                 final String newValue = combo.getText();
238                 if (e.type == SWT.Traverse) {
239                     e.doit = false;
240                 }
241                 combo.dispose();
242
243                 if (propertyInfo.immutable)
244                     return;
245
246                 Simantics.getSession().async(new WriteRequest() {
247                     @Override
248                     public void perform(WriteGraph graph)
249                             throws DatabaseException {
250                         graph.markUndoPoint();
251                         ComponentTypeCommands.editType(graph, componentType, propertyInfo.resource, convertDefaultValue, newValue);
252                     }
253                 });
254             }
255         };
256         combo.setFocus();
257         editor.setEditor(combo, selectedItem, column);
258         combo.addListener(SWT.FocusOut, listener);
259         combo.addListener(SWT.Traverse, listener);
260     }
261
262     public void editUnit(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, int column) {
263         // Disallow unit editing for non-numeric configuration properties
264         if (propertyInfo.numberType == null && propertyInfo.sectionSpecificData == null)
265             return;
266
267         int extraStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0;
268         final Combo combo = new Combo(table, SWT.NONE | extraStyle);
269         String initialValue = selectedItem.getText(column);
270         List<String> units = new ArrayList<>( unitLibrary.getUnits() );
271         Collections.sort(units, String.CASE_INSENSITIVE_ORDER);
272         int i = -1;
273         int selected = -1;
274         for (String unit : units) {
275             combo.add(unit);
276             if (unit.equals(initialValue))
277                 combo.select(i);
278         }
279         if (selected == -1)
280             combo.setText(initialValue);
281
282         org.eclipse.swt.widgets.Listener listener = 
283                 new org.eclipse.swt.widgets.Listener() {
284             @Override
285             public void handleEvent(Event e) {
286                 if(e.type == SWT.Traverse) {
287                     if (e.detail == SWT.TRAVERSE_ESCAPE) {
288                         combo.dispose();
289                         e.doit = false;
290                         return;
291                     }
292                     if (e.detail == SWT.TRAVERSE_ARROW_NEXT
293                             || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS
294                             || e.detail == SWT.TRAVERSE_MNEMONIC)
295                         return;
296                 }
297                 final String newValue = combo.getText();
298                 if(e.type == SWT.Traverse) {
299                     e.doit = false;
300                 }
301                 combo.dispose();
302
303                 if (propertyInfo.immutable)
304                     return;
305
306                 Simantics.getSession().async(new WriteRequest() {
307                     @Override
308                     public void perform(WriteGraph graph)
309                             throws DatabaseException {
310                         graph.markUndoPoint();
311                         ComponentTypeCommands.setUnit(graph, componentType, propertyInfo.resource, newValue);
312                     }
313                 });
314             }
315         };
316         combo.setFocus();
317         editor.setEditor(combo, selectedItem, column);
318         combo.addListener(SWT.Deactivate, listener);
319         combo.addListener(SWT.Traverse, listener);
320     }
321
322     public void editValue(Table table, TableEditor editor,
323             final ComponentTypeViewerPropertyInfo propertyInfo,
324             TableItem selectedItem, int column,
325             final StringWriter writer,
326             final Function4<RequestProcessor, Resource, Resource, String, String> validator)
327     {
328         int extraStyle = writer == null ? SWT.READ_ONLY : 0;
329         final Text text = new Text(table, SWT.NONE | extraStyle);
330         text.setText(selectedItem.getText(column));
331         org.eclipse.swt.widgets.Listener listener = 
332                 new org.eclipse.swt.widgets.Listener() {
333             @Override
334             public void handleEvent(Event e) {
335                 if(e.type == SWT.Traverse) {
336                     if (e.detail == SWT.TRAVERSE_ESCAPE) {
337                         text.dispose();
338                         e.doit = false;
339                         return;
340                     }
341                     if (e.detail == SWT.TRAVERSE_ARROW_NEXT
342                             || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS
343                             || e.detail == SWT.TRAVERSE_MNEMONIC)
344                         return;
345                 }
346                 final String newValue = text.getText();
347                 if(e.type == SWT.Traverse) {
348                     e.doit = false;
349                 }
350                 text.dispose();
351
352                 if (validator != null) {
353                     String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue);
354                     if (error != null)
355                         return;
356                 }
357
358                 if (writer != null) {
359                     Simantics.getSession().async(new WriteRequest() {
360                         @Override
361                         public void perform(WriteGraph graph) throws DatabaseException {
362                             writer.perform(graph, newValue);
363                         }
364                     });
365                 }
366             }
367         };
368         text.selectAll();
369         text.setFocus();
370         editor.setEditor(text, selectedItem, column);
371         text.addListener(SWT.FocusOut, listener);
372         text.addListener(SWT.Traverse, listener);
373
374         if (validator != null) {
375             org.eclipse.swt.widgets.Listener validationListener = new org.eclipse.swt.widgets.Listener() {
376                 @Override
377                 public void handleEvent(Event e) {
378                     final String newValue = text.getText();
379                     String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue);
380                     if (error != null) {
381                         text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
382                         text.setToolTipText(error);
383                         return;
384                     } else {
385                         text.setBackground(null);
386                         text.setToolTipText(null);
387                     }
388                 }
389             };
390             text.addListener(SWT.Modify, validationListener);
391         }
392     }
393
394     private Range parseRange(NumberType numberType, String minStr, String maxStr, boolean lowInclusive, boolean highInclusive) throws RangeException {
395         try {
396             String rangeStr = (lowInclusive ? "[" : "(")  + minStr + ".." + maxStr + (highInclusive ? "]" : ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
397             return Range.valueOf(rangeStr);
398         } catch (IllegalArgumentException e) {
399             // Limits are invalid
400             throw new RangeException(e.getMessage(), e);
401         }
402     }
403     
404     private static Combo createRangeInclusionCombo(Composite parent, boolean inclusive) {
405         Combo rng = new Combo(parent, SWT.READ_ONLY);
406         rng.add(Messages.ComponentTypeViewerData_Inclusive);
407         rng.add(Messages.ComponentTypeViewerData_Exclusive);
408         rng.select(inclusive ? 0 : 1);
409         return rng;
410     }
411     
412     protected void editRange(Table table, TableEditor editor, final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem, Rectangle selectedItemBounds, int column) {
413         // Disallow range editing when the property is not numeric
414         if (propertyInfo.numberType == null)
415             return;
416
417         int extraTextStyle = propertyInfo.immutable ? SWT.READ_ONLY : 0;
418
419         // Parse initial range value
420         Range range = null;
421         String rangeStr = selectedItem.getText(column);
422         try {
423             range = Range.valueOf(rangeStr);
424         } catch (RangeException ex) {
425             range = new Range(Limit.nolimit(), Limit.nolimit());
426         }
427
428         final Shell shell = new Shell(table.getShell(), SWT.ON_TOP);
429         GridLayoutFactory.fillDefaults().applyTo(shell);
430
431         Composite composite = new Composite(shell, SWT.NONE);
432         GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
433         GridLayoutFactory.swtDefaults().numColumns(3).applyTo(composite);
434
435         Label low = new Label(composite, SWT.NONE);
436         low.setText(Messages.ComponentTypeViewerData_MinimumValue);
437         final Text lowText = new Text(composite, SWT.BORDER | extraTextStyle);
438         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(lowText);
439         final Combo lowSelector = createRangeInclusionCombo(composite, !range.getLower().isExclusive());
440         Label high = new Label(composite, SWT.NONE);
441         high.setText(Messages.ComponentTypeViewerData_MaximumValue);
442         final Text highText = new Text(composite, SWT.BORDER | extraTextStyle);
443         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(highText);
444         final Combo highSelector = createRangeInclusionCombo(composite, !range.getUpper().isExclusive());
445
446         Composite buttonComposite = new Composite(shell, SWT.NONE);
447         GridDataFactory.fillDefaults().grab(true, false).align(SWT.TRAIL, SWT.FILL).applyTo(buttonComposite);
448         GridLayoutFactory.swtDefaults().numColumns(2).equalWidth(true).applyTo(buttonComposite);
449
450         Button ok = new Button(buttonComposite, SWT.NONE);
451         ok.setText(IDialogConstants.OK_LABEL);
452         GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(ok);
453         Button cancel = new Button(buttonComposite, SWT.NONE);
454         cancel.setText(IDialogConstants.CANCEL_LABEL);
455         GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(ok);
456
457         if (range.getLower().getValue() != null)
458             lowText.setText(range.getLower().getValue().toString());
459         if (range.getUpper().getValue() != null)
460             highText.setText(range.getUpper().getValue().toString());
461
462         shell.addListener(SWT.Deactivate, new org.eclipse.swt.widgets.Listener() {
463             @Override
464             public void handleEvent(Event event) {
465                 shell.dispose();
466             }
467         });
468
469         ok.addSelectionListener(new SelectionAdapter() {
470             public void widgetSelected(SelectionEvent e) {
471                 try {
472                     final Range newRange = parseRange(propertyInfo.numberType,
473                             lowText.getText().trim(),
474                             highText.getText().trim(),
475                             lowSelector.getSelectionIndex() == 0 ? true : false,
476                             highSelector.getSelectionIndex() == 0 ? true : false);
477
478                     shell.dispose();
479
480                     if (propertyInfo.immutable)
481                         return;
482
483                     Simantics.getSession().async(new WriteRequest() {
484                         @Override
485                         public void perform(WriteGraph graph)
486                                 throws DatabaseException {
487                             graph.markUndoPoint();
488                             ComponentTypeCommands.setRange(graph, componentType, propertyInfo.resource, newRange == null ? null : newRange.toString());
489                         }
490                     });
491                 } catch (RangeException ex) {
492                     ErrorLogger.defaultLogError(ex);
493                 }
494             }
495         });
496         cancel.addSelectionListener(new SelectionAdapter() {
497             public void widgetSelected(SelectionEvent e) {
498                 shell.dispose();
499             }
500         });
501
502         shell.pack();
503         Point size = shell.getSize();
504
505         Display display = table.getDisplay();
506         Rectangle clientArea = display.getClientArea();
507         Point bt = table.toDisplay(selectedItemBounds.x, selectedItemBounds.y);
508         Rectangle b = selectedItemBounds;
509         b.x = bt.x;
510         b.y = bt.y;
511         b.width = size.x;
512         b.height = size.y;
513         if ((b.x + b.width) > clientArea.width)
514             b.x -= b.x + b.width - clientArea.width;
515         if (b.height > clientArea.height)
516             b.height = clientArea.height;
517         if ((b.y + b.height) > clientArea.height)
518             b.y -= b.y + b.height - clientArea.height;
519
520         shell.setBounds(selectedItemBounds);
521         shell.open();
522     }
523
524     public void editMultilineText(Table table, TableEditor editor,
525             final ComponentTypeViewerPropertyInfo propertyInfo, TableItem selectedItem,
526             Rectangle selectedItemBounds, int column, final StringWriter writer)
527     {
528         final Shell shell = new Shell(table.getShell(), SWT.ON_TOP);
529         GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(shell);
530         final StyledText text = new StyledText(shell, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | (propertyInfo.immutable ? SWT.READ_ONLY : 0));
531         GridDataFactory.fillDefaults().grab(true, true).applyTo(text);
532         text.setText(selectedItem.getText(column));
533         org.eclipse.swt.widgets.Listener listener = 
534                 new org.eclipse.swt.widgets.Listener() {
535             @Override
536             public void handleEvent(Event e) {
537                 final String newValue = text.getText();
538
539                 if (e.type == SWT.Traverse) {
540                     if (e.detail == SWT.TRAVERSE_ESCAPE) {
541                         shell.dispose();
542                         e.doit = false;
543                         return;
544                     }
545                     if (e.detail == SWT.TRAVERSE_ARROW_NEXT
546                             || e.detail == SWT.TRAVERSE_ARROW_PREVIOUS
547                             || e.detail == SWT.TRAVERSE_MNEMONIC)
548                         return;
549                     if ((e.stateMask & SWT.CTRL) == 0)
550                         return;
551                     e.doit = false;
552                 }
553
554                 shell.dispose();
555
556                 if (propertyInfo.immutable)
557                     return;
558
559                 if (writer != null) {
560                     Simantics.getSession().async(new WriteRequest() {
561                         @Override
562                         public void perform(WriteGraph graph) throws DatabaseException {
563                             writer.perform(graph, newValue);
564                         }
565                     });
566                 }
567             }
568         };
569
570         String helpText = propertyInfo.immutable ? Messages.ComponentTypeViewerData_ESCToClose : Messages.ComponentTypeViewerData_CtrlEnterApplyChanges;
571         Label help = tk.createLabel(shell, helpText, SWT.BORDER | SWT.FLAT);
572         GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(help);
573         help.setForeground( tk.getColors().createColor( "fg", tk.getColors().getSystemColor(SWT.COLOR_LIST_SELECTION) ) ); //$NON-NLS-1$
574
575         Display display = table.getDisplay();
576         Rectangle clientArea = display.getClientArea();
577         Point bt = table.toDisplay(selectedItemBounds.x, selectedItemBounds.y);
578         Rectangle b = selectedItemBounds;
579         b.x = bt.x;
580         b.y = bt.y;
581         b.height = 200;
582         if ((b.x + b.width) > clientArea.width)
583             b.x -= b.x + b.width - clientArea.width;
584         if (b.height > clientArea.height)
585             b.height = clientArea.height;
586         if ((b.y + b.height) > clientArea.height)
587             b.y -= b.y + b.height - clientArea.height;
588
589         shell.setBounds(selectedItemBounds);
590         shell.open();
591
592         text.selectAll();
593         text.setFocus();
594
595         text.addListener(SWT.Traverse, listener);
596         shell.addListener(SWT.Deactivate, listener);
597     }
598
599     private String validatePropertyName(ComponentTypeViewerPropertyInfo propertyInfo, String propertyName, Pattern namePattern) {
600         if (propertyName.equals(propertyInfo.name))
601             return null;
602         for (ComponentTypeViewerPropertyInfo info : properties) {
603             if (propertyName.equals(info.name))
604                 return NLS.bind(Messages.ComponentTypeViewerData_PropertyNameInUse, propertyName); 
605         }
606         for (NamedResource cp : connectionPoints) {
607             if (propertyName.equals(cp.getName()))
608                 return NLS.bind(Messages.ComponentTypeViewerData_NameInUse, propertyName ); 
609         }
610         Matcher m = namePattern.matcher(propertyName);
611         if (!m.matches())
612             return NLS.bind(Messages.ComponentTypeViewerData_ContainsInvalidCharacters, propertyName, namePattern.pattern());
613         return null;
614     }
615
616 }