-package org.simantics.databoard.forms;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.eclipse.jface.window.Window;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.CTabFolder;\r
-import org.eclipse.swt.custom.CTabItem;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Button;\r
-import org.eclipse.swt.widgets.Combo;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.DirectoryDialog;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.FileDialog;\r
-import org.eclipse.swt.widgets.Group;\r
-import org.eclipse.swt.widgets.Label;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.swt.widgets.Text;\r
-import org.simantics.databoard.Accessors;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.accessor.Accessor;\r
-import org.simantics.databoard.accessor.BooleanAccessor;\r
-import org.simantics.databoard.accessor.RecordAccessor;\r
-import org.simantics.databoard.accessor.StringAccessor;\r
-import org.simantics.databoard.accessor.UnionAccessor;\r
-import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
-import org.simantics.databoard.accessor.error.AccessorException;\r
-import org.simantics.databoard.accessor.error.ReferenceException;\r
-import org.simantics.databoard.accessor.reference.ChildReference;\r
-import org.simantics.databoard.accessor.reference.LabelReference;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.NumberBinding;\r
-import org.simantics.databoard.binding.RecordBinding;\r
-import org.simantics.databoard.binding.StringBinding;\r
-import org.simantics.databoard.binding.UnionBinding;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.mutable.TaggedObject;\r
-import org.simantics.databoard.parser.repository.DataTypeSyntaxError;\r
-import org.simantics.databoard.type.BooleanType;\r
-import org.simantics.databoard.type.Component;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.type.NumberType;\r
-import org.simantics.databoard.type.RecordType;\r
-import org.simantics.databoard.type.StringType;\r
-import org.simantics.databoard.type.UnionType;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.databoard.util.StringUtil;\r
-import org.simantics.databoard.util.URIUtil;\r
-\r
-/**\r
- * Databoard form creates SWT user interface from databoard record type.\r
- * \r
- * See DataboardFormExample for example usage.\r
- *\r
- * @author toni.kalajainen@semantum.fi\r
- */\r
-public class DataboardForm { \r
-\r
- public static final Datatype TEXTBOX;\r
- public static final Datatype PASSWORD;\r
- \r
- public int column1Width = -1;\r
- \r
- private RecordType allfields = new RecordType();\r
- \r
- /**\r
- * Make file type\r
- * \r
- * @param namesAndExts array of names and extensions\r
- * @param exts\r
- * @return\r
- */\r
- public static StringType fileSaveDialog(String...namesAndExts)\r
- { \r
- StringType result = new StringType();\r
- result.metadata.put("style", "filesave");\r
- \r
- StringBuilder sb1 = new StringBuilder();\r
- StringBuilder sb2 = new StringBuilder();\r
- \r
- for (int i=0; i<namesAndExts.length; i++) {\r
- StringBuilder sb = (i%2==0?sb1:sb2);\r
- int j = i/2;\r
- if (j>0) sb.append(','); \r
- sb.append(namesAndExts[i]);\r
- }\r
- \r
- result.metadata.put("filetypes", sb1.toString());\r
- result.metadata.put("fileexts", sb2.toString());\r
- return result;\r
- }\r
-\r
- /**\r
- * Make file type\r
- * \r
- * @param namesAndExts array of names and extensions\r
- * @param exts\r
- * @return\r
- */\r
- public static StringType fileOpenDialog(String...namesAndExts)\r
- { \r
- StringType result = new StringType();\r
- result.metadata.put("style", "fileopen");\r
- \r
- StringBuilder sb1 = new StringBuilder();\r
- StringBuilder sb2 = new StringBuilder();\r
- \r
- for (int i=0; i<namesAndExts.length; i++) {\r
- StringBuilder sb = (i%2==0?sb1:sb2);\r
- int j = i/2;\r
- if (j>0) sb.append(','); \r
- sb.append(namesAndExts[i]);\r
- }\r
- \r
- result.metadata.put("filetypes", sb1.toString());\r
- result.metadata.put("fileexts", sb2.toString());\r
- return result;\r
- }\r
- \r
- public static StringType directoryDialog()\r
- { \r
- StringType result = new StringType();\r
- result.metadata.put("style", "directory");\r
- return result;\r
- }\r
- \r
- public DataboardForm() {\r
- }\r
- \r
- public void setFirstColumnWidth(int width) {\r
- column1Width = width;\r
- }\r
- \r
- \r
- /**\r
- * Validate the fields for valid values.\r
- * StringTypes can be restricted with regular expressions.\r
- * NumberTypes with value ranges.\r
- * \r
- * @param composite\r
- * @return list of problems\r
- */\r
- public List<Problem> validate( Composite composite ) {\r
- List<Problem> result = new ArrayList<Problem>();\r
- _validateFields(composite, result);\r
- return result;\r
- }\r
- \r
- public static List<String> toStrings(List<Problem> problems) {\r
- List<String> result = new ArrayList<String>( problems.size() );\r
- for (Problem p : problems) result.add(p.error);\r
- return result;\r
- }\r
- \r
- public static class Problem extends Bean {\r
- /** Reference to the field with problem */\r
- public String fieldReference;\r
- /** The field with problem */\r
- public transient Control control;\r
- /** The validation error */\r
- public String error;\r
- }\r
-\r
- protected void _validateFields( Control control, List<Problem> result )\r
- {\r
- // Read this control\r
- Object data = control.getData();\r
- if ( data != null && data instanceof String ) {\r
- String refStr = (String) data;\r
- ChildReference ref = ChildReference.parsePath( refStr);\r
- if ( ref != null ) {\r
- try {\r
- Datatype fieldType = allfields.getChildType( ref );\r
- \r
- // Read Combo Union\r
- if ( fieldType instanceof UnionType && control instanceof Combo ) {\r
- // Nothing to validate\r
- } else\r
-\r
- // Read Radio Union\r
- if ( fieldType instanceof UnionType && control instanceof Composite ) {\r
- // Nothing to validate\r
- } else\r
- \r
- // Read Boolean\r
- if ( fieldType instanceof BooleanType && control instanceof Button ) {\r
- // Nothing to validate\r
- } else\r
-\r
- // Text + Dialog button\r
- if ( fieldType instanceof RecordType && control instanceof Text ) {\r
- try {\r
- Text text = (Text) control;\r
- RecordBinding fieldBinding = Bindings.getMutableBinding(fieldType);\r
- Object value = parse(fieldBinding, text.getText());\r
- fieldBinding.assertInstaceIsValid( value );\r
- } catch (BindingException er) {\r
- Problem problem = new Problem();\r
- if ( er.getCause()!=null ) {\r
- problem.error = er.getCause().getMessage();\r
- } else {\r
- problem.error = er.getMessage();\r
- }\r
- problem.fieldReference = refStr;\r
- problem.control = control;\r
- result.add( problem );\r
- } \r
- \r
- } else\r
- \r
- // Read Text\r
- if ( fieldType instanceof StringAccessor && control instanceof Text ) {\r
- try {\r
- Text text = (Text) control;\r
- StringBinding binding = Bindings.getBinding(fieldType);\r
- Object value = binding.create(text.getText());\r
- binding.assertInstaceIsValid( value );\r
- } catch (BindingException er) {\r
- Problem problem = new Problem();\r
- if ( er.getCause()!=null ) {\r
- problem.error = er.getCause().getMessage();\r
- } else {\r
- problem.error = er.getMessage();\r
- }\r
- problem.fieldReference = refStr;\r
- problem.control = control;\r
- result.add( problem );\r
- } \r
- } else\r
- \r
- // Read Numbers\r
- if ( fieldType instanceof NumberType && control instanceof Text ) {\r
- try {\r
- Text text = (Text) control;\r
- NumberBinding binding = Bindings.getBinding(fieldType);\r
- Object value = binding.create(text.getText());\r
- binding.assertInstaceIsValid( value );\r
- } catch (BindingException er) {\r
- Problem problem = new Problem();\r
- if ( er.getCause()!=null && er.getCause() instanceof NumberFormatException) {\r
- NumberFormatException nfe = (NumberFormatException) er.getCause();\r
- problem.error = nfe.getMessage();\r
- } else {\r
- problem.error = er.getMessage();\r
- }\r
- problem.fieldReference = refStr;\r
- problem.control = control;\r
- result.add( problem );\r
- } \r
- }\r
- \r
- } catch (AccessorConstructionException e) {\r
- Problem problem = new Problem();\r
- problem.error = e.getMessage();\r
- problem.fieldReference = refStr;\r
- problem.control = control;\r
- result.add( problem );\r
- }\r
- }\r
- }\r
- \r
- // Recursion\r
- if ( control instanceof Composite ) {\r
- Composite composite = (Composite) control;\r
- for (Control child : composite.getChildren()) \r
- {\r
- _validateFields(child, result);\r
- }\r
- }\r
- \r
- }\r
- \r
- public RecordType type() {\r
- return allfields;\r
- }\r
-\r
- /**\r
- * Find control by reference \r
- * @param control\r
- * @param ref\r
- * @return control or null\r
- */\r
- public Control getControl( Control control, ChildReference ref )\r
- {\r
- return getControl( control, ref.toPath() );\r
- }\r
- \r
- /**\r
- * Find control by reference. \r
- * \r
- * @param composite\r
- * @param ref\r
- * @return control or null\r
- */\r
- public Control getControl( Control control, String ref )\r
- {\r
- Object data = control.getData();\r
- if ( data != null && data instanceof String && data.equals(ref)) return control;\r
- \r
- // Recursion\r
- if ( control instanceof Composite ) {\r
- Composite composite = (Composite) control;\r
- for (Control child : composite.getChildren()) \r
- {\r
- Control result = getControl(child, ref);\r
- if ( result != null ) return result;\r
- }\r
- }\r
- return null;\r
- }\r
- \r
- /**\r
- * Reads values of fields into a record\r
- * \r
- * @param composite the composite that holds the widgets\r
- * @param binding record binding\r
- * @param dst the record where values are read to\r
- * @throws BindingException\r
- * @throws AccessorConstructionException \r
- * @throws AccessorException \r
- */\r
- public void readFields( Composite composite, RecordBinding binding, Object dst)\r
- throws BindingException, AccessorConstructionException, AccessorException\r
- {\r
- RecordAccessor ra = Accessors.getAccessor(binding, dst);\r
- _readFields(composite, ra);\r
- }\r
- \r
- protected void _readFields( Control control, RecordAccessor ra ) \r
- throws AccessorException, BindingException\r
- {\r
- // Read this control\r
- Object data = control.getData();\r
- if ( data != null && data instanceof String ) {\r
- ChildReference ref = ChildReference.parsePath( (String) data);\r
- if ( ref != null ) {\r
- try {\r
- Accessor fieldAccessor = ra.getComponent( ref );\r
- \r
- // Read Combo Union\r
- if ( fieldAccessor instanceof UnionAccessor && control instanceof Combo ) {\r
- UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
- Combo combo = (Combo) control;\r
- String text = combo.getText();\r
- int tag = sa.type().getComponentIndex2(text);\r
- Datatype tagType = sa.type().components[tag].type;\r
- Binding tagBinding = Bindings.getBinding(tagType);\r
- Object defaultValue = tagBinding.createDefault(); \r
- sa.setComponentValue(tag, tagBinding, defaultValue);\r
- } else\r
-\r
- // Read Radio Union\r
- if ( fieldAccessor instanceof UnionAccessor && control instanceof Composite ) {\r
- Composite radioComposite = (Composite) control;\r
- for (Control c : radioComposite.getChildren()) {\r
- if ( c instanceof Button && ((Button)c).getSelection() ) {\r
- Object data2 = c.getData();\r
- if (data2==null) continue;\r
- String name = getName( data2.toString() );\r
- if ( name==null ) continue;\r
- \r
- UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
- int tag = sa.type().getComponentIndex2( name );\r
- if ( tag>=0 ) {\r
- Datatype tagType = sa.type().components[tag].type;\r
- Binding tagBinding = Bindings.getBinding(tagType);\r
- Object defaultValue = tagBinding.createDefault(); \r
- sa.setComponentValue(tag, tagBinding, defaultValue);\r
- break;\r
- }\r
- }\r
- }\r
- } else\r
- \r
- // Read Boolean\r
- if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {\r
- BooleanAccessor sa = (BooleanAccessor) fieldAccessor;\r
- sa.setValue(((Button)control).getSelection());\r
- } else\r
-\r
- // Read Text + Dialog Button\r
- if ( fieldAccessor instanceof RecordAccessor && control instanceof Text ) {\r
- RecordAccessor raa = (RecordAccessor) fieldAccessor;\r
- Text text = (Text) control;\r
- RecordBinding fieldBinding = Bindings.getMutableBinding( raa.type() );\r
- Object value = parse( fieldBinding, text.getText() );\r
- raa.setValue(fieldBinding, value);\r
- } else\r
- \r
- // Read Text\r
- if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {\r
- StringAccessor sa = (StringAccessor) fieldAccessor;\r
- sa.setValue(((Text)control).getText());\r
- } else\r
- \r
- // Read Numbers\r
- if ( fieldAccessor.type() instanceof NumberType && control instanceof Text ) {\r
- NumberBinding binding = Bindings.getBinding( fieldAccessor.type() );\r
- Object value = binding.create( ((Text)control).getText() );\r
- fieldAccessor.setValue(binding, value);\r
- }\r
- \r
- } catch (AccessorConstructionException e) {\r
- //e.printStackTrace();\r
- }\r
- }\r
- }\r
- \r
- // Recursion\r
- if ( control instanceof Composite ) {\r
- Composite composite = (Composite) control;\r
- for (Control child : composite.getChildren()) \r
- {\r
- _readFields(child, ra);\r
- }\r
- }\r
- }\r
-\r
- public void writeFields( Composite composite, RecordBinding binding, Object src)\r
- throws AccessorException, BindingException, AccessorConstructionException\r
- {\r
- RecordAccessor ra = Accessors.getAccessor(binding, src);\r
- _writeFields(composite, ra);\r
- }\r
- \r
- void _writeFields( Control control, RecordAccessor ra )\r
- throws AccessorException, BindingException, AccessorConstructionException\r
- {\r
- // Read this control\r
- Object data = control.getData();\r
- if ( data != null && data instanceof String ) {\r
- ChildReference ref = ChildReference.parsePath( (String) data);\r
- if ( ref != null ) {\r
- try {\r
- Accessor fieldAccessor = ra.getComponent( ref );\r
- \r
- // Read Combo Union\r
- if ( fieldAccessor instanceof UnionAccessor && control instanceof Combo ) {\r
- UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
- Combo combo = (Combo) control;\r
- int tag = sa.getTag(); \r
- combo.setText( sa.type().getComponent(tag).name );\r
- } else\r
-\r
- // Read Radio Union\r
- if ( fieldAccessor instanceof UnionAccessor && control instanceof Composite) {\r
- Composite radioComposite = (Composite) control;\r
- UnionAccessor sa = (UnionAccessor) fieldAccessor;\r
- int tag = sa.getTag();\r
- for (int i=0; i<sa.count(); i++) {\r
- Button button = (Button) radioComposite.getChildren()[i*2];\r
- button.setSelection(i==tag);\r
- }\r
- } else\r
- \r
- // Read Boolean\r
- if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {\r
- BooleanAccessor sa = (BooleanAccessor) fieldAccessor;\r
- ((Button)control).setSelection(sa.getValue());\r
- } else\r
-\r
- // Write Text + Dialog Selection\r
- if ( fieldAccessor instanceof RecordAccessor && control instanceof Text ) {\r
- RecordAccessor raa = (RecordAccessor) fieldAccessor;\r
- Text text = (Text) control;\r
- RecordBinding fieldBinding = Bindings.getMutableBinding( raa.type() );\r
- String str = print( fieldBinding, raa.getValue(fieldBinding) ); \r
- text.setText( str );\r
- } else\r
- \r
- // Read Text\r
- if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {\r
- StringAccessor sa = (StringAccessor) fieldAccessor;\r
- ((Text)control).setText( sa.getValue() );\r
- } else\r
- \r
- // Read Numbers\r
- if ( fieldAccessor.type() instanceof NumberType && control instanceof Text ) {\r
- NumberBinding binding = Bindings.getBinding( fieldAccessor.type() );\r
- Object value = fieldAccessor.getValue(binding);\r
- ((Text)control).setText( binding.toString(value, true) );\r
- }\r
- \r
- } catch (AccessorConstructionException e) {\r
- //e.printStackTrace();\r
- }\r
- }\r
- }\r
- \r
- // Recursion\r
- if ( control instanceof Composite ) {\r
- Composite composite = (Composite) control;\r
- for (Control child : composite.getChildren()) \r
- {\r
- _writeFields(child, ra);\r
- }\r
- }\r
- \r
- }\r
- \r
- public void clear( Control control ) \r
- { \r
- _clearFields( control );\r
- allfields.clear();\r
- }\r
-\r
- protected void _clearFields( Control control ) \r
- { \r
- // Recursion\r
- if ( control instanceof Composite ) {\r
- Composite composite = (Composite) control;\r
- for (Control child : composite.getChildren()) \r
- {\r
- _clearFields(child);\r
- child.dispose();\r
- }\r
- }\r
-\r
- }\r
- \r
- /**\r
- * Add a listener to all the controls that represent the data type.\r
- * \r
- * @param composite the composite that holds the widgets\r
- * @param binding record binding\r
- * @param dst the record where values are read to\r
- * @throws BindingException\r
- * @throws AccessorConstructionException \r
- * @throws AccessorException \r
- */\r
- public void addListener( Composite composite, RecordType type, Listener listener )\r
- throws BindingException, AccessorConstructionException, AccessorException\r
- {\r
- _addListener(composite, type, listener );\r
- }\r
- \r
- protected void _addListener( Control control, Datatype type, Listener listener ) \r
- throws AccessorException, BindingException\r
- {\r
- // Read this control\r
- Object data = control.getData();\r
- ChildReference ref = null;\r
- if ( data != null && data instanceof String ) {\r
- ref = ChildReference.parsePath( (String) data);\r
- }\r
- \r
- try { \r
- Datatype fieldType = ref==null ? type : type.getChildType( ref );\r
-\r
- // Read Combo Union\r
- if ( fieldType instanceof UnionType && control instanceof Combo ) {\r
- control.addListener(SWT.Selection, listener);\r
- } else\r
- // Read Radio Union\r
- if ( fieldType instanceof UnionType && control instanceof Composite ) {\r
- Composite radioComposite = (Composite) control;\r
- for (Control c : radioComposite.getChildren()) {\r
- if ( c instanceof Button ) {\r
- c.addListener(SWT.Selection, listener);\r
- }\r
- }\r
- } else\r
- \r
- // Read Boolean\r
- if ( fieldType instanceof BooleanType && control instanceof Button ) {\r
- control.addListener(SWT.Selection, listener);\r
- } else\r
- \r
- // Read Text\r
- if ( fieldType instanceof StringType && control instanceof Text ) {\r
- control.addListener(SWT.Modify, listener);\r
- } else\r
- \r
- // Read Numbers\r
- if ( fieldType instanceof NumberType && control instanceof Text ) {\r
- control.addListener(SWT.Modify, listener);\r
- }\r
- \r
- } catch (ReferenceException re) {\r
- }\r
- \r
- // Recursion\r
- if ( control instanceof Composite ) {\r
- Composite composite = (Composite) control;\r
- for (Control child : composite.getChildren()) \r
- {\r
- _addListener(child, type, listener);\r
- }\r
- }\r
- }\r
- \r
- public void addField( Composite parent, String name, Datatype fieldType )\r
- {\r
- addField(parent, fieldType, URIUtil.encodeURI(name), null);\r
- allfields.addComponent(name, fieldType);\r
- }\r
- \r
- public void addField( Composite parent, String name, Datatype fieldType, String ref )\r
- {\r
- addField(parent, fieldType, appendName(ref, name), null);\r
- \r
- RecordType root = allfields;\r
- if ( ref != null && !ref.isEmpty() ) {\r
- // find deeper root\r
- ChildReference path = ChildReference.parsePath(ref);\r
- while ( path!=null ) {\r
- if ( path instanceof LabelReference == false ) {\r
- throw new RuntimeException( "blaah" ); \r
- }\r
- LabelReference lr = (LabelReference) path;\r
- String label = lr.label;\r
- \r
- if ( root.hasComponent(label) ) {\r
- root = (RecordType) root.getComponent(label).type;\r
- } else {\r
- RecordType rt = new RecordType();\r
- root.addComponent(label, rt);\r
- root = rt;\r
- }\r
- path = path.childReference;\r
- }\r
- }\r
- if ( !root.hasComponent(name) ) root.addComponent(name, fieldType); \r
- }\r
- \r
- \r
- public void addFields( Composite parent, RecordType source ) \r
- {\r
- for (Component component : source.getComponents()) \r
- addField( parent, component.name, component.type );\r
- }\r
- \r
- public void addFields( Composite parent, RecordType source, String ref ) \r
- {\r
- for (Component component : source.getComponents()) \r
- addField( parent, component.name, component.type, ref );\r
- }\r
- \r
- \r
- public void addField( Composite parent, Datatype fieldType, String ref, GridData lblLayout )\r
- {\r
- if (lblLayout==null) {\r
- lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);\r
- if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;\r
- } \r
- String fieldName = getName(ref);\r
- \r
- if (fieldType instanceof StringType) {\r
- Label label = new Label(parent, 0);\r
- label.setText(fieldName + ":");\r
- label.setToolTipText(fieldName);\r
- label.setLayoutData( lblLayout );\r
-\r
- addString(parent, (StringType) fieldType, ref);\r
- \r
- } else if (fieldType instanceof BooleanType) {\r
-\r
- Label label = new Label(parent, 0);\r
- label.setLayoutData( lblLayout );\r
- \r
- addBoolean(parent, (BooleanType) fieldType, ref);\r
-\r
- } else if (fieldType instanceof NumberType) {\r
-\r
- Label label = new Label(parent, 0);\r
- label.setText(fieldName + ":");\r
- label.setLayoutData( lblLayout );\r
-\r
- addNumber(parent, (NumberType) fieldType, ref);\r
-\r
- } else if (fieldType instanceof RecordType) {\r
- RecordType record = (RecordType) fieldType;\r
- String options = record.metadata.get("style");\r
- boolean dialog = options==null?false:options.contains("dialog");\r
- boolean tabbed = options==null?false:options.contains("tabbed");\r
- \r
- // Method 0: Tabbed, each field is a tab page\r
- if ( tabbed ) {\r
- Label label = new Label(parent, 0);\r
- label.setText(fieldName + ":");\r
- label.setLayoutData( lblLayout );\r
- \r
- CTabFolder folder = new CTabFolder(parent, SWT.TOP | SWT.BORDER);\r
- //folder.setUnselectedCloseVisible(false);\r
- folder.setSimple(false);\r
- folder.setLayout( new GridLayout(3, false) ); \r
- folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));\r
- \r
- for (int i=0; i<record.getComponentCount(); i++) {\r
- String childName = record.getComponent(i).name;\r
- Datatype childType = record.getComponentType(i);\r
- String childRef = appendName(ref, childName);\r
- if (i>0) new Label(parent, 0);\r
- \r
- CTabItem item = new CTabItem(folder, SWT.NONE);\r
- item.setText(childName);\r
- Composite composite = new Composite(folder, 0);\r
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));\r
- composite.setLayout( new GridLayout(3, false) );\r
- composite.setData(ref);\r
- \r
- if ( childType instanceof RecordType ) {\r
- addRecord( composite, (RecordType)childType, childRef); \r
- } else {\r
- addWidget( composite, childType, childRef );\r
- }\r
- \r
- item.setControl( composite );\r
- } \r
- folder.setSelection(0);\r
-\r
- } else\r
- \r
- // Method 1: Dialog = Label + Text + [Button]\r
- if ( dialog ) {\r
- Label label = new Label(parent, 0);\r
- label.setText(fieldName + ":");\r
- label.setLayoutData( lblLayout );\r
- \r
- final String title = fieldName;\r
- final Shell shell = parent.getShell();\r
- final RecordBinding fieldBinding = Bindings.getMutableBinding( fieldType );\r
- final Object fieldValue = fieldBinding.createDefaultUnchecked();\r
- final Text text = new Text(parent, SWT.BORDER);\r
- final Button select = new Button(parent, SWT.PUSH);\r
- text.setLayoutData( new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1 ) );\r
- text.setText( print(fieldBinding, fieldValue) );\r
- text.setData(ref); \r
- text.addListener(SWT.Verify, new Listener() {\r
- public void handleEvent(Event e) {\r
- try {\r
- String newText = applyEventToString( text.getText(), e );\r
- Object value = parse(fieldBinding, newText);\r
- fieldBinding.assertInstaceIsValid( value );\r
- text.setBackground(null);\r
- } catch (BindingException er) {\r
- Color error = new Color(text.getDisplay(), 255, 222, 222); \r
- text.setBackground(error); \r
- error.dispose();\r
- }\r
- }\r
- }); \r
- \r
- //text.setEditable( false );\r
- select.setText("Select");\r
- select.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));\r
- select.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- Object initialValue;\r
- try {\r
- initialValue = parse(fieldBinding, text.getText());\r
- } catch (BindingException e1) {\r
- initialValue = fieldBinding.createDefaultUnchecked();\r
- }\r
- DataboardDialog dialog = new DataboardDialog(\r
- shell,\r
- title, \r
- fieldBinding, \r
- initialValue);\r
- \r
- int code = dialog.open();\r
- if ( code == Window.OK ) {\r
- Object result = dialog.getResult();\r
- String str = print(fieldBinding, result);\r
- text.setText( str );\r
- }\r
- }\r
- });\r
- \r
- } else \r
-\r
- // Method 2: Label + composite\r
- if ( allBooleans(record) ) { \r
- Label label = new Label(parent, 0);\r
- label.setText(fieldName + ":");\r
- label.setLayoutData( lblLayout );\r
- \r
- for (int i=0; i<record.getComponentCount(); i++) {\r
- String childName = record.getComponent(i).name;\r
- Datatype childType = record.getComponentType(i);\r
- String childRef = appendName(ref, childName);\r
- if (i>0) new Label(parent, 0);\r
- addWidget( parent, childType, childRef );\r
- } \r
- \r
- } \r
- else\r
- \r
- // Method 3: Groups\r
- {\r
- Group group = new Group(parent, 0);\r
- group.setText(fieldName);\r
- group.setLayout( new GridLayout(3, false) ); \r
- group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));\r
- group.setData(ref);\r
- addRecord(group, record, ref);\r
- }\r
- \r
- } else if (fieldType instanceof UnionType) {\r
- Label label = new Label(parent, 0);\r
- label.setText(fieldName + ":");\r
- label.setLayoutData( lblLayout );\r
- addUnion( parent, (UnionType) fieldType, ref );\r
- }\r
- \r
- }\r
-\r
- protected void addWidget(Composite parent, Datatype fieldType, String ref) {\r
- if (fieldType instanceof StringType) {\r
- addString(parent, (StringType) fieldType, ref);\r
- } else if (fieldType instanceof BooleanType) {\r
- addBoolean(parent, (BooleanType) fieldType, ref);\r
- } else if (fieldType instanceof NumberType) {\r
- addNumber(parent, (NumberType) fieldType, ref);\r
- } else if (fieldType instanceof RecordType) {\r
- RecordType rt = (RecordType) fieldType;\r
- Group group = new Group(parent, 0);\r
- String name = getName(ref);\r
- group.setText(name);\r
- group.setLayout( new GridLayout(3, false) ); \r
- group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));\r
- group.setData(ref);\r
- addRecord(group, rt, ref);\r
- } else if (fieldType instanceof UnionType) {\r
- addUnion( parent, (UnionType) fieldType, ref );\r
- }\r
- }\r
- \r
- public CTabFolder addTabFolder( Composite parent, RecordType record, String ref )\r
- {\r
- CTabFolder folder = new CTabFolder(parent, SWT.TOP | SWT.BORDER);\r
- folder.setSimple(false);\r
- folder.setLayout( new GridLayout(3, false) ); \r
- folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));\r
- \r
- for (int i=0; i<record.getComponentCount(); i++) {\r
- String childName = record.getComponent(i).name;\r
- Datatype childType = record.getComponentType(i);\r
- String childRef = appendName(ref, childName);\r
- if (i>0) new Label(parent, 0);\r
- \r
- CTabItem item = new CTabItem(folder, SWT.NONE);\r
- item.setText(childName);\r
- Composite composite = new Composite(folder, 0);\r
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));\r
- composite.setLayout( new GridLayout(3, false) );\r
- composite.setData(ref);\r
- \r
- if ( childType instanceof RecordType ) {\r
- addRecord( composite, (RecordType)childType, childRef); \r
- } else {\r
- addWidget( composite, childType, childRef );\r
- }\r
- \r
- item.setControl( composite );\r
- allfields.addComponent(childName, childType);\r
- } \r
- folder.setSelection(0);\r
- return folder;\r
- \r
- }\r
- \r
- protected void addRecord( Composite parent, RecordType record, String ref )\r
- {\r
- String options = record.metadata.get("style");\r
- boolean dialog = options==null?false:options.contains("dialog");\r
- boolean tabbed = options==null?false:options.contains("tabbed");\r
- \r
- // Method 0: Tabbed, each field is a tab page\r
- if ( tabbed ) {\r
- addTabFolder( parent, record, ref );\r
- return;\r
- }\r
- \r
- // Normal Record\r
- GridData lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);\r
- if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;\r
- \r
- for (int i=0; i<record.getComponentCount(); i++) {\r
- String fieldName = record.getComponent(i).name;\r
- Datatype fieldType = record.getComponentType(i);\r
- String fieldRef = appendName(ref, fieldName);\r
- addField( parent, fieldType, fieldRef, lblLayout);\r
- } \r
- return;\r
- }\r
- \r
- protected void addUnion( Composite parent, UnionType union, String ref )\r
- {\r
- if ( union.isEnumeration() ) {\r
- addEnum( parent, union, ref );\r
- } else {\r
- addRadio( parent, union, ref );\r
- } \r
- }\r
- \r
- protected void addEnum( Composite parent, UnionType union, String ref )\r
- {\r
- Combo combo = new Combo(parent, SWT.READ_ONLY);\r
- String[] items = new String[union.getComponentCount()];\r
- for (int i = 0; i < items.length; i++) {\r
- items[i] = union.getComponent(i).name;\r
- }\r
- combo.setItems(items);\r
- combo.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
- combo.setData(ref);\r
- \r
- // Set default value\r
- UnionBinding binding = Bindings.getBinding(union);\r
- try {\r
- TaggedObject defaultOption = (TaggedObject) binding.createDefault();\r
- combo.setText( items[ defaultOption.tag ] );\r
- } catch (BindingException e) {\r
- } \r
- }\r
-\r
- protected void addRadio( Composite parent, UnionType union, String ref )\r
- {\r
- Composite composite = new Composite(parent, 0);\r
- composite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
- composite.setLayout( new GridLayout(3, false) );\r
- composite.setData(ref);\r
- final int count = union.getComponentCount();\r
- final Composite panels[] = new Composite[count];\r
- final Button buttons[] = new Button[count];\r
- for ( int i=0; i<count; i++ ) {\r
- Component component = union.getComponent(i);\r
- String childRef = ref+"/"+URIUtil.encodeURI(component.name);\r
- Button b = buttons[i] = new Button(composite, SWT.RADIO);\r
- b.setLayoutData(new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1));\r
- b.setText(component.name);\r
- b.setData(childRef);\r
- \r
- String options = union.metadata.get("style");\r
- boolean border = options==null?true:!options.contains("no-border");\r
- int style = 0; \r
- if (border) style |= SWT.BORDER;\r
- \r
- Composite panel = panels[i] = new Composite(composite, style);\r
- panel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
- panel.setLayout( new GridLayout(3, false) );\r
- panel.setData(childRef);\r
- \r
- Datatype componentType = union.getComponentType(i);\r
- if ( componentType instanceof RecordType ) {\r
- addRecord(panel, (RecordType) componentType, childRef);\r
- } else {\r
- addWidget(panel, componentType, childRef);\r
- } \r
- }\r
- \r
- // Set default value\r
- UnionBinding binding = Bindings.getBinding(union);\r
- try {\r
- TaggedObject defaultOption = (TaggedObject) binding.createDefault();\r
- buttons[defaultOption.tag].setSelection(true);\r
- } catch (BindingException e) {\r
- } \r
- \r
- }\r
- \r
- protected void addNumber( Composite parent, NumberType number, String ref )\r
- {\r
- String unit = number.getUnit();\r
- String options = number.metadata.get("style");\r
- boolean border = options==null?true:!options.contains("no-border");\r
- int style = 0; \r
- if (border) style |= SWT.BORDER;\r
- final Text text = new Text(parent, style);\r
- text.setData(ref);\r
- text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, unit==null?2:1, 1));\r
- \r
- // Set default value\r
- final NumberBinding binding = Bindings.getBinding( number );\r
- try {\r
- text.setText( binding.createDefault().toString() );\r
- } catch (BindingException e) {\r
- }\r
- \r
- // Add validator\r
- text.addListener(SWT.Verify, new Listener() {\r
- public void handleEvent(Event e) {\r
- try {\r
- String newText = applyEventToString( text.getText(), e );\r
- Object value = binding.create( newText );\r
- binding.assertInstaceIsValid( value );\r
- text.setBackground(null); \r
- } catch (BindingException er) {\r
- Color error = new Color(text.getDisplay(), 255, 222, 222); \r
- text.setBackground(error);\r
- error.dispose(); \r
- }\r
- }});\r
- \r
- if ( unit!=null ) {\r
- Label unitLabel = new Label(parent, 0);\r
- unitLabel.setText(unit);\r
- }\r
- }\r
- \r
- static String applyEventToString(String orig, Event e) {\r
- if (e.character==8) {\r
- return orig.substring(0, e.start) + orig.substring(e.end, orig.length());\r
- }\r
- return orig.substring(0, e.start) + e.text + orig.substring(e.end, orig.length()); \r
- }\r
- \r
- protected void addBoolean( Composite parent, BooleanType booleanType, String ref )\r
- {\r
- Button button = new Button(parent, SWT.CHECK);\r
- button.setText( getName(ref) );\r
- button.setData(ref);\r
- button.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));\r
- }\r
- \r
- protected void addString( Composite parent, StringType stringType, String ref )\r
- { \r
- String options = stringType.metadata.get("style");\r
- boolean password = options==null?false:options.contains("password");\r
- boolean filesave = options==null?false:options.contains("filesave");\r
- boolean fileopen = options==null?false:options.contains("fileopen");\r
- boolean directory = options==null?false:options.contains("directory");\r
- boolean multi = options==null?false:options.contains("multi");\r
- boolean border = options==null?true:!options.contains("no-border");\r
-\r
- int style = 0;\r
- if (password) style |= SWT.PASSWORD;\r
- if (multi) style |= SWT.MULTI;\r
- if (border) style |= SWT.BORDER;\r
- final Text text = new Text(parent, style);\r
- text.setLayoutData( new GridData(SWT.FILL, multi?SWT.FILL:SWT.BEGINNING, true, false, filesave|fileopen|directory?1:2, 1 ) );\r
- text.setData(ref);\r
-\r
- // Set default value\r
- final StringBinding binding = Bindings.getBinding( stringType );\r
- try {\r
- text.setText( binding.createDefault().toString() );\r
- } catch (BindingException e) {\r
- }\r
- \r
- text.addListener(SWT.Verify, new Listener() {\r
- public void handleEvent(Event e) {\r
- try {\r
- String newText = applyEventToString( text.getText(), e );\r
- Object value = binding.create( newText );\r
- binding.assertInstaceIsValid( value );\r
- text.setBackground(null);\r
- } catch (BindingException er) {\r
- Color error = new Color(text.getDisplay(), 255, 222, 222); \r
- text.setBackground(error); \r
- error.dispose();\r
- }\r
- }\r
- }); \r
- if (filesave|fileopen) {\r
- final FileDialog fd = new FileDialog(parent.getShell(), filesave?SWT.SAVE:SWT.OPEN);\r
- \r
- String filetypesStr = stringType.metadata.get("filetypes");\r
- String fileextsStr = stringType.metadata.get("fileexts");\r
- String name = getName(ref);\r
- String[] filetypes = filetypesStr==null?null:(String[]) filetypesStr.split(","); \r
- String[] fileexts = fileextsStr==null?null:(String[]) fileextsStr.split(","); \r
- fd.setFilterNames(filetypes);\r
- fd.setFilterExtensions(fileexts);\r
- \r
- boolean nameMatchesExt = false;\r
- if ( name!=null && !name.isEmpty() ) {\r
- for (String fileext : fileexts) {\r
- nameMatchesExt |= StringUtil.simplePatternMatch(name, fileext) && !name.contains(" ");\r
- }\r
- }\r
- final String initialName = nameMatchesExt?name:null;\r
- \r
- Button chooseFileButton = new Button(parent, SWT.PUSH);\r
- chooseFileButton.setText("Select");\r
- chooseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));\r
- chooseFileButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- String name = text.getText();\r
- if ( name == null || name.isEmpty() ) name = initialName;\r
- if ( name!=null ) fd.setFileName( name );\r
- String result = fd.open();\r
- if (result != null)\r
- text.setText(result);\r
- }\r
- });\r
- }\r
-\r
- if (directory) {\r
- final DirectoryDialog fd = new DirectoryDialog(parent.getShell(), 0);\r
- String name = getName(ref);\r
- fd.setMessage( name );\r
- Button chooseDirButton = new Button(parent, SWT.PUSH);\r
- chooseDirButton.setText("Select");\r
- chooseDirButton.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));\r
- chooseDirButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- String dir = text.getText(); \r
- fd.setFilterPath(dir);\r
- String result = fd.open();\r
- if (result != null)\r
- text.setText(result);\r
- }\r
- });\r
- }\r
- }\r
-\r
- static String appendName(String ref, String name)\r
- {\r
- return ref+"/"+URIUtil.encodeURI(name);\r
- }\r
- \r
- static String getName(String ref)\r
- {\r
- if ( ref==null ) return null;\r
- int i = ref.lastIndexOf('/');\r
- if (i<0) return URIUtil.decodeURI(ref);\r
- String namePart = ref.substring(i+1);\r
- return URIUtil.decodeURI(namePart);\r
- }\r
- \r
- static int getDepth(String ref)\r
- {\r
- int depth = 0;\r
- for (int i=0; i<ref.length(); i++) if ( ref.charAt(i)=='/' ) depth++;\r
- return depth;\r
- }\r
- \r
- static boolean allBooleans(RecordType rt) {\r
- for (Component c : rt.getComponents())\r
- if ( c.type instanceof BooleanType == false ) return false;\r
- return true;\r
- }\r
- \r
- static String print(RecordBinding recordBinding, Object value) { \r
- if ( allBooleans(recordBinding.type() ) ) {\r
- StringBuilder sb = new StringBuilder();\r
- int j = 0;\r
- for ( int i = 0; i<recordBinding.getComponentCount(); i++ ) {\r
- try {\r
- boolean b = recordBinding.getBoolean(value, i);\r
- if ( !b ) continue;\r
- if ( j>0 ) sb.append(", ");\r
- sb.append(recordBinding.type().getComponent(i).name);\r
- j++;\r
- } catch (BindingException e) {\r
- continue;\r
- } \r
- }\r
- return sb.toString();\r
- } else \r
- try {\r
- return recordBinding.toString(value, true);\r
- } catch (BindingException e) {\r
- return e.toString();\r
- }\r
- }\r
- \r
- static Object parse(RecordBinding recordBinding, String txt) throws BindingException {\r
- if ( allBooleans(recordBinding.type() ) ) {\r
- Object result = recordBinding.createDefaultUnchecked();\r
- String[] tokens = txt.split(", ");\r
- for ( String token : tokens ) {\r
- if ( token.isEmpty() ) continue;\r
- int i = recordBinding.type().getComponentIndex2(token);\r
- if ( i>=0 ) {\r
- try {\r
- recordBinding.setBoolean(result, i, true);\r
- } catch (BindingException e) {\r
- throw e;\r
- }\r
- } else {\r
- throw new BindingException("There is no field \""+token+"\"");\r
- }\r
- }\r
- return result;\r
- } else {\r
- try {\r
- return recordBinding.parseValueDefinition(txt);\r
- } catch (DataTypeSyntaxError e) {\r
- throw new BindingException(e);\r
- }\r
- \r
- }\r
- }\r
- \r
- static {\r
- PASSWORD = new StringType();\r
- PASSWORD.metadata.put("style", "password");\r
- \r
- TEXTBOX = new StringType();\r
- TEXTBOX.metadata.put("style", "multi");\r
- }\r
- \r
-}\r
+package org.simantics.databoard.forms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.simantics.databoard.Accessors;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.accessor.Accessor;
+import org.simantics.databoard.accessor.BooleanAccessor;
+import org.simantics.databoard.accessor.RecordAccessor;
+import org.simantics.databoard.accessor.StringAccessor;
+import org.simantics.databoard.accessor.UnionAccessor;
+import org.simantics.databoard.accessor.error.AccessorConstructionException;
+import org.simantics.databoard.accessor.error.AccessorException;
+import org.simantics.databoard.accessor.error.ReferenceException;
+import org.simantics.databoard.accessor.reference.ChildReference;
+import org.simantics.databoard.accessor.reference.LabelReference;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.NumberBinding;
+import org.simantics.databoard.binding.RecordBinding;
+import org.simantics.databoard.binding.StringBinding;
+import org.simantics.databoard.binding.UnionBinding;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.mutable.TaggedObject;
+import org.simantics.databoard.parser.repository.DataTypeSyntaxError;
+import org.simantics.databoard.type.BooleanType;
+import org.simantics.databoard.type.Component;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.type.NumberType;
+import org.simantics.databoard.type.RecordType;
+import org.simantics.databoard.type.StringType;
+import org.simantics.databoard.type.UnionType;
+import org.simantics.databoard.util.Bean;
+import org.simantics.databoard.util.StringUtil;
+import org.simantics.databoard.util.URIUtil;
+
+/**
+ * Databoard form creates SWT user interface from databoard record type.
+ *
+ * See DataboardFormExample for example usage.
+ *
+ * @author toni.kalajainen@semantum.fi
+ */
+public class DataboardForm {
+
+ public static final Datatype TEXTBOX;
+ public static final Datatype PASSWORD;
+
+ public int column1Width = -1;
+
+ private RecordType allfields = new RecordType();
+
+ /**
+ * Make file type
+ *
+ * @param namesAndExts array of names and extensions
+ * @param exts
+ * @return
+ */
+ public static StringType fileSaveDialog(String...namesAndExts)
+ {
+ StringType result = new StringType();
+ result.metadata.put("style", "filesave");
+
+ StringBuilder sb1 = new StringBuilder();
+ StringBuilder sb2 = new StringBuilder();
+
+ for (int i=0; i<namesAndExts.length; i++) {
+ StringBuilder sb = (i%2==0?sb1:sb2);
+ int j = i/2;
+ if (j>0) sb.append(',');
+ sb.append(namesAndExts[i]);
+ }
+
+ result.metadata.put("filetypes", sb1.toString());
+ result.metadata.put("fileexts", sb2.toString());
+ return result;
+ }
+
+ /**
+ * Make file type
+ *
+ * @param namesAndExts array of names and extensions
+ * @param exts
+ * @return
+ */
+ public static StringType fileOpenDialog(String...namesAndExts)
+ {
+ StringType result = new StringType();
+ result.metadata.put("style", "fileopen");
+
+ StringBuilder sb1 = new StringBuilder();
+ StringBuilder sb2 = new StringBuilder();
+
+ for (int i=0; i<namesAndExts.length; i++) {
+ StringBuilder sb = (i%2==0?sb1:sb2);
+ int j = i/2;
+ if (j>0) sb.append(',');
+ sb.append(namesAndExts[i]);
+ }
+
+ result.metadata.put("filetypes", sb1.toString());
+ result.metadata.put("fileexts", sb2.toString());
+ return result;
+ }
+
+ public static StringType directoryDialog()
+ {
+ StringType result = new StringType();
+ result.metadata.put("style", "directory");
+ return result;
+ }
+
+ public DataboardForm() {
+ }
+
+ public void setFirstColumnWidth(int width) {
+ column1Width = width;
+ }
+
+
+ /**
+ * Validate the fields for valid values.
+ * StringTypes can be restricted with regular expressions.
+ * NumberTypes with value ranges.
+ *
+ * @param composite
+ * @return list of problems
+ */
+ public List<Problem> validate( Composite composite ) {
+ List<Problem> result = new ArrayList<Problem>();
+ _validateFields(composite, result);
+ return result;
+ }
+
+ public static List<String> toStrings(List<Problem> problems) {
+ List<String> result = new ArrayList<String>( problems.size() );
+ for (Problem p : problems) result.add(p.error);
+ return result;
+ }
+
+ public static class Problem extends Bean {
+ /** Reference to the field with problem */
+ public String fieldReference;
+ /** The field with problem */
+ public transient Control control;
+ /** The validation error */
+ public String error;
+ }
+
+ protected void _validateFields( Control control, List<Problem> result )
+ {
+ // Read this control
+ Object data = control.getData();
+ if ( data != null && data instanceof String ) {
+ String refStr = (String) data;
+ ChildReference ref = ChildReference.parsePath( refStr);
+ if ( ref != null ) {
+ try {
+ Datatype fieldType = allfields.getChildType( ref );
+
+ // Read Combo Union
+ if ( fieldType instanceof UnionType && control instanceof Combo ) {
+ // Nothing to validate
+ } else
+
+ // Read Radio Union
+ if ( fieldType instanceof UnionType && control instanceof Composite ) {
+ // Nothing to validate
+ } else
+
+ // Read Boolean
+ if ( fieldType instanceof BooleanType && control instanceof Button ) {
+ // Nothing to validate
+ } else
+
+ // Text + Dialog button
+ if ( fieldType instanceof RecordType && control instanceof Text ) {
+ try {
+ Text text = (Text) control;
+ RecordBinding fieldBinding = Bindings.getMutableBinding(fieldType);
+ Object value = parse(fieldBinding, text.getText());
+ fieldBinding.assertInstaceIsValid( value );
+ } catch (BindingException er) {
+ Problem problem = new Problem();
+ if ( er.getCause()!=null ) {
+ problem.error = er.getCause().getMessage();
+ } else {
+ problem.error = er.getMessage();
+ }
+ problem.fieldReference = refStr;
+ problem.control = control;
+ result.add( problem );
+ }
+
+ } else
+
+ // Read Text
+ if ( fieldType instanceof StringAccessor && control instanceof Text ) {
+ try {
+ Text text = (Text) control;
+ StringBinding binding = Bindings.getBinding(fieldType);
+ Object value = binding.create(text.getText());
+ binding.assertInstaceIsValid( value );
+ } catch (BindingException er) {
+ Problem problem = new Problem();
+ if ( er.getCause()!=null ) {
+ problem.error = er.getCause().getMessage();
+ } else {
+ problem.error = er.getMessage();
+ }
+ problem.fieldReference = refStr;
+ problem.control = control;
+ result.add( problem );
+ }
+ } else
+
+ // Read Numbers
+ if ( fieldType instanceof NumberType && control instanceof Text ) {
+ try {
+ Text text = (Text) control;
+ NumberBinding binding = Bindings.getBinding(fieldType);
+ Object value = binding.create(text.getText());
+ binding.assertInstaceIsValid( value );
+ } catch (BindingException er) {
+ Problem problem = new Problem();
+ if ( er.getCause()!=null && er.getCause() instanceof NumberFormatException) {
+ NumberFormatException nfe = (NumberFormatException) er.getCause();
+ problem.error = nfe.getMessage();
+ } else {
+ problem.error = er.getMessage();
+ }
+ problem.fieldReference = refStr;
+ problem.control = control;
+ result.add( problem );
+ }
+ }
+
+ } catch (AccessorConstructionException e) {
+ Problem problem = new Problem();
+ problem.error = e.getMessage();
+ problem.fieldReference = refStr;
+ problem.control = control;
+ result.add( problem );
+ }
+ }
+ }
+
+ // Recursion
+ if ( control instanceof Composite ) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren())
+ {
+ _validateFields(child, result);
+ }
+ }
+
+ }
+
+ public RecordType type() {
+ return allfields;
+ }
+
+ /**
+ * Find control by reference
+ * @param control
+ * @param ref
+ * @return control or null
+ */
+ public Control getControl( Control control, ChildReference ref )
+ {
+ return getControl( control, ref.toPath() );
+ }
+
+ /**
+ * Find control by reference.
+ *
+ * @param composite
+ * @param ref
+ * @return control or null
+ */
+ public Control getControl( Control control, String ref )
+ {
+ Object data = control.getData();
+ if ( data != null && data instanceof String && data.equals(ref)) return control;
+
+ // Recursion
+ if ( control instanceof Composite ) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren())
+ {
+ Control result = getControl(child, ref);
+ if ( result != null ) return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Reads values of fields into a record
+ *
+ * @param composite the composite that holds the widgets
+ * @param binding record binding
+ * @param dst the record where values are read to
+ * @throws BindingException
+ * @throws AccessorConstructionException
+ * @throws AccessorException
+ */
+ public void readFields( Composite composite, RecordBinding binding, Object dst)
+ throws BindingException, AccessorConstructionException, AccessorException
+ {
+ RecordAccessor ra = Accessors.getAccessor(binding, dst);
+ _readFields(composite, ra);
+ }
+
+ protected void _readFields( Control control, RecordAccessor ra )
+ throws AccessorException, BindingException
+ {
+ // Read this control
+ Object data = control.getData();
+ if ( data != null && data instanceof String ) {
+ ChildReference ref = ChildReference.parsePath( (String) data);
+ if ( ref != null ) {
+ try {
+ Accessor fieldAccessor = ra.getComponent( ref );
+
+ // Read Combo Union
+ if ( fieldAccessor instanceof UnionAccessor && control instanceof Combo ) {
+ UnionAccessor sa = (UnionAccessor) fieldAccessor;
+ Combo combo = (Combo) control;
+ String text = combo.getText();
+ int tag = sa.type().getComponentIndex2(text);
+ Datatype tagType = sa.type().components[tag].type;
+ Binding tagBinding = Bindings.getBinding(tagType);
+ Object defaultValue = tagBinding.createDefault();
+ sa.setComponentValue(tag, tagBinding, defaultValue);
+ } else
+
+ // Read Radio Union
+ if ( fieldAccessor instanceof UnionAccessor && control instanceof Composite ) {
+ Composite radioComposite = (Composite) control;
+ for (Control c : radioComposite.getChildren()) {
+ if ( c instanceof Button && ((Button)c).getSelection() ) {
+ Object data2 = c.getData();
+ if (data2==null) continue;
+ String name = getName( data2.toString() );
+ if ( name==null ) continue;
+
+ UnionAccessor sa = (UnionAccessor) fieldAccessor;
+ int tag = sa.type().getComponentIndex2( name );
+ if ( tag>=0 ) {
+ Datatype tagType = sa.type().components[tag].type;
+ Binding tagBinding = Bindings.getBinding(tagType);
+ Object defaultValue = tagBinding.createDefault();
+ sa.setComponentValue(tag, tagBinding, defaultValue);
+ break;
+ }
+ }
+ }
+ } else
+
+ // Read Boolean
+ if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {
+ BooleanAccessor sa = (BooleanAccessor) fieldAccessor;
+ sa.setValue(((Button)control).getSelection());
+ } else
+
+ // Read Text + Dialog Button
+ if ( fieldAccessor instanceof RecordAccessor && control instanceof Text ) {
+ RecordAccessor raa = (RecordAccessor) fieldAccessor;
+ Text text = (Text) control;
+ RecordBinding fieldBinding = Bindings.getMutableBinding( raa.type() );
+ Object value = parse( fieldBinding, text.getText() );
+ raa.setValue(fieldBinding, value);
+ } else
+
+ // Read Text
+ if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {
+ StringAccessor sa = (StringAccessor) fieldAccessor;
+ sa.setValue(((Text)control).getText());
+ } else
+
+ // Read Numbers
+ if ( fieldAccessor.type() instanceof NumberType && control instanceof Text ) {
+ NumberBinding binding = Bindings.getBinding( fieldAccessor.type() );
+ Object value = binding.create( ((Text)control).getText() );
+ fieldAccessor.setValue(binding, value);
+ }
+
+ } catch (AccessorConstructionException e) {
+ //e.printStackTrace();
+ }
+ }
+ }
+
+ // Recursion
+ if ( control instanceof Composite ) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren())
+ {
+ _readFields(child, ra);
+ }
+ }
+ }
+
+ public void writeFields( Composite composite, RecordBinding binding, Object src)
+ throws AccessorException, BindingException, AccessorConstructionException
+ {
+ RecordAccessor ra = Accessors.getAccessor(binding, src);
+ _writeFields(composite, ra);
+ }
+
+ void _writeFields( Control control, RecordAccessor ra )
+ throws AccessorException, BindingException, AccessorConstructionException
+ {
+ // Read this control
+ Object data = control.getData();
+ if ( data != null && data instanceof String ) {
+ ChildReference ref = ChildReference.parsePath( (String) data);
+ if ( ref != null ) {
+ try {
+ Accessor fieldAccessor = ra.getComponent( ref );
+
+ // Read Combo Union
+ if ( fieldAccessor instanceof UnionAccessor && control instanceof Combo ) {
+ UnionAccessor sa = (UnionAccessor) fieldAccessor;
+ Combo combo = (Combo) control;
+ int tag = sa.getTag();
+ combo.setText( sa.type().getComponent(tag).name );
+ } else
+
+ // Read Radio Union
+ if ( fieldAccessor instanceof UnionAccessor && control instanceof Composite) {
+ Composite radioComposite = (Composite) control;
+ UnionAccessor sa = (UnionAccessor) fieldAccessor;
+ int tag = sa.getTag();
+ for (int i=0; i<sa.count(); i++) {
+ Button button = (Button) radioComposite.getChildren()[i*2];
+ button.setSelection(i==tag);
+ }
+ } else
+
+ // Read Boolean
+ if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {
+ BooleanAccessor sa = (BooleanAccessor) fieldAccessor;
+ ((Button)control).setSelection(sa.getValue());
+ } else
+
+ // Write Text + Dialog Selection
+ if ( fieldAccessor instanceof RecordAccessor && control instanceof Text ) {
+ RecordAccessor raa = (RecordAccessor) fieldAccessor;
+ Text text = (Text) control;
+ RecordBinding fieldBinding = Bindings.getMutableBinding( raa.type() );
+ String str = print( fieldBinding, raa.getValue(fieldBinding) );
+ text.setText( str );
+ } else
+
+ // Read Text
+ if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {
+ StringAccessor sa = (StringAccessor) fieldAccessor;
+ ((Text)control).setText( sa.getValue() );
+ } else
+
+ // Read Numbers
+ if ( fieldAccessor.type() instanceof NumberType && control instanceof Text ) {
+ NumberBinding binding = Bindings.getBinding( fieldAccessor.type() );
+ Object value = fieldAccessor.getValue(binding);
+ ((Text)control).setText( binding.toString(value, true) );
+ }
+
+ } catch (AccessorConstructionException e) {
+ //e.printStackTrace();
+ }
+ }
+ }
+
+ // Recursion
+ if ( control instanceof Composite ) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren())
+ {
+ _writeFields(child, ra);
+ }
+ }
+
+ }
+
+ public void clear( Control control )
+ {
+ _clearFields( control );
+ allfields.clear();
+ }
+
+ protected void _clearFields( Control control )
+ {
+ // Recursion
+ if ( control instanceof Composite ) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren())
+ {
+ _clearFields(child);
+ child.dispose();
+ }
+ }
+
+ }
+
+ /**
+ * Add a listener to all the controls that represent the data type.
+ *
+ * @param composite the composite that holds the widgets
+ * @param binding record binding
+ * @param dst the record where values are read to
+ * @throws BindingException
+ * @throws AccessorConstructionException
+ * @throws AccessorException
+ */
+ public void addListener( Composite composite, RecordType type, Listener listener )
+ throws BindingException, AccessorConstructionException, AccessorException
+ {
+ _addListener(composite, type, listener );
+ }
+
+ protected void _addListener( Control control, Datatype type, Listener listener )
+ throws AccessorException, BindingException
+ {
+ // Read this control
+ Object data = control.getData();
+ ChildReference ref = null;
+ if ( data != null && data instanceof String ) {
+ ref = ChildReference.parsePath( (String) data);
+ }
+
+ try {
+ Datatype fieldType = ref==null ? type : type.getChildType( ref );
+
+ // Read Combo Union
+ if ( fieldType instanceof UnionType && control instanceof Combo ) {
+ control.addListener(SWT.Selection, listener);
+ } else
+ // Read Radio Union
+ if ( fieldType instanceof UnionType && control instanceof Composite ) {
+ Composite radioComposite = (Composite) control;
+ for (Control c : radioComposite.getChildren()) {
+ if ( c instanceof Button ) {
+ c.addListener(SWT.Selection, listener);
+ }
+ }
+ } else
+
+ // Read Boolean
+ if ( fieldType instanceof BooleanType && control instanceof Button ) {
+ control.addListener(SWT.Selection, listener);
+ } else
+
+ // Read Text
+ if ( fieldType instanceof StringType && control instanceof Text ) {
+ control.addListener(SWT.Modify, listener);
+ } else
+
+ // Read Numbers
+ if ( fieldType instanceof NumberType && control instanceof Text ) {
+ control.addListener(SWT.Modify, listener);
+ }
+
+ } catch (ReferenceException re) {
+ }
+
+ // Recursion
+ if ( control instanceof Composite ) {
+ Composite composite = (Composite) control;
+ for (Control child : composite.getChildren())
+ {
+ _addListener(child, type, listener);
+ }
+ }
+ }
+
+ public void addField( Composite parent, String name, Datatype fieldType )
+ {
+ addField(parent, fieldType, URIUtil.encodeURI(name), null);
+ allfields.addComponent(name, fieldType);
+ }
+
+ public void addField( Composite parent, String name, Datatype fieldType, String ref )
+ {
+ addField(parent, fieldType, appendName(ref, name), null);
+
+ RecordType root = allfields;
+ if ( ref != null && !ref.isEmpty() ) {
+ // find deeper root
+ ChildReference path = ChildReference.parsePath(ref);
+ while ( path!=null ) {
+ if ( path instanceof LabelReference == false ) {
+ throw new RuntimeException( "blaah" );
+ }
+ LabelReference lr = (LabelReference) path;
+ String label = lr.label;
+
+ if ( root.hasComponent(label) ) {
+ root = (RecordType) root.getComponent(label).type;
+ } else {
+ RecordType rt = new RecordType();
+ root.addComponent(label, rt);
+ root = rt;
+ }
+ path = path.childReference;
+ }
+ }
+ if ( !root.hasComponent(name) ) root.addComponent(name, fieldType);
+ }
+
+
+ public void addFields( Composite parent, RecordType source )
+ {
+ for (Component component : source.getComponents())
+ addField( parent, component.name, component.type );
+ }
+
+ public void addFields( Composite parent, RecordType source, String ref )
+ {
+ for (Component component : source.getComponents())
+ addField( parent, component.name, component.type, ref );
+ }
+
+
+ public void addField( Composite parent, Datatype fieldType, String ref, GridData lblLayout )
+ {
+ if (lblLayout==null) {
+ lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);
+ if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;
+ }
+ String fieldName = getName(ref);
+
+ if (fieldType instanceof StringType) {
+ Label label = new Label(parent, 0);
+ label.setText(fieldName + ":");
+ label.setToolTipText(fieldName);
+ label.setLayoutData( lblLayout );
+
+ addString(parent, (StringType) fieldType, ref);
+
+ } else if (fieldType instanceof BooleanType) {
+
+ Label label = new Label(parent, 0);
+ label.setLayoutData( lblLayout );
+
+ addBoolean(parent, (BooleanType) fieldType, ref);
+
+ } else if (fieldType instanceof NumberType) {
+
+ Label label = new Label(parent, 0);
+ label.setText(fieldName + ":");
+ label.setLayoutData( lblLayout );
+
+ addNumber(parent, (NumberType) fieldType, ref);
+
+ } else if (fieldType instanceof RecordType) {
+ RecordType record = (RecordType) fieldType;
+ String options = record.metadata.get("style");
+ boolean dialog = options==null?false:options.contains("dialog");
+ boolean tabbed = options==null?false:options.contains("tabbed");
+
+ // Method 0: Tabbed, each field is a tab page
+ if ( tabbed ) {
+ Label label = new Label(parent, 0);
+ label.setText(fieldName + ":");
+ label.setLayoutData( lblLayout );
+
+ CTabFolder folder = new CTabFolder(parent, SWT.TOP | SWT.BORDER);
+ //folder.setUnselectedCloseVisible(false);
+ folder.setSimple(false);
+ folder.setLayout( new GridLayout(3, false) );
+ folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+
+ for (int i=0; i<record.getComponentCount(); i++) {
+ String childName = record.getComponent(i).name;
+ Datatype childType = record.getComponentType(i);
+ String childRef = appendName(ref, childName);
+ if (i>0) new Label(parent, 0);
+
+ CTabItem item = new CTabItem(folder, SWT.NONE);
+ item.setText(childName);
+ Composite composite = new Composite(folder, 0);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ composite.setLayout( new GridLayout(3, false) );
+ composite.setData(ref);
+
+ if ( childType instanceof RecordType ) {
+ addRecord( composite, (RecordType)childType, childRef);
+ } else {
+ addWidget( composite, childType, childRef );
+ }
+
+ item.setControl( composite );
+ }
+ folder.setSelection(0);
+
+ } else
+
+ // Method 1: Dialog = Label + Text + [Button]
+ if ( dialog ) {
+ Label label = new Label(parent, 0);
+ label.setText(fieldName + ":");
+ label.setLayoutData( lblLayout );
+
+ final String title = fieldName;
+ final Shell shell = parent.getShell();
+ final RecordBinding fieldBinding = Bindings.getMutableBinding( fieldType );
+ final Object fieldValue = fieldBinding.createDefaultUnchecked();
+ final Text text = new Text(parent, SWT.BORDER);
+ final Button select = new Button(parent, SWT.PUSH);
+ text.setLayoutData( new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1 ) );
+ text.setText( print(fieldBinding, fieldValue) );
+ text.setData(ref);
+ text.addListener(SWT.Verify, new Listener() {
+ public void handleEvent(Event e) {
+ try {
+ String newText = applyEventToString( text.getText(), e );
+ Object value = parse(fieldBinding, newText);
+ fieldBinding.assertInstaceIsValid( value );
+ text.setBackground(null);
+ } catch (BindingException er) {
+ Color error = new Color(text.getDisplay(), 255, 222, 222);
+ text.setBackground(error);
+ error.dispose();
+ }
+ }
+ });
+
+ //text.setEditable( false );
+ select.setText("Select");
+ select.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));
+ select.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ Object initialValue;
+ try {
+ initialValue = parse(fieldBinding, text.getText());
+ } catch (BindingException e1) {
+ initialValue = fieldBinding.createDefaultUnchecked();
+ }
+ DataboardDialog dialog = new DataboardDialog(
+ shell,
+ title,
+ fieldBinding,
+ initialValue);
+
+ int code = dialog.open();
+ if ( code == Window.OK ) {
+ Object result = dialog.getResult();
+ String str = print(fieldBinding, result);
+ text.setText( str );
+ }
+ }
+ });
+
+ } else
+
+ // Method 2: Label + composite
+ if ( allBooleans(record) ) {
+ Label label = new Label(parent, 0);
+ label.setText(fieldName + ":");
+ label.setLayoutData( lblLayout );
+
+ for (int i=0; i<record.getComponentCount(); i++) {
+ String childName = record.getComponent(i).name;
+ Datatype childType = record.getComponentType(i);
+ String childRef = appendName(ref, childName);
+ if (i>0) new Label(parent, 0);
+ addWidget( parent, childType, childRef );
+ }
+
+ }
+ else
+
+ // Method 3: Groups
+ {
+ Group group = new Group(parent, 0);
+ group.setText(fieldName);
+ group.setLayout( new GridLayout(3, false) );
+ group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
+ group.setData(ref);
+ addRecord(group, record, ref);
+ }
+
+ } else if (fieldType instanceof UnionType) {
+ Label label = new Label(parent, 0);
+ label.setText(fieldName + ":");
+ label.setLayoutData( lblLayout );
+ addUnion( parent, (UnionType) fieldType, ref );
+ }
+
+ }
+
+ protected void addWidget(Composite parent, Datatype fieldType, String ref) {
+ if (fieldType instanceof StringType) {
+ addString(parent, (StringType) fieldType, ref);
+ } else if (fieldType instanceof BooleanType) {
+ addBoolean(parent, (BooleanType) fieldType, ref);
+ } else if (fieldType instanceof NumberType) {
+ addNumber(parent, (NumberType) fieldType, ref);
+ } else if (fieldType instanceof RecordType) {
+ RecordType rt = (RecordType) fieldType;
+ Group group = new Group(parent, 0);
+ String name = getName(ref);
+ group.setText(name);
+ group.setLayout( new GridLayout(3, false) );
+ group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
+ group.setData(ref);
+ addRecord(group, rt, ref);
+ } else if (fieldType instanceof UnionType) {
+ addUnion( parent, (UnionType) fieldType, ref );
+ }
+ }
+
+ public CTabFolder addTabFolder( Composite parent, RecordType record, String ref )
+ {
+ CTabFolder folder = new CTabFolder(parent, SWT.TOP | SWT.BORDER);
+ folder.setSimple(false);
+ folder.setLayout( new GridLayout(3, false) );
+ folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+
+ for (int i=0; i<record.getComponentCount(); i++) {
+ String childName = record.getComponent(i).name;
+ Datatype childType = record.getComponentType(i);
+ String childRef = appendName(ref, childName);
+ if (i>0) new Label(parent, 0);
+
+ CTabItem item = new CTabItem(folder, SWT.NONE);
+ item.setText(childName);
+ Composite composite = new Composite(folder, 0);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ composite.setLayout( new GridLayout(3, false) );
+ composite.setData(ref);
+
+ if ( childType instanceof RecordType ) {
+ addRecord( composite, (RecordType)childType, childRef);
+ } else {
+ addWidget( composite, childType, childRef );
+ }
+
+ item.setControl( composite );
+ allfields.addComponent(childName, childType);
+ }
+ folder.setSelection(0);
+ return folder;
+
+ }
+
+ protected void addRecord( Composite parent, RecordType record, String ref )
+ {
+ String options = record.metadata.get("style");
+ boolean dialog = options==null?false:options.contains("dialog");
+ boolean tabbed = options==null?false:options.contains("tabbed");
+
+ // Method 0: Tabbed, each field is a tab page
+ if ( tabbed ) {
+ addTabFolder( parent, record, ref );
+ return;
+ }
+
+ // Normal Record
+ GridData lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);
+ if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;
+
+ for (int i=0; i<record.getComponentCount(); i++) {
+ String fieldName = record.getComponent(i).name;
+ Datatype fieldType = record.getComponentType(i);
+ String fieldRef = appendName(ref, fieldName);
+ addField( parent, fieldType, fieldRef, lblLayout);
+ }
+ return;
+ }
+
+ protected void addUnion( Composite parent, UnionType union, String ref )
+ {
+ if ( union.isEnumeration() ) {
+ addEnum( parent, union, ref );
+ } else {
+ addRadio( parent, union, ref );
+ }
+ }
+
+ protected void addEnum( Composite parent, UnionType union, String ref )
+ {
+ Combo combo = new Combo(parent, SWT.READ_ONLY);
+ String[] items = new String[union.getComponentCount()];
+ for (int i = 0; i < items.length; i++) {
+ items[i] = union.getComponent(i).name;
+ }
+ combo.setItems(items);
+ combo.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
+ combo.setData(ref);
+
+ // Set default value
+ UnionBinding binding = Bindings.getBinding(union);
+ try {
+ TaggedObject defaultOption = (TaggedObject) binding.createDefault();
+ combo.setText( items[ defaultOption.tag ] );
+ } catch (BindingException e) {
+ }
+ }
+
+ protected void addRadio( Composite parent, UnionType union, String ref )
+ {
+ Composite composite = new Composite(parent, 0);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
+ composite.setLayout( new GridLayout(3, false) );
+ composite.setData(ref);
+ final int count = union.getComponentCount();
+ final Composite panels[] = new Composite[count];
+ final Button buttons[] = new Button[count];
+ for ( int i=0; i<count; i++ ) {
+ Component component = union.getComponent(i);
+ String childRef = ref+"/"+URIUtil.encodeURI(component.name);
+ Button b = buttons[i] = new Button(composite, SWT.RADIO);
+ b.setLayoutData(new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1));
+ b.setText(component.name);
+ b.setData(childRef);
+
+ String options = union.metadata.get("style");
+ boolean border = options==null?true:!options.contains("no-border");
+ int style = 0;
+ if (border) style |= SWT.BORDER;
+
+ Composite panel = panels[i] = new Composite(composite, style);
+ panel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
+ panel.setLayout( new GridLayout(3, false) );
+ panel.setData(childRef);
+
+ Datatype componentType = union.getComponentType(i);
+ if ( componentType instanceof RecordType ) {
+ addRecord(panel, (RecordType) componentType, childRef);
+ } else {
+ addWidget(panel, componentType, childRef);
+ }
+ }
+
+ // Set default value
+ UnionBinding binding = Bindings.getBinding(union);
+ try {
+ TaggedObject defaultOption = (TaggedObject) binding.createDefault();
+ buttons[defaultOption.tag].setSelection(true);
+ } catch (BindingException e) {
+ }
+
+ }
+
+ protected void addNumber( Composite parent, NumberType number, String ref )
+ {
+ String unit = number.getUnit();
+ String options = number.metadata.get("style");
+ boolean border = options==null?true:!options.contains("no-border");
+ int style = 0;
+ if (border) style |= SWT.BORDER;
+ final Text text = new Text(parent, style);
+ text.setData(ref);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, unit==null?2:1, 1));
+
+ // Set default value
+ final NumberBinding binding = Bindings.getBinding( number );
+ try {
+ text.setText( binding.createDefault().toString() );
+ } catch (BindingException e) {
+ }
+
+ // Add validator
+ text.addListener(SWT.Verify, new Listener() {
+ public void handleEvent(Event e) {
+ try {
+ String newText = applyEventToString( text.getText(), e );
+ Object value = binding.create( newText );
+ binding.assertInstaceIsValid( value );
+ text.setBackground(null);
+ } catch (BindingException er) {
+ Color error = new Color(text.getDisplay(), 255, 222, 222);
+ text.setBackground(error);
+ error.dispose();
+ }
+ }});
+
+ if ( unit!=null ) {
+ Label unitLabel = new Label(parent, 0);
+ unitLabel.setText(unit);
+ }
+ }
+
+ static String applyEventToString(String orig, Event e) {
+ if (e.character==8) {
+ return orig.substring(0, e.start) + orig.substring(e.end, orig.length());
+ }
+ return orig.substring(0, e.start) + e.text + orig.substring(e.end, orig.length());
+ }
+
+ protected void addBoolean( Composite parent, BooleanType booleanType, String ref )
+ {
+ Button button = new Button(parent, SWT.CHECK);
+ button.setText( getName(ref) );
+ button.setData(ref);
+ button.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
+ }
+
+ protected void addString( Composite parent, StringType stringType, String ref )
+ {
+ String options = stringType.metadata.get("style");
+ boolean password = options==null?false:options.contains("password");
+ boolean filesave = options==null?false:options.contains("filesave");
+ boolean fileopen = options==null?false:options.contains("fileopen");
+ boolean directory = options==null?false:options.contains("directory");
+ boolean multi = options==null?false:options.contains("multi");
+ boolean border = options==null?true:!options.contains("no-border");
+
+ int style = 0;
+ if (password) style |= SWT.PASSWORD;
+ if (multi) style |= SWT.MULTI;
+ if (border) style |= SWT.BORDER;
+ final Text text = new Text(parent, style);
+ text.setLayoutData( new GridData(SWT.FILL, multi?SWT.FILL:SWT.BEGINNING, true, false, filesave|fileopen|directory?1:2, 1 ) );
+ text.setData(ref);
+
+ // Set default value
+ final StringBinding binding = Bindings.getBinding( stringType );
+ try {
+ text.setText( binding.createDefault().toString() );
+ } catch (BindingException e) {
+ }
+
+ text.addListener(SWT.Verify, new Listener() {
+ public void handleEvent(Event e) {
+ try {
+ String newText = applyEventToString( text.getText(), e );
+ Object value = binding.create( newText );
+ binding.assertInstaceIsValid( value );
+ text.setBackground(null);
+ } catch (BindingException er) {
+ Color error = new Color(text.getDisplay(), 255, 222, 222);
+ text.setBackground(error);
+ error.dispose();
+ }
+ }
+ });
+ if (filesave|fileopen) {
+ final FileDialog fd = new FileDialog(parent.getShell(), filesave?SWT.SAVE:SWT.OPEN);
+
+ String filetypesStr = stringType.metadata.get("filetypes");
+ String fileextsStr = stringType.metadata.get("fileexts");
+ String name = getName(ref);
+ String[] filetypes = filetypesStr==null?null:(String[]) filetypesStr.split(",");
+ String[] fileexts = fileextsStr==null?null:(String[]) fileextsStr.split(",");
+ fd.setFilterNames(filetypes);
+ fd.setFilterExtensions(fileexts);
+
+ boolean nameMatchesExt = false;
+ if ( name!=null && !name.isEmpty() ) {
+ for (String fileext : fileexts) {
+ nameMatchesExt |= StringUtil.simplePatternMatch(name, fileext) && !name.contains(" ");
+ }
+ }
+ final String initialName = nameMatchesExt?name:null;
+
+ Button chooseFileButton = new Button(parent, SWT.PUSH);
+ chooseFileButton.setText("Select");
+ chooseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));
+ chooseFileButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ String name = text.getText();
+ if ( name == null || name.isEmpty() ) name = initialName;
+ if ( name!=null ) fd.setFileName( name );
+ String result = fd.open();
+ if (result != null)
+ text.setText(result);
+ }
+ });
+ }
+
+ if (directory) {
+ final DirectoryDialog fd = new DirectoryDialog(parent.getShell(), 0);
+ String name = getName(ref);
+ fd.setMessage( name );
+ Button chooseDirButton = new Button(parent, SWT.PUSH);
+ chooseDirButton.setText("Select");
+ chooseDirButton.setLayoutData(new GridData(SWT.RIGHT, SWT.BEGINNING, false, false));
+ chooseDirButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ String dir = text.getText();
+ fd.setFilterPath(dir);
+ String result = fd.open();
+ if (result != null)
+ text.setText(result);
+ }
+ });
+ }
+ }
+
+ static String appendName(String ref, String name)
+ {
+ return ref+"/"+URIUtil.encodeURI(name);
+ }
+
+ static String getName(String ref)
+ {
+ if ( ref==null ) return null;
+ int i = ref.lastIndexOf('/');
+ if (i<0) return URIUtil.decodeURI(ref);
+ String namePart = ref.substring(i+1);
+ return URIUtil.decodeURI(namePart);
+ }
+
+ static int getDepth(String ref)
+ {
+ int depth = 0;
+ for (int i=0; i<ref.length(); i++) if ( ref.charAt(i)=='/' ) depth++;
+ return depth;
+ }
+
+ static boolean allBooleans(RecordType rt) {
+ for (Component c : rt.getComponents())
+ if ( c.type instanceof BooleanType == false ) return false;
+ return true;
+ }
+
+ static String print(RecordBinding recordBinding, Object value) {
+ if ( allBooleans(recordBinding.type() ) ) {
+ StringBuilder sb = new StringBuilder();
+ int j = 0;
+ for ( int i = 0; i<recordBinding.getComponentCount(); i++ ) {
+ try {
+ boolean b = recordBinding.getBoolean(value, i);
+ if ( !b ) continue;
+ if ( j>0 ) sb.append(", ");
+ sb.append(recordBinding.type().getComponent(i).name);
+ j++;
+ } catch (BindingException e) {
+ continue;
+ }
+ }
+ return sb.toString();
+ } else
+ try {
+ return recordBinding.toString(value, true);
+ } catch (BindingException e) {
+ return e.toString();
+ }
+ }
+
+ static Object parse(RecordBinding recordBinding, String txt) throws BindingException {
+ if ( allBooleans(recordBinding.type() ) ) {
+ Object result = recordBinding.createDefaultUnchecked();
+ String[] tokens = txt.split(", ");
+ for ( String token : tokens ) {
+ if ( token.isEmpty() ) continue;
+ int i = recordBinding.type().getComponentIndex2(token);
+ if ( i>=0 ) {
+ try {
+ recordBinding.setBoolean(result, i, true);
+ } catch (BindingException e) {
+ throw e;
+ }
+ } else {
+ throw new BindingException("There is no field \""+token+"\"");
+ }
+ }
+ return result;
+ } else {
+ try {
+ return recordBinding.parseValueDefinition(txt);
+ } catch (DataTypeSyntaxError e) {
+ throw new BindingException(e);
+ }
+
+ }
+ }
+
+ static {
+ PASSWORD = new StringType();
+ PASSWORD.metadata.put("style", "password");
+
+ TEXTBOX = new StringType();
+ TEXTBOX.metadata.put("style", "multi");
+ }
+
+}