Announcement Announcement Module
Collapse
No announcement yet.
How to bind File property in a Form Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to bind File property in a Form

    I have a domain class with a File property such as
    Code:
    public class Customer {
        private String name;
        private File file;
    
        ...
        getters and setters
    }
    I display a form such as
    Code:
    public class CustomerForm extends AbstractForm {
        public CustomerForm(Customer customer) {
            super(customer);
            setId("customer");
        }
    
        @Override
        protected JComponent createFormControl() {
            TableFormBuilder formBuilder = new TableFormBuilder(getBindingFactory());
            formBuilder.setLabelAttributes("colGrId=label colSpec=right:pref");
            formBuilder.addSeparator("General");
            formBuilder.row();
    
            formBuilder.add("name");
            formBuilder.row();
    
            // add file property
            formBuilder.add(new FileChooserBinding(getFormModel(), "file",
                    File.class, new FileChooser(),
                    FileChooser.FileChooserMode.FILE, true));
    
            return formBuilder.getForm();
        }
    }
    but when retrieve the FormModel in onFinish() TitledPageApplicationDialog method the file property is null

    Code:
    @Override
        protected boolean onFinish() {
            form.getFormModel().commit();
    
            Customer Customer = (Customer) form.getFormModel().getFormObject();
    
            // print null
            System.out.println("file " + Customer.geFile());        
    
            return true;
        }
    Anxious to receive help from you.
    Thanks for any help!

    Sorry for my English
    Last edited by tachosx; Dec 15th, 2010, 02:27 PM.

  • #2
    Lol, yeah thats broken for sure. The FileChooserBinding.doBindControl() method adds a focus listener to the FileChooser component that, when the FileChooser loses focus notifies the form model that the FileChooser control's value has changed and that the form model should update the bound property to the new value.

    The problem is that the FileChooser never gets the focus, the focus is in the text field or dialog button components in the FileChooser. Therefore since focus is never lost the model is never told you selected a file or changed the text in the text field.

    To fix this you will need to create your own implementation of FileChooser... mostly because the text field and mouse handler are private and there are no provided accessor methods. One possible solution would be to add this to your FileChooser:

    Code:
    // Holds the last value in the text field.
    private String lastText;
    protected void fireFileChangedEvent(String newText) {
      String oldText = lastText;
      lastText = newText;
      this.firePropertyChange("selectedFile", oldText, newText);
    }
    Then add a document listener to the nameField in the constructor:

    Code:
    nameField.getDocument().addDocumentListener(new DocumentListener() {
    
      @Override
      public void insertUpdate(DocumentEvent e) {
        fireFileChangedEvent(nameField.getText());
      }
    
      @Override
      public void removeUpdate(DocumentEvent e) {
        fireFileChangedEvent(nameField.getText());
      }
    
      @Override
      public void changedUpdate(DocumentEvent e) {
        fireFileChangedEvent(nameField.getText());
      }
    });
    You will then need to create your own FileChooserBinder and FileChooserBinding as your Binder needs to create an instance of your Binding class and your Binding class needs to use your FileChooser class. And add a propertyChangeListener instead of a focus listener to notify the form model of a value change in the FileChooser component:

    Code:
    // In your binder class
    protected Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context) {
      final FileChooser chooser = (FileChooser)control;
      if(isUseFile()) {
        return new MyFileChooserBinding(formModel, formPropertyPath, File.class, chooser, mode, useFile);
      } else {
        return new MyFileChooserBinding(formModel, formPropertyPath, String.class, chooser, mode, useFile);
      }
    }
    
    // In your binding class
    protected JComponent doBindControl() {
      if(!useFile && getValue() != null) {
        field.setText((String)getValue());
      } else if(useFile && getValue() != null) {
        field.setText(((java.io.File)getValue()).getAbsolutePath());
      } else {
        field.setText("");
      }
      field.addPropertyChangeListener("selectedFile", new PropertyChangeListener() {
    
        @Override
        public void propertyChange(PropertyChangeEvent e) {
          if(field.isEditable()) {
            if(useFile) {
              controlValueChanged(new File(field.getText()));
            } else {
              controlValueChanged(field.getText());
            }
          }
        }
      });
      return field;
    }
    You can then register your binder with the binder selection strategy, if you like, to use it like any other property:

    Code:
    <bean id="binderSelectionStrategy"
            class="org.springframework.richclient.form.binding.swing.SwingBinderSelectionStrategy">
        <property name="bindersForControlTypes">
          <map>
            <entry>
              <key>
                <value type="java.lang.Class">
                  javax.swing.JSpinner
                </value>
              </key>
              <bean class="org.springframework.richclient.form.binding.swing.SpinnerBinder"/>
            </entry>
            <entry>
              <key>
                <value type="java.lang.Class">
                  org.springframework.richclient.components.ShuttleList
                </value>
              </key>
              <bean class="org.springframework.richclient.form.binding.swing.ShuttleListBinder"/>
            </entry>
          </map>
        </property>
        <property name="bindersForPropertyTypes">
          <map>
            <entry>
              <key>
                <value type="java.lang.Class">
                  java.util.Date
                </value>
              </key>
              <bean class="org.springframework.richclient.form.binding.swing.date.JXDatePickerDateFieldBinder"/>
            </entry>
            <entry>
              <key>
                <value type="java.lang.Class">
                  java.io.File
                </value>
              </key>
              <bean class="org.my.app.form.binding.MyFileChooserBinder"/>
            </entry>
          </map>
        </property>
      </bean>
    Then you can use your binder like this:

    Code:
    protected JComponent createFormControl() {
        SwingBindingFactory bf = (SwingBindingFactory)getBindingFactory();
        TableFormBuilder formBuilder = new TableFormBuilder(bf);
        formBuilder.setLabelAttributes("colGrId=label colSpec=right:pref");
        formBuilder.addSeparator("General");
        formBuilder.row();
    
        formBuilder.add("name");
        formBuilder.row();
    
        // add file property
        formBuilder.addBinding(bf.createBinding("file"));
    
        return formBuilder.getForm();
    }
    You may need to create a pair of conversion classes and register them with the conversion service to convert back and forth between File and String classes. You could also register the FileChooser with the binderSelectionStrategy and use the formBuilder.addComponent(...) methods, etc.

    Anyway, this should point out the problem and provide at least one possible solution. You could also refer here: http://www.doclo.be/lieven/articles/...binderrcp.html for some other information on how to write your own implementations.

    Comment


    • #3
      ok, thanks for your reply

      Comment

      Working...
      X