Announcement Announcement Module
Collapse
No announcement yet.
FormModelHelper.createChildPageFormModel questions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • FormModelHelper.createChildPageFormModel questions

    I'm definitely new to RCP, so I'm still stumbling in the dark a little.

    I'm trying to setup a hierarchical properties editor on a complex object. The object contains many nested objects including arrays of nested objects. Here's a stripped sample:

    Code:
    class Physician {
       int id;
       Name name;
       Office[] offices;
    
       public int getId();
       public Office[] getOffice();
       public Office getOffice(int index);
       public Name getName();
    
       // and a lot more
    }
    I'm trying to use a TreeCompositeDialogPage to hold all the property forms. In general, I'd like to end up with something like this (where the appropriate form displays on the right when a node is selected):

    Code:
    / - Demographics
      + Offices
      |  | 
      |  + Some Office Name
      |  |   |
      |  |   + Contact Info
      |  |   + Personnel
      |  |   + Documents
      |  + Next office
      |  |   [same subforms as above]
      + Next major sub-object
      |
      and so on...
    So, I'm trying to add one of the child office forms using this call:
    Code:
                	String propPath = "office[" + i + "]";
                	ConfigurableFormModel ogFormModel = FormModelHelper.createChildPageFormModel((NestingFormModel) physFormModel, "office", propPath);
    I was assuming that this would construct a nested form model rooted on the object "office[0]". However, this doesn't work. At runtime, I get the following exception:

    Code:
    org.springframework.beans.InvalidPropertyException: Invalid property 'office[0]' of bean class [com.fhm.pdbm.ui.view.PhysicianView]: No property 'office[0]' found
    	at org.springframework.beans.BeanWrapperImpl.getPropertyDescriptor(BeanWrapperImpl.java:1123)
    	at org.springframework.binding.support.BeanPropertyAccessStrategy$BeanPropertyMetaAspectAccessor.getPropertyType(BeanPropertyAccessStrategy.java:332)
    	at org.springframework.binding.form.support.CompoundFormModel.createChildInternal(CompoundFormModel.java:89)
    	at org.springframework.binding.form.support.CompoundFormModel.createChild(CompoundFormModel.java:74)
    	at org.springframework.richclient.form.FormModelHelper.createChildPageFormModel(FormModelHelper.java:97)
    	at com.fhm.pdbm.ui.PhysicianTableView$PropertiesExecutor.execute(PhysicianTableView.java:215)
    	at org.springframework.richclient.command.support.AbstractActionCommandExecutor.execute(AbstractActionCommandExecutor.java:51)
    	at org.springframework.richclient.command.TargetableActionCommand.doExecuteCommand(TargetableActionCommand.java:99)
    	at org.springframework.richclient.command.ActionCommand.execute(ActionCommand.java:188)
    	at org.springframework.richclient.command.ActionCommand$1.actionPerformed(ActionCommand.java:123)
    	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1849)
    	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2169)
    	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
    	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
    	at javax.swing.AbstractButton.doClick(AbstractButton.java:302)
    	at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1000)
    	at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1041)
    	at java.awt.Component.processMouseEvent(Component.java:5488)
    	at javax.swing.JComponent.processMouseEvent(JComponent.java:3126)
    	at java.awt.Component.processEvent(Component.java:5253)
    	at java.awt.Container.processEvent(Container.java:1966)
    	at java.awt.Component.dispatchEventImpl(Component.java:3955)
    	at java.awt.Container.dispatchEventImpl(Container.java:2024)
    	at java.awt.Component.dispatchEvent(Component.java:3803)
    	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212)
    	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3892)
    	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
    	at java.awt.Container.dispatchEventImpl(Container.java:2010)
    	at java.awt.Window.dispatchEventImpl(Window.java:1774)
    	at java.awt.Component.dispatchEvent(Component.java:3803)
    	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
    	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
    	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
    	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
    	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
    	at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
    By digging into the code, it seems to be attempting to process the subpropertyPath as a simple property name instead of treating it as a property path. Is it not capable of dealing with array references like this? I know that you can certainly use array references in property paths (I tested it).

    So, I'm pretty lost at the moment. I want to be able to create multiple instances of the subforms dedicated on an Office by creating child form models that reference the objects office[0], office[1], etc.

    Is this doable? If not, how do you go about creating a complex property dialog like I've described?

    Let me know if I haven't described this well enough.

    Thanks,
    Larry.

  • #2
    A little more digging, and I found methods that allow me to specify the value model directly and I determined that the TreeCompositeDialogPage requires all the forms to have unique Id's. So, I have now ensured that both the FormModel and the Form have unique Id's.

    Yielding code like this (where the OfficeGeneralForm constuctor uses the index to create the form Id):

    Code:
                for&#40;int i=0; i < phys.getOfficeCount&#40;&#41;; i++&#41; &#123;
                	Office o = phys.getOffice&#40;i&#41;;
                	ValueModel officeValueModel = new ValueHolder&#40;o&#41;;
                	System.out.println&#40; "Office&#91;" + i + "&#93;=" + ToStringBuilder.reflectionToString&#40;o&#41;&#41;;
                	ConfigurableFormModel ogFormModel = physFormModel.createChild&#40;"office"+i, officeValueModel&#41;;
            		OfficeGeneralForm ogForm = new OfficeGeneralForm&#40;ogFormModel,i&#41;;
            		compositePage.addForm&#40;olPage, ogForm&#41;;
                &#125;

    That's a little closer, in that it doesn't throw exceptions :wink:

    However, it doesn't really work either. In a case where a physician has 2 offices, the 2 entries get created in the tree, and selecting each of them does display a different form (which I can tell because the labels are changing due to the form model Id's being different). But, the data being displayed in each form is not changing. I.e., although the form changed, it doesn't appear to be pulling it's data from the configured form model.

    Now I'm seriously in over my head and in need of help in understanding if I'm just trying to do something RCP wasn't designed to do.

    Thanks.
    Larry.

    Comment


    • #3
      So far - I'm having a great time talking to myself!

      I've been doing a lot of trial and error plus debugging to try to get this to work and what I'm finding seems wrong to me, but it's probably my lack of knowledge of how CompundFormModels are supposed to work.

      To give some more details on what I'm seeing, here's the setup:

      1. I've created one CompoundFormModel to hold all my form models (this seems the right thing to do given other posts).

      2. I create forms that use distinct value models and add them to the compound form using CompoundForm.createChild

      3. Then I create a FormBackedDialogPage and add that to the composite dialog.

      To be more concrete, the top-level CompoundModel represents a physician, a sub-model is created for every office, and another sub-model is created for each person associated with an office.

      The physician and the office personnel objects both contain a property of type Name (which is a simple object containing properties like firstName, lastName, etc.). On both the physician form and the personnel form, I access the needed values using "name.firstName" and "name.lastName".

      When I display the form for one of the office personnel, instead of showing the proper first and last name it shows the first and last names of the physician. :shock:

      From a lot of debugging, all I can determine is that DefaultFormModel.getValueModel() at line 163 first tries to find a cached converter in convertingValueModels. If it doesn't find one, it then checks to see if it has a parent value model (which mine do since they are nested) and then dispatches to getParent().findValueModel(formPropertyPath, targetClass). This is where things go wrong.

      At this point, CompoundValueModel searches all of its sub-models looking for the propertyPath - which it finds since the physician model has already been processed. Problem is, this is the wrong binding.

      Sorry for that long winded intro, but we finally get to the question - why isn't the current form model searched before we go looking through its siblings? This definitely seems busted to me.

      Thanks.
      Larry.

      Comment


      • #4
        org.springframework.beans.InvalidPropertyException : Invalid property 'office[0]' of bean class [com.fhm.pdbm.ui.view.PhysicianView]: No property 'office[0]' found
        Funny. I was improving the unit tests for BeanPropertyAccesStrategy over the weekend and found this sucker myself...

        Basically what you were doing should work. Unfortunately BeanWrapperImpl which BeanPropertyAccessStrategy relies on for the raw property access does not return metadata for indexed paths - getPropertyValue("office[0]") works just fine but getPropertyDescriptor("office[0]") dumps out with the exception you discovered. I doubt that BeanWrapperImpl could even be fixed - as the PropertyDescriptor class is not suited to describing indexed properties... I guess I'll have to implement this logic in BeanPropertyAccessStrategy.

        Code:
        Sorry for that long winded intro, but we finally get to the question - why isn't the current form model searched before we go looking through its siblings? This definitely seems busted to me.
        Yes it's busted. IMHO child form models should never search their parent/siblings for a missing value model. I'm currently working on a heavy refactoring of the form model code and this has already been addressed. It's still a while off until I commit. A short term fix would be to comment out line 165 in DefaultFormModel.

        Ollie

        Comment


        • #5
          Originally posted by oliverhutchison View Post
          Funny. I was improving the unit tests for BeanPropertyAccesStrategy over the weekend and found this sucker myself...

          Basically what you were doing should work. Unfortunately BeanWrapperImpl which BeanPropertyAccessStrategy relies on for the raw property access does not return metadata for indexed paths - getPropertyValue("office[0]") works just fine but getPropertyDescriptor("office[0]") dumps out with the exception you discovered. I doubt that BeanWrapperImpl could even be fixed - as the PropertyDescriptor class is not suited to describing indexed properties... I guess I'll have to implement this logic in BeanPropertyAccessStrategy.
          Is this fixed in the meantime? I am using v0.2.1 end get still this error ;-(

          Marcel

          Comment

          Working...
          X