1 package org.simantics.databoard.forms;
\r
3 import java.util.ArrayList;
\r
4 import java.util.List;
\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
59 * Databoard form creates SWT user interface from databoard record type.
\r
61 * See DataboardFormExample for example usage.
\r
63 * @author toni.kalajainen@semantum.fi
\r
65 public class DataboardForm {
\r
67 public static final Datatype TEXTBOX;
\r
68 public static final Datatype PASSWORD;
\r
70 public int column1Width = -1;
\r
72 private RecordType allfields = new RecordType();
\r
77 * @param namesAndExts array of names and extensions
\r
81 public static StringType fileSaveDialog(String...namesAndExts)
\r
83 StringType result = new StringType();
\r
84 result.metadata.put("style", "filesave");
\r
86 StringBuilder sb1 = new StringBuilder();
\r
87 StringBuilder sb2 = new StringBuilder();
\r
89 for (int i=0; i<namesAndExts.length; i++) {
\r
90 StringBuilder sb = (i%2==0?sb1:sb2);
\r
92 if (j>0) sb.append(',');
\r
93 sb.append(namesAndExts[i]);
\r
96 result.metadata.put("filetypes", sb1.toString());
\r
97 result.metadata.put("fileexts", sb2.toString());
\r
104 * @param namesAndExts array of names and extensions
\r
108 public static StringType fileOpenDialog(String...namesAndExts)
\r
110 StringType result = new StringType();
\r
111 result.metadata.put("style", "fileopen");
\r
113 StringBuilder sb1 = new StringBuilder();
\r
114 StringBuilder sb2 = new StringBuilder();
\r
116 for (int i=0; i<namesAndExts.length; i++) {
\r
117 StringBuilder sb = (i%2==0?sb1:sb2);
\r
119 if (j>0) sb.append(',');
\r
120 sb.append(namesAndExts[i]);
\r
123 result.metadata.put("filetypes", sb1.toString());
\r
124 result.metadata.put("fileexts", sb2.toString());
\r
128 public static StringType directoryDialog()
\r
130 StringType result = new StringType();
\r
131 result.metadata.put("style", "directory");
\r
135 public DataboardForm() {
\r
138 public void setFirstColumnWidth(int width) {
\r
139 column1Width = width;
\r
144 * Validate the fields for valid values.
\r
145 * StringTypes can be restricted with regular expressions.
\r
146 * NumberTypes with value ranges.
\r
149 * @return list of problems
\r
151 public List<Problem> validate( Composite composite ) {
\r
152 List<Problem> result = new ArrayList<Problem>();
\r
153 _validateFields(composite, result);
\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
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
172 protected void _validateFields( Control control, List<Problem> result )
\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
181 Datatype fieldType = allfields.getChildType( ref );
\r
183 // Read Combo Union
\r
184 if ( fieldType instanceof UnionType && control instanceof Combo ) {
\r
185 // Nothing to validate
\r
188 // Read Radio Union
\r
189 if ( fieldType instanceof UnionType && control instanceof Composite ) {
\r
190 // Nothing to validate
\r
194 if ( fieldType instanceof BooleanType && control instanceof Button ) {
\r
195 // Nothing to validate
\r
198 // Text + Dialog button
\r
199 if ( fieldType instanceof RecordType && control instanceof Text ) {
\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
210 problem.error = er.getMessage();
\r
212 problem.fieldReference = refStr;
\r
213 problem.control = control;
\r
214 result.add( problem );
\r
220 if ( fieldType instanceof StringAccessor && control instanceof Text ) {
\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
231 problem.error = er.getMessage();
\r
233 problem.fieldReference = refStr;
\r
234 problem.control = control;
\r
235 result.add( problem );
\r
240 if ( fieldType instanceof NumberType && control instanceof Text ) {
\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
252 problem.error = er.getMessage();
\r
254 problem.fieldReference = refStr;
\r
255 problem.control = control;
\r
256 result.add( problem );
\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
271 if ( control instanceof Composite ) {
\r
272 Composite composite = (Composite) control;
\r
273 for (Control child : composite.getChildren())
\r
275 _validateFields(child, result);
\r
281 public RecordType type() {
\r
286 * Find control by reference
\r
289 * @return control or null
\r
291 public Control getControl( Control control, ChildReference ref )
\r
293 return getControl( control, ref.toPath() );
\r
297 * Find control by reference.
\r
301 * @return control or null
\r
303 public Control getControl( Control control, String ref )
\r
305 Object data = control.getData();
\r
306 if ( data != null && data instanceof String && data.equals(ref)) return control;
\r
309 if ( control instanceof Composite ) {
\r
310 Composite composite = (Composite) control;
\r
311 for (Control child : composite.getChildren())
\r
313 Control result = getControl(child, ref);
\r
314 if ( result != null ) return result;
\r
321 * Reads values of fields into a record
\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
330 public void readFields( Composite composite, RecordBinding binding, Object dst)
\r
331 throws BindingException, AccessorConstructionException, AccessorException
\r
333 RecordAccessor ra = Accessors.getAccessor(binding, dst);
\r
334 _readFields(composite, ra);
\r
337 protected void _readFields( Control control, RecordAccessor ra )
\r
338 throws AccessorException, BindingException
\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
346 Accessor fieldAccessor = ra.getComponent( ref );
\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
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
370 UnionAccessor sa = (UnionAccessor) fieldAccessor;
\r
371 int tag = sa.type().getComponentIndex2( name );
\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
384 if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {
\r
385 BooleanAccessor sa = (BooleanAccessor) fieldAccessor;
\r
386 sa.setValue(((Button)control).getSelection());
\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
399 if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {
\r
400 StringAccessor sa = (StringAccessor) fieldAccessor;
\r
401 sa.setValue(((Text)control).getText());
\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
411 } catch (AccessorConstructionException e) {
\r
412 //e.printStackTrace();
\r
418 if ( control instanceof Composite ) {
\r
419 Composite composite = (Composite) control;
\r
420 for (Control child : composite.getChildren())
\r
422 _readFields(child, ra);
\r
427 public void writeFields( Composite composite, RecordBinding binding, Object src)
\r
428 throws AccessorException, BindingException, AccessorConstructionException
\r
430 RecordAccessor ra = Accessors.getAccessor(binding, src);
\r
431 _writeFields(composite, ra);
\r
434 void _writeFields( Control control, RecordAccessor ra )
\r
435 throws AccessorException, BindingException, AccessorConstructionException
\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
443 Accessor fieldAccessor = ra.getComponent( ref );
\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
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
465 if ( fieldAccessor instanceof BooleanAccessor && control instanceof Button ) {
\r
466 BooleanAccessor sa = (BooleanAccessor) fieldAccessor;
\r
467 ((Button)control).setSelection(sa.getValue());
\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
480 if ( fieldAccessor instanceof StringAccessor && control instanceof Text ) {
\r
481 StringAccessor sa = (StringAccessor) fieldAccessor;
\r
482 ((Text)control).setText( sa.getValue() );
\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
492 } catch (AccessorConstructionException e) {
\r
493 //e.printStackTrace();
\r
499 if ( control instanceof Composite ) {
\r
500 Composite composite = (Composite) control;
\r
501 for (Control child : composite.getChildren())
\r
503 _writeFields(child, ra);
\r
509 public void clear( Control control )
\r
511 _clearFields( control );
\r
515 protected void _clearFields( Control control )
\r
518 if ( control instanceof Composite ) {
\r
519 Composite composite = (Composite) control;
\r
520 for (Control child : composite.getChildren())
\r
522 _clearFields(child);
\r
530 * Add a listener to all the controls that represent the data type.
\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
539 public void addListener( Composite composite, RecordType type, Listener listener )
\r
540 throws BindingException, AccessorConstructionException, AccessorException
\r
542 _addListener(composite, type, listener );
\r
545 protected void _addListener( Control control, Datatype type, Listener listener )
\r
546 throws AccessorException, BindingException
\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
556 Datatype fieldType = ref==null ? type : type.getChildType( ref );
\r
558 // Read Combo Union
\r
559 if ( fieldType instanceof UnionType && control instanceof Combo ) {
\r
560 control.addListener(SWT.Selection, listener);
\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
573 if ( fieldType instanceof BooleanType && control instanceof Button ) {
\r
574 control.addListener(SWT.Selection, listener);
\r
578 if ( fieldType instanceof StringType && control instanceof Text ) {
\r
579 control.addListener(SWT.Modify, listener);
\r
583 if ( fieldType instanceof NumberType && control instanceof Text ) {
\r
584 control.addListener(SWT.Modify, listener);
\r
587 } catch (ReferenceException re) {
\r
591 if ( control instanceof Composite ) {
\r
592 Composite composite = (Composite) control;
\r
593 for (Control child : composite.getChildren())
\r
595 _addListener(child, type, listener);
\r
600 public void addField( Composite parent, String name, Datatype fieldType )
\r
602 addField(parent, fieldType, URIUtil.encodeURI(name), null);
\r
603 allfields.addComponent(name, fieldType);
\r
606 public void addField( Composite parent, String name, Datatype fieldType, String ref )
\r
608 addField(parent, fieldType, appendName(ref, name), null);
\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
618 LabelReference lr = (LabelReference) path;
\r
619 String label = lr.label;
\r
621 if ( root.hasComponent(label) ) {
\r
622 root = (RecordType) root.getComponent(label).type;
\r
624 RecordType rt = new RecordType();
\r
625 root.addComponent(label, rt);
\r
628 path = path.childReference;
\r
631 if ( !root.hasComponent(name) ) root.addComponent(name, fieldType);
\r
635 public void addFields( Composite parent, RecordType source )
\r
637 for (Component component : source.getComponents())
\r
638 addField( parent, component.name, component.type );
\r
641 public void addFields( Composite parent, RecordType source, String ref )
\r
643 for (Component component : source.getComponents())
\r
644 addField( parent, component.name, component.type, ref );
\r
648 public void addField( Composite parent, Datatype fieldType, String ref, GridData lblLayout )
\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
654 String fieldName = getName(ref);
\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
662 addString(parent, (StringType) fieldType, ref);
\r
664 } else if (fieldType instanceof BooleanType) {
\r
666 Label label = new Label(parent, 0);
\r
667 label.setLayoutData( lblLayout );
\r
669 addBoolean(parent, (BooleanType) fieldType, ref);
\r
671 } else if (fieldType instanceof NumberType) {
\r
673 Label label = new Label(parent, 0);
\r
674 label.setText(fieldName + ":");
\r
675 label.setLayoutData( lblLayout );
\r
677 addNumber(parent, (NumberType) fieldType, ref);
\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
685 // Method 0: Tabbed, each field is a tab page
\r
687 Label label = new Label(parent, 0);
\r
688 label.setText(fieldName + ":");
\r
689 label.setLayoutData( lblLayout );
\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
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
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
710 if ( childType instanceof RecordType ) {
\r
711 addRecord( composite, (RecordType)childType, childRef);
\r
713 addWidget( composite, childType, childRef );
\r
716 item.setControl( composite );
\r
718 folder.setSelection(0);
\r
722 // Method 1: Dialog = Label + Text + [Button]
\r
724 Label label = new Label(parent, 0);
\r
725 label.setText(fieldName + ":");
\r
726 label.setLayoutData( lblLayout );
\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
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
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
759 initialValue = parse(fieldBinding, text.getText());
\r
760 } catch (BindingException e1) {
\r
761 initialValue = fieldBinding.createDefaultUnchecked();
\r
763 DataboardDialog dialog = new DataboardDialog(
\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
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
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
797 // Method 3: Groups
\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
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
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
837 public CTabFolder addTabFolder( Composite parent, RecordType record, String ref )
\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
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
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
857 if ( childType instanceof RecordType ) {
\r
858 addRecord( composite, (RecordType)childType, childRef);
\r
860 addWidget( composite, childType, childRef );
\r
863 item.setControl( composite );
\r
864 allfields.addComponent(childName, childType);
\r
866 folder.setSelection(0);
\r
871 protected void addRecord( Composite parent, RecordType record, String ref )
\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
877 // Method 0: Tabbed, each field is a tab page
\r
879 addTabFolder( parent, record, ref );
\r
884 GridData lblLayout = new GridData(SWT.LEFT, SWT.BEGINNING, false, false, 1, 1);
\r
885 if ( getDepth(ref) < 3 ) lblLayout.widthHint = column1Width;
\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
896 protected void addUnion( Composite parent, UnionType union, String ref )
\r
898 if ( union.isEnumeration() ) {
\r
899 addEnum( parent, union, ref );
\r
901 addRadio( parent, union, ref );
\r
905 protected void addEnum( Composite parent, UnionType union, String ref )
\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
912 combo.setItems(items);
\r
913 combo.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
\r
914 combo.setData(ref);
\r
916 // Set default value
\r
917 UnionBinding binding = Bindings.getBinding(union);
\r
919 TaggedObject defaultOption = (TaggedObject) binding.createDefault();
\r
920 combo.setText( items[ defaultOption.tag ] );
\r
921 } catch (BindingException e) {
\r
925 protected void addRadio( Composite parent, UnionType union, String ref )
\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
942 String options = union.metadata.get("style");
\r
943 boolean border = options==null?true:!options.contains("no-border");
\r
945 if (border) style |= SWT.BORDER;
\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
952 Datatype componentType = union.getComponentType(i);
\r
953 if ( componentType instanceof RecordType ) {
\r
954 addRecord(panel, (RecordType) componentType, childRef);
\r
956 addWidget(panel, componentType, childRef);
\r
960 // Set default value
\r
961 UnionBinding binding = Bindings.getBinding(union);
\r
963 TaggedObject defaultOption = (TaggedObject) binding.createDefault();
\r
964 buttons[defaultOption.tag].setSelection(true);
\r
965 } catch (BindingException e) {
\r
970 protected void addNumber( Composite parent, NumberType number, String ref )
\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
976 if (border) style |= SWT.BORDER;
\r
977 final Text text = new Text(parent, style);
\r
979 text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, unit==null?2:1, 1));
\r
981 // Set default value
\r
982 final NumberBinding binding = Bindings.getBinding( number );
\r
984 text.setText( binding.createDefault().toString() );
\r
985 } catch (BindingException e) {
\r
989 text.addListener(SWT.Verify, new Listener() {
\r
990 public void handleEvent(Event e) {
\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
1003 if ( unit!=null ) {
\r
1004 Label unitLabel = new Label(parent, 0);
\r
1005 unitLabel.setText(unit);
\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
1013 return orig.substring(0, e.start) + e.text + orig.substring(e.end, orig.length());
\r
1016 protected void addBoolean( Composite parent, BooleanType booleanType, String ref )
\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
1024 protected void addString( Composite parent, StringType stringType, String ref )
\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
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
1042 // Set default value
\r
1043 final StringBinding binding = Bindings.getBinding( stringType );
\r
1045 text.setText( binding.createDefault().toString() );
\r
1046 } catch (BindingException e) {
\r
1049 text.addListener(SWT.Verify, new Listener() {
\r
1050 public void handleEvent(Event e) {
\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
1063 if (filesave|fileopen) {
\r
1064 final FileDialog fd = new FileDialog(parent.getShell(), filesave?SWT.SAVE:SWT.OPEN);
\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
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
1080 final String initialName = nameMatchesExt?name:null;
\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
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
1116 static String appendName(String ref, String name)
\r
1118 return ref+"/"+URIUtil.encodeURI(name);
\r
1121 static String getName(String ref)
\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
1130 static int getDepth(String ref)
\r
1133 for (int i=0; i<ref.length(); i++) if ( ref.charAt(i)=='/' ) depth++;
\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
1143 static String print(RecordBinding recordBinding, Object value) {
\r
1144 if ( allBooleans(recordBinding.type() ) ) {
\r
1145 StringBuilder sb = new StringBuilder();
\r
1147 for ( int i = 0; i<recordBinding.getComponentCount(); i++ ) {
\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
1154 } catch (BindingException e) {
\r
1158 return sb.toString();
\r
1161 return recordBinding.toString(value, true);
\r
1162 } catch (BindingException e) {
\r
1163 return e.toString();
\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
1176 recordBinding.setBoolean(result, i, true);
\r
1177 } catch (BindingException e) {
\r
1181 throw new BindingException("There is no field \""+token+"\"");
\r
1187 return recordBinding.parseValueDefinition(txt);
\r
1188 } catch (DataTypeSyntaxError e) {
\r
1189 throw new BindingException(e);
\r
1196 PASSWORD = new StringType();
\r
1197 PASSWORD.metadata.put("style", "password");
\r
1199 TEXTBOX = new StringType();
\r
1200 TEXTBOX.metadata.put("style", "multi");
\r