]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/forms/DataboardForm.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / forms / DataboardForm.java
1 package org.simantics.databoard.forms;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.List;\r
5 \r
6 import org.eclipse.jface.window.Window;\r
7 import org.eclipse.swt.SWT;\r
8 import org.eclipse.swt.custom.CTabFolder;\r
9 import org.eclipse.swt.custom.CTabItem;\r
10 import org.eclipse.swt.events.SelectionAdapter;\r
11 import org.eclipse.swt.events.SelectionEvent;\r
12 import org.eclipse.swt.graphics.Color;\r
13 import org.eclipse.swt.layout.GridData;\r
14 import org.eclipse.swt.layout.GridLayout;\r
15 import org.eclipse.swt.widgets.Button;\r
16 import org.eclipse.swt.widgets.Combo;\r
17 import org.eclipse.swt.widgets.Composite;\r
18 import org.eclipse.swt.widgets.Control;\r
19 import org.eclipse.swt.widgets.DirectoryDialog;\r
20 import org.eclipse.swt.widgets.Event;\r
21 import org.eclipse.swt.widgets.FileDialog;\r
22 import org.eclipse.swt.widgets.Group;\r
23 import org.eclipse.swt.widgets.Label;\r
24 import org.eclipse.swt.widgets.Listener;\r
25 import org.eclipse.swt.widgets.Shell;\r
26 import org.eclipse.swt.widgets.Text;\r
27 import org.simantics.databoard.Accessors;\r
28 import org.simantics.databoard.Bindings;\r
29 import org.simantics.databoard.accessor.Accessor;\r
30 import org.simantics.databoard.accessor.BooleanAccessor;\r
31 import org.simantics.databoard.accessor.RecordAccessor;\r
32 import org.simantics.databoard.accessor.StringAccessor;\r
33 import org.simantics.databoard.accessor.UnionAccessor;\r
34 import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
35 import org.simantics.databoard.accessor.error.AccessorException;\r
36 import org.simantics.databoard.accessor.error.ReferenceException;\r
37 import org.simantics.databoard.accessor.reference.ChildReference;\r
38 import org.simantics.databoard.accessor.reference.LabelReference;\r
39 import org.simantics.databoard.binding.Binding;\r
40 import org.simantics.databoard.binding.NumberBinding;\r
41 import org.simantics.databoard.binding.RecordBinding;\r
42 import org.simantics.databoard.binding.StringBinding;\r
43 import org.simantics.databoard.binding.UnionBinding;\r
44 import org.simantics.databoard.binding.error.BindingException;\r
45 import org.simantics.databoard.binding.mutable.TaggedObject;\r
46 import org.simantics.databoard.parser.repository.DataTypeSyntaxError;\r
47 import org.simantics.databoard.type.BooleanType;\r
48 import org.simantics.databoard.type.Component;\r
49 import org.simantics.databoard.type.Datatype;\r
50 import org.simantics.databoard.type.NumberType;\r
51 import org.simantics.databoard.type.RecordType;\r
52 import org.simantics.databoard.type.StringType;\r
53 import org.simantics.databoard.type.UnionType;\r
54 import org.simantics.databoard.util.Bean;\r
55 import org.simantics.databoard.util.StringUtil;\r
56 import org.simantics.databoard.util.URIUtil;\r
57 \r
58 /**\r
59  * Databoard form creates SWT user interface from databoard record type.\r
60  * \r
61  * See DataboardFormExample for example usage.\r
62  *\r
63  * @author toni.kalajainen@semantum.fi\r
64  */\r
65 public class DataboardForm {    \r
66 \r
67         public static final Datatype TEXTBOX;\r
68         public static final Datatype PASSWORD;\r
69         \r
70         public int column1Width = -1;\r
71         \r
72         private RecordType allfields = new RecordType();\r
73         \r
74         /**\r
75          * Make file type\r
76          * \r
77          * @param namesAndExts array of names and extensions\r
78          * @param exts\r
79          * @return\r
80          */\r
81         public static StringType fileSaveDialog(String...namesAndExts)\r
82         {               \r
83             StringType result = new StringType();\r
84             result.metadata.put("style", "filesave");\r
85                     \r
86             StringBuilder sb1 = new StringBuilder();\r
87             StringBuilder sb2 = new StringBuilder();\r
88             \r
89             for (int i=0; i<namesAndExts.length; i++) {\r
90                 StringBuilder sb = (i%2==0?sb1:sb2);\r
91                 int j = i/2;\r
92                 if (j>0) sb.append(','); \r
93                 sb.append(namesAndExts[i]);\r
94             }\r
95             \r
96                 result.metadata.put("filetypes", sb1.toString());\r
97             result.metadata.put("fileexts", sb2.toString());\r
98             return result;\r
99         }\r
100 \r
101         /**\r
102          * Make file type\r
103          * \r
104          * @param namesAndExts array of names and extensions\r
105          * @param exts\r
106          * @return\r
107          */\r
108         public static StringType fileOpenDialog(String...namesAndExts)\r
109         {               \r
110             StringType result = new StringType();\r
111             result.metadata.put("style", "fileopen");\r
112                     \r
113             StringBuilder sb1 = new StringBuilder();\r
114             StringBuilder sb2 = new StringBuilder();\r
115             \r
116             for (int i=0; i<namesAndExts.length; i++) {\r
117                 StringBuilder sb = (i%2==0?sb1:sb2);\r
118                 int j = i/2;\r
119                 if (j>0) sb.append(','); \r
120                 sb.append(namesAndExts[i]);\r
121             }\r
122             \r
123                 result.metadata.put("filetypes", sb1.toString());\r
124             result.metadata.put("fileexts", sb2.toString());\r
125             return result;\r
126         }\r
127         \r
128         public static StringType directoryDialog()\r
129         {               \r
130             StringType result = new StringType();\r
131             result.metadata.put("style", "directory");\r
132             return result;\r
133         }\r
134         \r
135         public DataboardForm() {\r
136         }\r
137         \r
138         public void setFirstColumnWidth(int width) {\r
139                 column1Width = width;\r
140         }\r
141         \r
142         \r
143         /**\r
144          * Validate the fields for valid values.\r
145          * StringTypes can be restricted with regular expressions.\r
146          * NumberTypes with value ranges.\r
147          * \r
148          * @param composite\r
149          * @return list of problems\r
150          */\r
151         public List<Problem> validate( Composite composite ) {\r
152                 List<Problem> result = new ArrayList<Problem>();\r
153                 _validateFields(composite, result);\r
154                 return result;\r
155         }\r
156         \r
157         public static List<String> toStrings(List<Problem> problems) {\r
158                 List<String> result = new ArrayList<String>( problems.size() );\r
159                 for (Problem p : problems) result.add(p.error);\r
160                 return result;\r
161         }\r
162         \r
163         public static class Problem extends Bean {\r
164                 /** Reference to the field with problem */\r
165                 public String fieldReference;\r
166                 /** The field with problem */\r
167                 public transient Control control;\r
168                 /** The validation error */\r
169                 public String error;\r
170         }\r
171 \r
172         protected void _validateFields( Control control, List<Problem> result )\r
173         {\r
174                 // Read this control\r
175                 Object data = control.getData();\r
176                 if ( data != null && data instanceof String ) {\r
177                         String refStr = (String) data;\r
178                         ChildReference ref = ChildReference.parsePath( refStr);\r
179                         if ( ref != null ) {\r
180                                 try {\r
181                                         Datatype fieldType = allfields.getChildType( ref );\r
182                                         \r
183                                         // Read Combo Union\r
184                                         if ( fieldType instanceof UnionType && control instanceof Combo ) {\r
185                                                 // Nothing to validate\r
186                                         } else\r
187 \r
188                                         // Read Radio Union\r
189                                         if ( fieldType instanceof UnionType && control instanceof Composite ) {\r
190                                                 // Nothing to validate\r
191                                         } else\r
192                                         \r
193                                         // Read Boolean\r
194                                         if ( fieldType instanceof BooleanType && control instanceof Button ) {\r
195                                                 // Nothing to validate\r
196                                         } else\r
197 \r
198                                         // Text + Dialog button\r
199                                         if ( fieldType instanceof RecordType && control instanceof Text ) {\r
200                                                 try {\r
201                                                         Text text = (Text) control;\r
202                                                         RecordBinding fieldBinding = Bindings.getMutableBinding(fieldType);\r
203                                                         Object value = parse(fieldBinding, text.getText());\r
204                                                         fieldBinding.assertInstaceIsValid( value );\r
205                                                 } catch (BindingException er) {\r
206                                                         Problem problem = new Problem();\r
207                                                         if ( er.getCause()!=null ) {\r
208                                                                 problem.error = er.getCause().getMessage();\r
209                                                         } else {\r
210                                                                 problem.error = er.getMessage();\r
211                                                         }\r
212                                                         problem.fieldReference = refStr;\r
213                                                         problem.control = control;\r
214                                                         result.add( problem );\r
215                                                 }                                               \r
216                                                 \r
217                                         } else\r
218                                                 \r
219                                         // Read Text\r
220                                         if ( fieldType instanceof StringAccessor && control instanceof Text ) {\r
221                                                 try {\r
222                                                         Text text = (Text) control;\r
223                                                         StringBinding binding = Bindings.getBinding(fieldType);\r
224                                                         Object value = binding.create(text.getText());\r
225                                                         binding.assertInstaceIsValid( value );\r
226                                                 } catch (BindingException er) {\r
227                                                         Problem problem = new Problem();\r
228                                                         if ( er.getCause()!=null ) {\r
229                                                                 problem.error = er.getCause().getMessage();\r
230                                                         } else {\r
231                                                                 problem.error = er.getMessage();\r
232                                                         }\r
233                                                         problem.fieldReference = refStr;\r
234                                                         problem.control = control;\r
235                                                         result.add( problem );\r
236                                                 }                                               \r
237                                         } else\r
238                                         \r
239                                         // Read Numbers\r
240                                         if ( fieldType instanceof NumberType && control instanceof Text ) {\r
241                                                 try {\r
242                                                         Text text = (Text) control;\r
243                                                         NumberBinding binding = Bindings.getBinding(fieldType);\r
244                                                         Object value = binding.create(text.getText());\r
245                                                         binding.assertInstaceIsValid( value );\r
246                                                 } catch (BindingException er) {\r
247                                                         Problem problem = new Problem();\r
248                                                         if ( er.getCause()!=null && er.getCause() instanceof NumberFormatException) {\r
249                                                                 NumberFormatException nfe = (NumberFormatException) er.getCause();\r
250                                                                 problem.error = nfe.getMessage();\r
251                                                         } else {\r
252                                                                 problem.error = er.getMessage();\r
253                                                         }\r
254                                                         problem.fieldReference = refStr;\r
255                                                         problem.control = control;\r
256                                                         result.add( problem );\r
257                                                 }                                               \r
258                                         }\r
259                                         \r
260                                 } catch (AccessorConstructionException e) {\r
261                                         Problem problem = new Problem();\r
262                                         problem.error = e.getMessage();\r
263                                         problem.fieldReference = refStr;\r
264                                         problem.control = control;\r
265                                         result.add( problem );\r
266                                 }\r
267                         }\r
268                 }\r
269                 \r
270                 // Recursion\r
271                 if ( control instanceof Composite ) {\r
272                         Composite composite = (Composite) control;\r
273                         for (Control child : composite.getChildren()) \r
274                         {\r
275                                 _validateFields(child, result);\r
276                         }\r
277                 }\r
278                 \r
279         }\r
280         \r
281         public RecordType type() {\r
282                 return allfields;\r
283         }\r
284 \r
285         /**\r
286          * Find control by reference \r
287          * @param control\r
288          * @param ref\r
289          * @return control or null\r
290          */\r
291         public Control getControl( Control control, ChildReference ref )\r
292         {\r
293                 return getControl( control, ref.toPath() );\r
294         }\r
295         \r
296         /**\r
297          * Find control by reference. \r
298          * \r
299          * @param composite\r
300          * @param ref\r
301          * @return control or null\r
302          */\r
303         public Control getControl( Control control, String ref )\r
304         {\r
305                 Object data = control.getData();\r
306                 if ( data != null && data instanceof String && data.equals(ref)) return control;\r
307                         \r
308                 // Recursion\r
309                 if ( control instanceof Composite ) {\r
310                         Composite composite = (Composite) control;\r
311                         for (Control child : composite.getChildren()) \r
312                         {\r
313                                 Control result = getControl(child, ref);\r
314                                 if ( result != null ) return result;\r
315                         }\r
316                 }\r
317                 return null;\r
318         }\r
319         \r
320         /**\r
321          * Reads values of fields into a record\r
322          * \r
323          * @param composite the composite that holds the widgets\r
324          * @param binding record binding\r
325          * @param dst the record where values are read to\r
326          * @throws BindingException\r
327          * @throws AccessorConstructionException \r
328          * @throws AccessorException \r
329          */\r
330         public void readFields( Composite composite, RecordBinding binding, Object dst)\r
331         throws BindingException, AccessorConstructionException, AccessorException\r
332         {\r
333                 RecordAccessor ra = Accessors.getAccessor(binding, dst);\r
334                 _readFields(composite, ra);\r
335         }\r
336         \r
337         protected void _readFields( Control control, RecordAccessor ra ) \r
338         throws AccessorException, BindingException\r
339         {\r
340                 // Read this control\r
341                 Object data = control.getData();\r
342                 if ( data != null && data instanceof String ) {\r
343                         ChildReference ref = ChildReference.parsePath( (String) data);\r
344                         if ( ref != null ) {\r
345                                 try {\r
346                                         Accessor fieldAccessor = ra.getComponent( ref );\r
347                                         \r
348                                         // Read Combo Union\r
349                                         if ( fieldAccessor instanceof UnionAccessor && control instanceof Combo ) {\r
350                                                 UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
351                                                 Combo combo = (Combo) control;\r
352                                                 String text = combo.getText();\r
353                                                 int tag = sa.type().getComponentIndex2(text);\r
354                                                 Datatype tagType = sa.type().components[tag].type;\r
355                                                 Binding tagBinding = Bindings.getBinding(tagType);\r
356                                                 Object defaultValue = tagBinding.createDefault();                                                                       \r
357                                                 sa.setComponentValue(tag, tagBinding, defaultValue);\r
358                                         } else\r
359 \r
360                                         // Read Radio Union\r
361                                         if ( fieldAccessor instanceof UnionAccessor && control instanceof Composite ) {\r
362                                                 Composite radioComposite = (Composite) control;\r
363                                                 for (Control c : radioComposite.getChildren()) {\r
364                                                         if ( c instanceof Button && ((Button)c).getSelection() ) {\r
365                                                                 Object data2 = c.getData();\r
366                                                                 if (data2==null) continue;\r
367                                                                 String name = getName( data2.toString() );\r
368                                                                 if ( name==null ) continue;\r
369                                                                 \r
370                                                                 UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
371                                                                 int tag = sa.type().getComponentIndex2( name );\r
372                                                                 if ( tag>=0 ) {\r
373                                                                         Datatype tagType = sa.type().components[tag].type;\r
374                                                                         Binding tagBinding = Bindings.getBinding(tagType);\r
375                                                                         Object defaultValue = tagBinding.createDefault();                                                                       \r
376                                                                         sa.setComponentValue(tag, tagBinding, defaultValue);\r
377                                                                         break;\r
378                                                                 }\r
379                                                         }\r
380                                                 }\r
381                                         } else\r
382                                         \r
383                                         // Read Boolean\r
384                                         if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {\r
385                                                 BooleanAccessor sa = (BooleanAccessor) fieldAccessor;\r
386                                                 sa.setValue(((Button)control).getSelection());\r
387                                         } else\r
388 \r
389                                         // Read Text + Dialog Button\r
390                                         if ( fieldAccessor instanceof RecordAccessor && control instanceof Text ) {\r
391                                                 RecordAccessor raa = (RecordAccessor) fieldAccessor;\r
392                                                 Text text = (Text) control;\r
393                                                 RecordBinding fieldBinding = Bindings.getMutableBinding( raa.type() );\r
394                                                 Object value = parse( fieldBinding, text.getText() );\r
395                                                 raa.setValue(fieldBinding, value);\r
396                                         } else\r
397                                                 \r
398                                         // Read Text\r
399                                         if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {\r
400                                                 StringAccessor sa = (StringAccessor) fieldAccessor;\r
401                                                 sa.setValue(((Text)control).getText());\r
402                                         } else\r
403                                         \r
404                                         // Read Numbers\r
405                                         if ( fieldAccessor.type() instanceof NumberType && control instanceof Text ) {\r
406                                                 NumberBinding binding = Bindings.getBinding( fieldAccessor.type() );\r
407                                                 Object value = binding.create( ((Text)control).getText() );\r
408                                                 fieldAccessor.setValue(binding, value);\r
409                                         }\r
410                                         \r
411                                 } catch (AccessorConstructionException e) {\r
412                                         //e.printStackTrace();\r
413                                 }\r
414                         }\r
415                 }\r
416                 \r
417                 // Recursion\r
418                 if ( control instanceof Composite ) {\r
419                         Composite composite = (Composite) control;\r
420                         for (Control child : composite.getChildren()) \r
421                         {\r
422                                 _readFields(child, ra);\r
423                         }\r
424                 }\r
425         }\r
426 \r
427         public void writeFields( Composite composite, RecordBinding binding, Object src)\r
428                         throws AccessorException, BindingException, AccessorConstructionException\r
429         {\r
430                 RecordAccessor ra = Accessors.getAccessor(binding, src);\r
431                 _writeFields(composite, ra);\r
432         }\r
433         \r
434         void _writeFields( Control control, RecordAccessor ra )\r
435                         throws AccessorException, BindingException, AccessorConstructionException\r
436         {\r
437                 // Read this control\r
438                 Object data = control.getData();\r
439                 if ( data != null && data instanceof String ) {\r
440                         ChildReference ref = ChildReference.parsePath( (String) data);\r
441                         if ( ref != null ) {\r
442                                 try {\r
443                                         Accessor fieldAccessor = ra.getComponent( ref );\r
444                                         \r
445                                         // Read Combo Union\r
446                                         if ( fieldAccessor instanceof UnionAccessor && control instanceof Combo ) {\r
447                                                 UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
448                                                 Combo combo = (Combo) control;\r
449                                                 int tag = sa.getTag();                                          \r
450                                                 combo.setText( sa.type().getComponent(tag).name );\r
451                                         } else\r
452 \r
453                                         // Read Radio Union\r
454                                         if ( fieldAccessor instanceof UnionAccessor && control instanceof Composite) {\r
455                                                 Composite radioComposite = (Composite) control;\r
456                                                 UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
457                                                 int tag = sa.getTag();\r
458                                                 for (int i=0; i<sa.count(); i++) {\r
459                                                         Button button = (Button) radioComposite.getChildren()[i*2];\r
460                                                         button.setSelection(i==tag);\r
461                                                 }\r
462                                         } else\r
463                                         \r
464                                         // Read Boolean\r
465                                         if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {\r
466                                                 BooleanAccessor sa = (BooleanAccessor) fieldAccessor;\r
467                                                 ((Button)control).setSelection(sa.getValue());\r
468                                         } else\r
469 \r
470                                         // Write Text + Dialog Selection\r
471                                         if ( fieldAccessor instanceof RecordAccessor && control instanceof Text ) {\r
472                                                 RecordAccessor raa = (RecordAccessor) fieldAccessor;\r
473                                                 Text text = (Text) control;\r
474                                                 RecordBinding fieldBinding = Bindings.getMutableBinding( raa.type() );\r
475                                                 String str = print( fieldBinding, raa.getValue(fieldBinding) );                                 \r
476                                                 text.setText( str );\r
477                                         } else\r
478                                                 \r
479                                         // Read Text\r
480                                         if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {\r
481                                                 StringAccessor sa = (StringAccessor) fieldAccessor;\r
482                                                 ((Text)control).setText( sa.getValue() );\r
483                                         } else\r
484                                         \r
485                                         // Read Numbers\r
486                                         if ( fieldAccessor.type() instanceof NumberType && control instanceof Text ) {\r
487                                                 NumberBinding binding = Bindings.getBinding( fieldAccessor.type() );\r
488                                                 Object value = fieldAccessor.getValue(binding);\r
489                                                 ((Text)control).setText( binding.toString(value, true) );\r
490                                         }\r
491                                         \r
492                                 } catch (AccessorConstructionException e) {\r
493                                         //e.printStackTrace();\r
494                                 }\r
495                         }\r
496                 }\r
497                 \r
498                 // Recursion\r
499                 if ( control instanceof Composite ) {\r
500                         Composite composite = (Composite) control;\r
501                         for (Control child : composite.getChildren()) \r
502                         {\r
503                                 _writeFields(child, ra);\r
504                         }\r
505                 }\r
506                 \r
507         }\r
508         \r
509         public void clear( Control control ) \r
510         {               \r
511                 _clearFields( control );\r
512                 allfields.clear();\r
513         }\r
514 \r
515         protected void _clearFields( Control control ) \r
516         {               \r
517                 // Recursion\r
518                 if ( control instanceof Composite ) {\r
519                         Composite composite = (Composite) control;\r
520                         for (Control child : composite.getChildren()) \r
521                         {\r
522                                 _clearFields(child);\r
523                                 child.dispose();\r
524                         }\r
525                 }\r
526 \r
527         }\r
528         \r
529         /**\r
530          * Add a listener to all the controls that represent the data type.\r
531          * \r
532          * @param composite the composite that holds the widgets\r
533          * @param binding record binding\r
534          * @param dst the record where values are read to\r
535          * @throws BindingException\r
536          * @throws AccessorConstructionException \r
537          * @throws AccessorException \r
538          */\r
539         public void addListener( Composite composite, RecordType type, Listener listener )\r
540         throws BindingException, AccessorConstructionException, AccessorException\r
541         {\r
542                 _addListener(composite, type, listener );\r
543         }\r
544         \r
545         protected void _addListener( Control control, Datatype type, Listener listener ) \r
546         throws AccessorException, BindingException\r
547         {\r
548                 // Read this control\r
549                 Object data = control.getData();\r
550                 ChildReference ref = null;\r
551                 if ( data != null && data instanceof String ) {\r
552                         ref = ChildReference.parsePath( (String) data);\r
553                 }\r
554                         \r
555                                 try {                                   \r
556                                         Datatype fieldType = ref==null ? type : type.getChildType( ref );\r
557 \r
558                                         // Read Combo Union\r
559                                         if ( fieldType instanceof UnionType && control instanceof Combo ) {\r
560                                                 control.addListener(SWT.Selection, listener);\r
561                                         } else\r
562                                         // Read Radio Union\r
563                                         if ( fieldType instanceof UnionType && control instanceof Composite ) {\r
564                                                 Composite radioComposite = (Composite) control;\r
565                                                 for (Control c : radioComposite.getChildren()) {\r
566                                                         if ( c instanceof Button ) {\r
567                                                                 c.addListener(SWT.Selection, listener);\r
568                                                         }\r
569                                                 }\r
570                                         } else\r
571                                         \r
572                                         // Read Boolean\r
573                                         if ( fieldType instanceof BooleanType && control instanceof Button ) {\r
574                                                 control.addListener(SWT.Selection, listener);\r
575                                         } else\r
576                                         \r
577                                         // Read Text\r
578                                         if ( fieldType instanceof StringType && control instanceof Text ) {\r
579                                                 control.addListener(SWT.Modify, listener);\r
580                                         } else\r
581                                         \r
582                                         // Read Numbers\r
583                                         if ( fieldType instanceof NumberType && control instanceof Text ) {\r
584                                                 control.addListener(SWT.Modify, listener);\r
585                                         }\r
586                                 \r
587                                 } catch (ReferenceException re) {\r
588                                 }\r
589                 \r
590                 // Recursion\r
591                 if ( control instanceof Composite ) {\r
592                         Composite composite = (Composite) control;\r
593                         for (Control child : composite.getChildren()) \r
594                         {\r
595                                 _addListener(child, type, listener);\r
596                         }\r
597                 }\r
598         }\r
599         \r
600         public void addField( Composite parent, String name, Datatype fieldType )\r
601         {\r
602                 addField(parent, fieldType, URIUtil.encodeURI(name), null);\r
603                 allfields.addComponent(name, fieldType);\r
604         }\r
605         \r
606         public void addField( Composite parent, String name, Datatype fieldType, String ref )\r
607         {\r
608                 addField(parent, fieldType, appendName(ref, name), null);\r
609                 \r
610                 RecordType root = allfields;\r
611                 if ( ref != null && !ref.isEmpty() ) {\r
612                         // find deeper root\r
613                         ChildReference path = ChildReference.parsePath(ref);\r
614                         while ( path!=null ) {\r
615                                 if ( path instanceof LabelReference == false ) {\r
616                                         throw new RuntimeException( "blaah" );                                          \r
617                                 }\r
618                                 LabelReference lr = (LabelReference) path;\r
619                                 String label = lr.label;\r
620                                 \r
621                                 if ( root.hasComponent(label) ) {\r
622                                         root = (RecordType) root.getComponent(label).type;\r
623                                 } else {\r
624                                         RecordType rt = new RecordType();\r
625                                         root.addComponent(label, rt);\r
626                                         root = rt;\r
627                                 }\r
628                                 path = path.childReference;\r
629                         }\r
630                 }\r
631                 if ( !root.hasComponent(name) ) root.addComponent(name, fieldType);             \r
632         }\r
633         \r
634         \r
635         public void addFields( Composite parent, RecordType source ) \r
636         {\r
637                 for (Component component : source.getComponents()) \r
638                         addField( parent, component.name, component.type );\r
639         }\r
640         \r
641         public void addFields( Composite parent, RecordType source, String ref ) \r
642         {\r
643                 for (Component component : source.getComponents()) \r
644                         addField( parent, component.name, component.type, ref );\r
645         }\r
646         \r
647         \r
648         public void addField( Composite parent, Datatype fieldType, String ref, GridData lblLayout )\r
649         {\r
650                 if (lblLayout==null) {\r
651                         lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);\r
652                         if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;\r
653                 }               \r
654                 String fieldName = getName(ref);\r
655                 \r
656                 if (fieldType instanceof StringType) {\r
657                         Label label = new Label(parent, 0);\r
658                         label.setText(fieldName + ":");\r
659                         label.setToolTipText(fieldName);\r
660                         label.setLayoutData( lblLayout );\r
661 \r
662                         addString(parent, (StringType) fieldType, ref);\r
663                         \r
664                 } else if (fieldType instanceof BooleanType) {\r
665 \r
666                         Label label = new Label(parent, 0);\r
667                         label.setLayoutData( lblLayout );\r
668                         \r
669                         addBoolean(parent, (BooleanType) fieldType, ref);\r
670 \r
671                 } else if (fieldType instanceof NumberType) {\r
672 \r
673                         Label label = new Label(parent, 0);\r
674                         label.setText(fieldName + ":");\r
675                         label.setLayoutData( lblLayout );\r
676 \r
677                         addNumber(parent, (NumberType) fieldType, ref);\r
678 \r
679                 } else if (fieldType instanceof RecordType) {\r
680                         RecordType record = (RecordType) fieldType;\r
681                         String options = record.metadata.get("style");\r
682                         boolean dialog = options==null?false:options.contains("dialog");\r
683                         boolean tabbed = options==null?false:options.contains("tabbed");\r
684                         \r
685                         // Method 0: Tabbed, each field is a tab page\r
686                         if ( tabbed ) {\r
687                                 Label label = new Label(parent, 0);\r
688                                 label.setText(fieldName + ":");\r
689                                 label.setLayoutData( lblLayout );\r
690                                 \r
691                                 CTabFolder folder = new CTabFolder(parent, SWT.TOP | SWT.BORDER);\r
692                                 //folder.setUnselectedCloseVisible(false);\r
693                                 folder.setSimple(false);\r
694                                 folder.setLayout( new GridLayout(3, false) );                   \r
695                                 folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));\r
696                                 \r
697                                 for (int i=0; i<record.getComponentCount(); i++) {\r
698                                         String childName = record.getComponent(i).name;\r
699                                         Datatype childType = record.getComponentType(i);\r
700                                         String childRef = appendName(ref, childName);\r
701                                         if (i>0) new Label(parent, 0);\r
702                                         \r
703                                         CTabItem item = new CTabItem(folder, SWT.NONE);\r
704                                         item.setText(childName);\r
705                                         Composite composite = new Composite(folder, 0);\r
706                                         composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));\r
707                                         composite.setLayout( new GridLayout(3, false) );\r
708                                         composite.setData(ref);\r
709                                         \r
710                                         if ( childType instanceof RecordType ) {\r
711                                                 addRecord( composite, (RecordType)childType, childRef);                                         \r
712                                         } else {\r
713                                                 addWidget( composite, childType, childRef );\r
714                                         }\r
715                                         \r
716                                         item.setControl( composite );\r
717                                 }       \r
718                                 folder.setSelection(0);\r
719 \r
720                         } else\r
721                                 \r
722                         // Method 1: Dialog = Label + Text + [Button]\r
723                         if ( dialog ) {\r
724                                 Label label = new Label(parent, 0);\r
725                                 label.setText(fieldName + ":");\r
726                                 label.setLayoutData( lblLayout );\r
727                                 \r
728                                 final String title = fieldName;\r
729                                 final Shell shell = parent.getShell();\r
730                                 final RecordBinding fieldBinding = Bindings.getMutableBinding( fieldType );\r
731                                 final Object fieldValue = fieldBinding.createDefaultUnchecked();\r
732                                 final Text text = new Text(parent, SWT.BORDER);\r
733                                 final Button select = new Button(parent, SWT.PUSH);\r
734                                 text.setLayoutData( new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1 ) );\r
735                                 text.setText( print(fieldBinding, fieldValue) );\r
736                                 text.setData(ref);                      \r
737                                 text.addListener(SWT.Verify, new Listener() {\r
738                                         public void handleEvent(Event e) {\r
739                                                 try {\r
740                                                         String newText = applyEventToString( text.getText(), e );\r
741                                                         Object value = parse(fieldBinding, newText);\r
742                                                         fieldBinding.assertInstaceIsValid( value );\r
743                                                         text.setBackground(null);\r
744                                                 } catch (BindingException er) {\r
745                                                         Color error = new Color(text.getDisplay(), 255, 222, 222); \r
746                                                         text.setBackground(error);                                      \r
747                                                         error.dispose();\r
748                                                 }\r
749                                         }\r
750                                 });             \r
751                                 \r
752                                 //text.setEditable( false );\r
753                                 select.setText("Select");\r
754                                 select.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));\r
755                                 select.addSelectionListener(new SelectionAdapter() {\r
756                                         public void widgetSelected(SelectionEvent e) {\r
757                                                 Object initialValue;\r
758                                                 try {\r
759                                                         initialValue = parse(fieldBinding, text.getText());\r
760                                                 } catch (BindingException e1) {\r
761                                                         initialValue = fieldBinding.createDefaultUnchecked();\r
762                                                 }\r
763                                                 DataboardDialog dialog = new DataboardDialog(\r
764                                                                 shell,\r
765                                                                 title, \r
766                                                                 fieldBinding, \r
767                                                                 initialValue);\r
768                                                                                                         \r
769                                                 int code = dialog.open();\r
770                                                 if ( code == Window.OK ) {\r
771                                                         Object result = dialog.getResult();\r
772                                                         String str = print(fieldBinding, result);\r
773                                                         text.setText( str );\r
774                                                 }\r
775                                         }\r
776                                 });\r
777                                 \r
778                         } else \r
779 \r
780                         // Method 2: Label + composite\r
781                         if ( allBooleans(record) ) {                    \r
782                                 Label label = new Label(parent, 0);\r
783                                 label.setText(fieldName + ":");\r
784                                 label.setLayoutData( lblLayout );\r
785                                 \r
786                                 for (int i=0; i<record.getComponentCount(); i++) {\r
787                                         String childName = record.getComponent(i).name;\r
788                                         Datatype childType = record.getComponentType(i);\r
789                                         String childRef = appendName(ref, childName);\r
790                                         if (i>0) new Label(parent, 0);\r
791                                         addWidget( parent, childType, childRef );\r
792                                 }               \r
793                                 \r
794                         } \r
795                         else\r
796                         \r
797                         // Method 3: Groups\r
798                         {\r
799                                 Group group = new Group(parent, 0);\r
800                                 group.setText(fieldName);\r
801                                 group.setLayout( new GridLayout(3, false) );                    \r
802                                 group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));\r
803                                 group.setData(ref);\r
804                                 addRecord(group, record, ref);\r
805                         }\r
806                         \r
807                 } else if (fieldType instanceof UnionType) {\r
808                         Label label = new Label(parent, 0);\r
809                         label.setText(fieldName + ":");\r
810                         label.setLayoutData( lblLayout );\r
811                         addUnion( parent, (UnionType) fieldType, ref );\r
812                 }\r
813                 \r
814         }\r
815 \r
816         protected void addWidget(Composite parent, Datatype fieldType, String ref) {\r
817                 if (fieldType instanceof StringType) {\r
818                         addString(parent, (StringType) fieldType, ref);\r
819                 } else if (fieldType instanceof BooleanType) {\r
820                         addBoolean(parent, (BooleanType) fieldType, ref);\r
821                 } else if (fieldType instanceof NumberType) {\r
822                         addNumber(parent, (NumberType) fieldType, ref);\r
823                 } else if (fieldType instanceof RecordType) {\r
824                         RecordType rt = (RecordType) fieldType;\r
825                         Group group = new Group(parent, 0);\r
826                         String name = getName(ref);\r
827                         group.setText(name);\r
828                         group.setLayout( new GridLayout(3, false) );                    \r
829                         group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));\r
830                         group.setData(ref);\r
831                         addRecord(group, rt, ref);\r
832                 } else if (fieldType instanceof UnionType) {\r
833                         addUnion( parent, (UnionType) fieldType, ref );\r
834                 }\r
835         }\r
836         \r
837         public CTabFolder addTabFolder( Composite parent, RecordType record, String ref )\r
838         {\r
839                 CTabFolder folder = new CTabFolder(parent, SWT.TOP | SWT.BORDER);\r
840                 folder.setSimple(false);\r
841                 folder.setLayout( new GridLayout(3, false) );                   \r
842                 folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));\r
843                 \r
844                 for (int i=0; i<record.getComponentCount(); i++) {\r
845                         String childName = record.getComponent(i).name;\r
846                         Datatype childType = record.getComponentType(i);\r
847                         String childRef = appendName(ref, childName);\r
848                         if (i>0) new Label(parent, 0);\r
849                         \r
850                         CTabItem item = new CTabItem(folder, SWT.NONE);\r
851                         item.setText(childName);\r
852                         Composite composite = new Composite(folder, 0);\r
853                         composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));\r
854                         composite.setLayout( new GridLayout(3, false) );\r
855                         composite.setData(ref);\r
856                         \r
857                         if ( childType instanceof RecordType ) {\r
858                                 addRecord( composite, (RecordType)childType, childRef);                                         \r
859                         } else {\r
860                                 addWidget( composite, childType, childRef );\r
861                         }\r
862                         \r
863                         item.setControl( composite );\r
864                         allfields.addComponent(childName, childType);\r
865                 }       \r
866                 folder.setSelection(0);\r
867                 return folder;\r
868                 \r
869         }\r
870         \r
871         protected void addRecord( Composite parent, RecordType record, String ref )\r
872         {\r
873                 String options = record.metadata.get("style");\r
874                 boolean dialog = options==null?false:options.contains("dialog");\r
875                 boolean tabbed = options==null?false:options.contains("tabbed");\r
876                 \r
877                 // Method 0: Tabbed, each field is a tab page\r
878                 if ( tabbed ) {\r
879                         addTabFolder( parent, record, ref );\r
880                         return;\r
881                 }\r
882                 \r
883                 // Normal Record\r
884                 GridData lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);\r
885                 if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;\r
886                         \r
887                 for (int i=0; i<record.getComponentCount(); i++) {\r
888                         String fieldName = record.getComponent(i).name;\r
889                         Datatype fieldType = record.getComponentType(i);\r
890                         String fieldRef = appendName(ref, fieldName);\r
891                         addField( parent, fieldType, fieldRef, lblLayout);\r
892                 }               \r
893                 return;\r
894         }\r
895                 \r
896         protected void addUnion( Composite parent, UnionType union, String ref )\r
897         {\r
898                 if ( union.isEnumeration() ) {\r
899                         addEnum( parent, union, ref );\r
900                 } else {\r
901                         addRadio( parent, union, ref );\r
902                 }               \r
903         }\r
904         \r
905         protected void addEnum( Composite parent, UnionType union, String ref )\r
906         {\r
907                 Combo combo = new Combo(parent, SWT.READ_ONLY);\r
908                 String[] items = new String[union.getComponentCount()];\r
909                 for (int i = 0; i < items.length; i++) {\r
910                         items[i] = union.getComponent(i).name;\r
911                 }\r
912                 combo.setItems(items);\r
913                 combo.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
914                 combo.setData(ref);\r
915                 \r
916                 // Set default value\r
917                 UnionBinding binding = Bindings.getBinding(union);\r
918                 try {\r
919                         TaggedObject defaultOption = (TaggedObject) binding.createDefault();\r
920                         combo.setText( items[ defaultOption.tag ] );\r
921                 } catch (BindingException e) {\r
922                 }                               \r
923         }\r
924 \r
925         protected void addRadio( Composite parent, UnionType union, String ref )\r
926         {\r
927                 Composite composite = new Composite(parent, 0);\r
928                 composite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
929                 composite.setLayout( new GridLayout(3, false) );\r
930                 composite.setData(ref);\r
931                 final int count = union.getComponentCount();\r
932                 final Composite panels[] = new Composite[count];\r
933                 final Button buttons[] = new Button[count];\r
934                 for ( int i=0; i<count; i++ ) {\r
935                         Component component = union.getComponent(i);\r
936                         String childRef = ref+"/"+URIUtil.encodeURI(component.name);\r
937                         Button b = buttons[i] = new Button(composite, SWT.RADIO);\r
938                         b.setLayoutData(new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1));\r
939                         b.setText(component.name);\r
940                         b.setData(childRef);\r
941                         \r
942                         String options = union.metadata.get("style");\r
943                         boolean border = options==null?true:!options.contains("no-border");\r
944                         int style = 0;                  \r
945                         if (border) style |= SWT.BORDER;\r
946                         \r
947                         Composite panel = panels[i] = new Composite(composite, style);\r
948                         panel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
949                         panel.setLayout( new GridLayout(3, false) );\r
950                         panel.setData(childRef);\r
951                         \r
952                         Datatype componentType = union.getComponentType(i);\r
953                         if ( componentType instanceof RecordType ) {\r
954                                 addRecord(panel, (RecordType) componentType, childRef);\r
955                         } else {\r
956                                 addWidget(panel, componentType, childRef);\r
957                         }                       \r
958                 }\r
959                 \r
960                 // Set default value\r
961                 UnionBinding binding = Bindings.getBinding(union);\r
962                 try {\r
963                         TaggedObject defaultOption = (TaggedObject) binding.createDefault();\r
964                         buttons[defaultOption.tag].setSelection(true);\r
965                 } catch (BindingException e) {\r
966                 }                               \r
967                 \r
968         }\r
969         \r
970         protected void addNumber( Composite parent, NumberType number, String ref )\r
971         {\r
972                 String unit = number.getUnit();\r
973                 String options = number.metadata.get("style");\r
974                 boolean border = options==null?true:!options.contains("no-border");\r
975                 int style = 0;                  \r
976                 if (border) style |= SWT.BORDER;\r
977                 final Text text = new Text(parent, style);\r
978                 text.setData(ref);\r
979                 text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, unit==null?2:1, 1));\r
980                 \r
981                 // Set default value\r
982                 final NumberBinding binding = Bindings.getBinding( number );\r
983                 try {\r
984                         text.setText( binding.createDefault().toString() );\r
985                 } catch (BindingException e) {\r
986                 }\r
987                 \r
988                 // Add validator\r
989                 text.addListener(SWT.Verify, new Listener() {\r
990                         public void handleEvent(Event e) {\r
991                                 try {\r
992                                         String newText = applyEventToString( text.getText(), e );\r
993                                         Object value = binding.create( newText );\r
994                                         binding.assertInstaceIsValid( value );\r
995                                         text.setBackground(null);                                       \r
996                                 } catch (BindingException er) {\r
997                                         Color error = new Color(text.getDisplay(), 255, 222, 222); \r
998                                         text.setBackground(error);\r
999                                         error.dispose();                                        \r
1000                                 }\r
1001                         }});\r
1002                 \r
1003                 if ( unit!=null ) {\r
1004                         Label unitLabel = new Label(parent, 0);\r
1005                         unitLabel.setText(unit);\r
1006                 }\r
1007         }\r
1008         \r
1009         static String applyEventToString(String orig, Event e) {\r
1010                 if (e.character==8) {\r
1011                         return orig.substring(0, e.start) + orig.substring(e.end, orig.length());\r
1012                 }\r
1013                 return orig.substring(0, e.start) + e.text + orig.substring(e.end, orig.length());              \r
1014         }\r
1015         \r
1016         protected void addBoolean( Composite parent, BooleanType booleanType, String ref )\r
1017         {\r
1018                 Button button = new Button(parent, SWT.CHECK);\r
1019                 button.setText( getName(ref) );\r
1020                 button.setData(ref);\r
1021                 button.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
1022         }\r
1023         \r
1024         protected void addString( Composite parent, StringType stringType, String ref )\r
1025         {               \r
1026                 String options = stringType.metadata.get("style");\r
1027                 boolean password = options==null?false:options.contains("password");\r
1028                 boolean filesave = options==null?false:options.contains("filesave");\r
1029                 boolean fileopen = options==null?false:options.contains("fileopen");\r
1030                 boolean directory = options==null?false:options.contains("directory");\r
1031                 boolean multi = options==null?false:options.contains("multi");\r
1032                 boolean border = options==null?true:!options.contains("no-border");\r
1033 \r
1034                 int style = 0;\r
1035                 if (password) style |= SWT.PASSWORD;\r
1036                 if (multi) style |= SWT.MULTI;\r
1037                 if (border) style |= SWT.BORDER;\r
1038                 final Text text = new Text(parent, style);\r
1039                 text.setLayoutData( new GridData(SWT.FILL, multi?SWT.FILL:SWT.BEGINNING, true, false, filesave|fileopen|directory?1:2, 1 ) );\r
1040                 text.setData(ref);\r
1041 \r
1042                 // Set default value\r
1043                 final StringBinding binding = Bindings.getBinding( stringType );\r
1044                 try {\r
1045                         text.setText( binding.createDefault().toString() );\r
1046                 } catch (BindingException e) {\r
1047                 }\r
1048                 \r
1049                 text.addListener(SWT.Verify, new Listener() {\r
1050                         public void handleEvent(Event e) {\r
1051                                 try {\r
1052                                         String newText = applyEventToString( text.getText(), e );\r
1053                                         Object value = binding.create( newText );\r
1054                                         binding.assertInstaceIsValid( value );\r
1055                                         text.setBackground(null);\r
1056                                 } catch (BindingException er) {\r
1057                                         Color error = new Color(text.getDisplay(), 255, 222, 222); \r
1058                                         text.setBackground(error);                                      \r
1059                                         error.dispose();\r
1060                                 }\r
1061                         }\r
1062                 });             \r
1063                 if (filesave|fileopen) {\r
1064                         final FileDialog fd = new FileDialog(parent.getShell(), filesave?SWT.SAVE:SWT.OPEN);\r
1065                                         \r
1066                         String filetypesStr = stringType.metadata.get("filetypes");\r
1067                         String fileextsStr = stringType.metadata.get("fileexts");\r
1068                         String name = getName(ref);\r
1069                         String[] filetypes = filetypesStr==null?null:(String[]) filetypesStr.split(","); \r
1070                         String[] fileexts = fileextsStr==null?null:(String[]) fileextsStr.split(",");                                   \r
1071                         fd.setFilterNames(filetypes);\r
1072                         fd.setFilterExtensions(fileexts);\r
1073                         \r
1074                         boolean nameMatchesExt = false;\r
1075                         if ( name!=null && !name.isEmpty() ) {\r
1076                                 for (String fileext : fileexts) {\r
1077                                         nameMatchesExt |= StringUtil.simplePatternMatch(name, fileext) && !name.contains(" ");\r
1078                                 }\r
1079                         }\r
1080                         final String initialName = nameMatchesExt?name:null;\r
1081                         \r
1082                         Button chooseFileButton = new Button(parent, SWT.PUSH);\r
1083                         chooseFileButton.setText("Select");\r
1084                         chooseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));\r
1085                         chooseFileButton.addSelectionListener(new SelectionAdapter() {\r
1086                                 public void widgetSelected(SelectionEvent e) {\r
1087                                         String name = text.getText();\r
1088                                         if ( name == null || name.isEmpty() ) name = initialName;\r
1089                                         if ( name!=null ) fd.setFileName( name );\r
1090                                         String result = fd.open();\r
1091                                         if (result != null)\r
1092                                                 text.setText(result);\r
1093                                 }\r
1094                         });\r
1095                 }\r
1096 \r
1097                 if (directory) {\r
1098                         final DirectoryDialog fd = new DirectoryDialog(parent.getShell(), 0);\r
1099                         String name = getName(ref);\r
1100                         fd.setMessage( name );\r
1101                         Button chooseDirButton = new Button(parent, SWT.PUSH);\r
1102                         chooseDirButton.setText("Select");\r
1103                         chooseDirButton.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));\r
1104                         chooseDirButton.addSelectionListener(new SelectionAdapter() {\r
1105                                 public void widgetSelected(SelectionEvent e) {\r
1106                                         String dir = text.getText();                                    \r
1107                                         fd.setFilterPath(dir);\r
1108                                         String result = fd.open();\r
1109                                         if (result != null)\r
1110                                                 text.setText(result);\r
1111                                 }\r
1112                         });\r
1113                 }\r
1114         }\r
1115 \r
1116         static String appendName(String ref, String name)\r
1117         {\r
1118                 return ref+"/"+URIUtil.encodeURI(name);\r
1119         }\r
1120         \r
1121         static String getName(String ref)\r
1122         {\r
1123                 if ( ref==null ) return null;\r
1124                 int i = ref.lastIndexOf('/');\r
1125                 if (i<0) return URIUtil.decodeURI(ref);\r
1126                 String namePart = ref.substring(i+1);\r
1127                 return URIUtil.decodeURI(namePart);\r
1128         }\r
1129         \r
1130         static int getDepth(String ref)\r
1131         {\r
1132                 int depth = 0;\r
1133                 for (int i=0; i<ref.length(); i++) if ( ref.charAt(i)=='/' ) depth++;\r
1134                 return depth;\r
1135         }\r
1136         \r
1137         static boolean allBooleans(RecordType rt) {\r
1138                 for (Component c : rt.getComponents())\r
1139                         if ( c.type instanceof BooleanType == false ) return false;\r
1140                 return true;\r
1141         }\r
1142         \r
1143         static String print(RecordBinding recordBinding, Object value) {                \r
1144                 if ( allBooleans(recordBinding.type() ) ) {\r
1145                         StringBuilder sb = new StringBuilder();\r
1146                         int j = 0;\r
1147                         for ( int i = 0; i<recordBinding.getComponentCount(); i++ ) {\r
1148                                 try {\r
1149                                         boolean b = recordBinding.getBoolean(value, i);\r
1150                                         if ( !b ) continue;\r
1151                                         if ( j>0 ) sb.append(", ");\r
1152                                         sb.append(recordBinding.type().getComponent(i).name);\r
1153                                         j++;\r
1154                                 } catch (BindingException e) {\r
1155                                         continue;\r
1156                                 }                               \r
1157                         }\r
1158                         return sb.toString();\r
1159                 } else \r
1160                 try {\r
1161                         return recordBinding.toString(value, true);\r
1162                 } catch (BindingException e) {\r
1163                         return e.toString();\r
1164                 }\r
1165         }\r
1166         \r
1167         static Object parse(RecordBinding recordBinding, String txt) throws BindingException {\r
1168                 if ( allBooleans(recordBinding.type() ) ) {\r
1169                         Object result = recordBinding.createDefaultUnchecked();\r
1170                         String[] tokens = txt.split(", ");\r
1171                         for ( String token : tokens ) {\r
1172                                 if ( token.isEmpty() ) continue;\r
1173                                 int i = recordBinding.type().getComponentIndex2(token);\r
1174                                 if ( i>=0 ) {\r
1175                                         try {\r
1176                                                 recordBinding.setBoolean(result, i, true);\r
1177                                         } catch (BindingException e) {\r
1178                                                 throw e;\r
1179                                         }\r
1180                                 } else {\r
1181                                         throw new BindingException("There is no field \""+token+"\"");\r
1182                                 }\r
1183                         }\r
1184                         return result;\r
1185                 } else {\r
1186                         try {\r
1187                                 return recordBinding.parseValueDefinition(txt);\r
1188                         } catch (DataTypeSyntaxError e) {\r
1189                                 throw new BindingException(e);\r
1190                         }\r
1191                         \r
1192                 }\r
1193         }\r
1194         \r
1195         static {\r
1196             PASSWORD = new StringType();\r
1197             PASSWORD.metadata.put("style", "password");\r
1198             \r
1199             TEXTBOX = new StringType();\r
1200             TEXTBOX.metadata.put("style", "multi");\r
1201         }\r
1202                 \r
1203 }\r