Results 1 to 10 of 10

Thread: [newbie] Form and Component-Concepts Question

  1. #1

    Default [newbie] Form and Component-Concepts Question

    Hello,

    I just started with spring-rcp and after simple ListViews with standard new/edit/delete buttons and bound-dialogs in the petclinic-style work well, I now want to create some complex things, like e.g. an order-view and an order-wizard. As I can't say that i understood the whole binding stuff in the background of rcp by now, i want to ask some questions to not start at the point.

    [forms, binding]
    - how do i disable single components?
    [i can disable a whole form but did not found how to disable a single component]

    - how do i update bound-comboboxes when new data is inserted?
    [the binder class do load the data from the connected service, but i think the combobox stays in cache even if the window is invisible and does not rebuild when it is visible again?]

    - is there a short example out which shows how i build a singlePageForm out of subForms. Like adding some Panels to a Frame? I tried that yesterday evening and wasen't very succesful..

    [wizard]
    i want to create a wizard with something about 5 pages. on the third page there will be something like a money-tranaction, therefore i want to temp-save my order when clicking "next" from the previous page, the do the transaction an later on "finish" save the order again.

    - how can i add some logic to the next/back buttons on a single wizard-page?
    - how can i control to do not let the user click next/back in defined situations, e.g. a broken money-transaction?

    any guidance would be nice... thx

  2. #2

    Smile slutions and new questions :)

    after crawling through the code i finally got my first bound combobox running.

    i which to post my implementation to get some hints on making things better and to prevent mistakes...

    the xml-config
    Code:
    <bean id="genreBinder" class="ui.binder.GenreBinder">
        <property name="service">
            <ref bean="genreService"/>
        </property>
    </bean>
    
    <bean id="binderSelectionStrategy" class="org.springframework.richclient.form.binding.swing.SwingBinderSelectionStrategy">
            <property name="bindersForPropertyTypes">
                <map>
                    <entry>
                        <key>
                            <value type="java.lang.Class">business.Genre</value>
                        </key>
                        <ref bean="genreBinder"/>
                    </entry>
                </map>
            </property>
        </bean>
    based on the PetTypeBinder i wrote my GenreBinder and implemented the ApplicationListener interface. On an ApllicationEvent which contains a Genre, the Binder will call AfterPropertiesSet again to relaod the updated Collection from the service.
    Code:
    public class GenreBinder extends AbstractBinder implements InitializingBean, ApplicationListener {
    
        private GenreService service;
        private Map map;
    
        public GenreBinder() {
            super(Genre.class, new String[] {});        
        }
    
        public void setService(GenreService service) {
            this.service = service;
        }
    
        @SuppressWarnings("unchecked")
    	public void afterPropertiesSet() throws Exception {
            map = new LinkedHashMap();
            for (Iterator i = service.getAll().iterator(); i.hasNext();) {
                Genre obj = (Genre)i.next();
                map.put(obj.getName(), obj);
            }
        }
    
        protected JComponent createControl(Map context) {
            return getComponentFactory().createComboBox();
        }
    
        protected Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context) {
            Assert.isTrue(control instanceof JComboBox, formPropertyPath);
            ComboBoxBinding binding = new ComboBoxBinding((JComboBox)control, formModel, formPropertyPath) {
                protected ValueModel getValueModel() {
                    return new GenreAdapter(super.getValueModel(), map);
                }
            };
            binding.setSelectableItemsHolder(new ValueHolder(map.keySet()));
            return binding;
        }
    
        // This is a hack to get the combo box working even though
        // PetType does not implement equals/hashCode.
        private class GenreAdapter extends TypeConverter {
            private GenreAdapter(ValueModel valueModel, final Map map) {
                super(valueModel, new Closure() {
                    public Object call(Object obj) {                    
                        return obj != null ? ((Genre)obj).getName() : "";
                    }
                }, new Closure() {
                    public Object call(Object objName) {
                        return map.get(objName);
                    }
                });            
            }
        }
        
        public void onApplicationEvent(ApplicationEvent evt) {
            if (evt.getSource() instanceof Genre) {
            	try {
    				afterPropertiesSet();
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
            }
        }
    }
    the new/edit/delete executors in the GenreManagerView fire a ApplicationEvent after an object is saved, updated or deleted, which invokes the binder to reload the objects.
    Code:
    getApplicationContext().publishEvent(new LifecycleApplicationEvent(LifecycleApplicationEvent.CREATED, object));
    actual i try to implement a CustomerConverter which should convert a Class to a String but should not be able to convert from String to Object. I wrote a Class->String-Converter and wired it in the application-context but i get an error message which claims that there is not a converter in the other direction. how can o disable the back-converion from a string?

    Code:
    ERROR [AWT-EventQueue-0] (ApplicationLifecycleAdvisor.java:167) - No converter registered to convert from sourceClass 'class java.lang.String' to target class 'class business.PaymentAccount'
    java.lang.IllegalArgumentException: No converter registered to convert from sourceClass 'class java.lang.String' to target class 'class business.PaymentAccount'
    	at org.springframework.binding.convert.support.DefaultConversionService.getConversionExecutor(DefaultConversionService.java:174)
    	at org.springframework.binding.form.support.AbstractFormModel.createConvertingValueModel(AbstractFormModel.java:306)
    	at org.springframework.binding.form.support.AbstractFormModel.getValueModel(AbstractFormModel.java:252)
    	at org.springframework.richclient.form.binding.support.AbstractBinding.getValueModel(AbstractBinding.java:112)
    	at org.springframework.richclient.form.binding.swing.TextComponentBinding.doBindControl(TextComponentBinding.java:39)
    	at org.springframework.richclient.form.binding.support.AbstractBinding.createControl(AbstractBinding.java:74)
    	at org.springframework.richclient.factory.AbstractControlFactory.getControl(AbstractControlFactory.java:48)
    	at org.springframework.richclient.form.binding.support.AbstractBindingFactory.interceptBinding(AbstractBindingFactory.java:90)
    	at org.springframework.richclient.form.binding.support.AbstractBindingFactory.createBinding(AbstractBindingFactory.java:68)
    	at org.springframework.richclient.form.binding.support.AbstractBindingFactory.createBinding(AbstractBindingFactory.java:53)
    	at org.springframework.richclient.form.builder.AbstractFormBuilder.getDefaultBinding(AbstractFormBuilder.java:72)
    	at org.springframework.richclient.form.builder.TableFormBuilder.add(TableFormBuilder.java:55)
    	at org.springframework.richclient.form.builder.TableFormBuilder.add(TableFormBuilder.java:47)
    	at com.mbee.ivs.adminApp.ui.saleManager.SaleForm.createFormControl(SaleForm.java:63)
    	at org.springframework.richclient.form.AbstractForm.createControl(AbstractForm.java:275)
    	at org.springframework.richclient.factory.AbstractControlFactory.getControl(AbstractControlFactory.java:48)
    	at org.springframework.richclient.dialog.FormBackedDialogPage.createControl(FormBackedDialogPage.java:74)
    	at org.springframework.richclient.dialog.AbstractDialogPage$1.createControl(AbstractDialogPage.java:52)
    	at org.springframework.richclient.factory.AbstractControlFactory.getControl(AbstractControlFactory.java:48)
    	at org.springframework.richclient.dialog.AbstractDialogPage.getControl(AbstractDialogPage.java:197)
    	at org.springframework.richclient.dialog.TitledPageApplicationDialog.createTitledDialogContentPane(TitledPageApplicationDialog.java:78)
    	at org.springframework.richclient.dialog.TitledApplicationDialog.createDialogContentPane(TitledApplicationDialog.java:132)
    	at org.springframework.richclient.dialog.TitledApplicationDialog.addDialogComponents(TitledApplicationDialog.java:120)
    	at org.springframework.richclient.dialog.ApplicationDialog.createDialog(ApplicationDialog.java:306)
    	at org.springframework.richclient.dialog.ApplicationDialog.showDialog(ApplicationDialog.java:272)
    	at ui.saleManager.SaleManagerView$NewExecutor.execute(SaleManagerView.java:253)
    	at org.springframework.richclient.command.support.AbstractActionCommandExecutor.execute(AbstractActionCommandExecutor.java:124)
    	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(Unknown Source)
    	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    	at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
    	at java.awt.Component.processMouseEvent(Unknown Source)
    	at javax.swing.JComponent.processMouseEvent(Unknown Source)
    	at java.awt.Component.processEvent(Unknown Source)
    	at java.awt.Container.processEvent(Unknown Source)
    	at java.awt.Component.dispatchEventImpl(Unknown Source)
    	at java.awt.Container.dispatchEventImpl(Unknown Source)
    	at java.awt.Component.dispatchEvent(Unknown Source)
    	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    	at java.awt.Container.dispatchEventImpl(Unknown Source)
    	at java.awt.Window.dispatchEventImpl(Unknown Source)
    	at java.awt.Component.dispatchEvent(Unknown Source)
    	at java.awt.EventQueue.dispatchEvent(Unknown Source)
    	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
    	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    	at java.awt.EventDispatchThread.run(Unknown Source)
    i had no time yet to take closer look at the properties-disabling and the wizard-thing from my first posting. i will get there..
    any hints for faster learning are very welcome...

    thx and best wishes...

  3. #3
    Join Date
    Aug 2005
    Location
    Austin, TX
    Posts
    425

    Default

    Quote Originally Posted by gibelium
    Hello,

    [forms, binding]
    - how do i disable single components?
    [i can disable a whole form but did not found how to disable a single component]
    A good way to do this is to mark the metadata for the property value as disabled (you can also mark it as read-only) and then the bound control will respond accordingly. Something like this:

    Code:
    PropertyMetadata md = getFormModel().getPropertyMetadata( "myProperty" );
    md.setReadOnly( true );
    md.setEnabled( false );
    Quote Originally Posted by gibelium
    - how do i update bound-comboboxes when new data is inserted?
    [the binder class do load the data from the connected service, but i think the combobox stays in cache even if the window is invisible and does not rebuild when it is visible again?]
    Take a look at RefreshableValueHolder and use it to provide the list of elements in the combo box.

    Quote Originally Posted by gibelium
    - is there a short example out which shows how i build a singlePageForm out of subForms. Like adding some Panels to a Frame? I tried that yesterday evening and wasen't very succesful..
    Unfortunately, I don't know of a short example. Although I haven't looked at the "spring rich journey" referenced on this forum.

    Quote Originally Posted by gibelium
    [wizard]
    i want to create a wizard with something about 5 pages. on the third page there will be something like a money-tranaction, therefore i want to temp-save my order when clicking "next" from the previous page, the do the transaction an later on "finish" save the order again.

    - how can i add some logic to the next/back buttons on a single wizard-page?
    - how can i control to do not let the user click next/back in defined situations, e.g. a broken money-transaction?

    any guidance would be nice... thx
    It's the WizardDialog that controls the next/back commands. So you may want to look there for adding some control logic.

    You can control whether the next button is enabled with WizardPage.canFlipToNextPage().


    I hope this information helps.

    Larry.

  4. #4

    Smile Receive ApplicationEvents in Forms

    thanks for reply larry,

    after some sleepless nights i found out how to place some forms in a view programmaticly... by now i just wonder if its possible to wire these forms in the specified view via xml to automaticly recieve ApplicationEvents in a Form not just in a View... Or is there another way to receive ApplicationEvent in non wired view-components?

    I had no time yet to take a closer look to the wizard... but the time hopefully will come soon..

    greetz, sebastian

  5. #5

    Talking

    so, its really easier than i thought yesterday evening...

    i don't know if its the best way, but it works...

    i put my form in the xml-config as a "normal" bean-definition, so i can call the specified bean from the ApplicationContext... And as all xml-defined beans get ApllicationEvents from the Context, when they implement the ApplicationListener Interface, my form now gets the needed events and updates all Refreshable Components...

    Should all forms be defined in via xml and the called from the context?
    Beside that. Is there a difference in performance of loading a form from applicationcontext or instance it programmaticly?

    greetz,
    sebastian

  6. #6
    Join Date
    Aug 2005
    Location
    Austin, TX
    Posts
    425

    Default

    Glad you've found it was easier than you thought :-)

    Creating all your forms in your application context is certainly viable as long as you have a way to provide runtime context to the form (i.e., setting the form object) and you should also ensure that you consider the "singleton" nature of the bean. If you'll never have more than a single instance of the form active at one time, then you should be fine. If not, then you probably need to mark the bean as non-singleton (factory).

    Larry.

  7. #7

    Default

    thanks larry, for bringing things together...

    in my special case i have a search-/filter-Form in which i do not need a special formObject and therefore create and pass a dummy-Object to the abstract superclass... so i do not have to take care of bringing a specified formObject into my form, i just create a new one...
    however, i don't know if it fits in the philosophy of spring-rcp to do so, but it works for the moment with my limited knowledge... perhaps there are other/better possibilities...?

    according to you're posting i'm now thinking about, how i could wire a form in the context and provide the formObject (needed by all other forms)... i just took a short look at the rcp classes and think that the PageComponentDescriptor would be the point to start at, cause if i understood it right, a form is somehow a pageComponent, right..?

    by the way, and comming back to comboBox-binding again...
    is it possible to bind a property to two comboboxes splitting the part of the property which is controlled by each of the components? in my prototype that i'm trying to rewrite with spring-rcp, i have a creditcard-validity property, which is stored in DB as a string with "MM/JJ" format. so i would like to control the month- and year-part of the validity-property by to seperate comboboxes...

    greetz again from germany...
    sebastian

  8. #8

    Question wizard and controls

    today it's wizard-day...

    i implemented a basic wizard on basis of the petclinic example. basic forms and validation seems to work, but it seems, that controlling the next/previous buttons only depends on validation-results based on the information collected in the form...?

    my first page has a master/detail form (e.g. order, orderdetails) where you can add orderdetails to the order as parent-object. some pages later there is a summary-page which shows all inserted data before he user can commit the wizard and save the new object.

    there are some issues.
    1. i need to commit all previous pages to be able to display the data inserted in the formModel on my summaryPage, but if the formModels are created as childFormModel, i get a uncommitable-exception, because the whole model isn't totally filled. so in this case the inserted data on a single page is valid, but the parent-Object isn't yet...
    2. i don't know how to add a rule, which says that there has to be at least one orderdetail before enabling the next-button, which would be a contraint on the size of a collection... is that possible?
    3. there is a point, where i have to define the next-page dynamiclly, because it depends on a previous selection. (e.g. payMethod)... the petclinic example only has static pages which are aded at startup, hopefully there is a way to have a default-page and others to which i can switch, when the payMethod is selected...

    any hints would be helpful...
    thanks sebastian

  9. #9
    Join Date
    Aug 2005
    Location
    Austin, TX
    Posts
    425

    Default

    Quote Originally Posted by gibelium
    today it's wizard-day...

    there are some issues.
    1. i need to commit all previous pages to be able to display the data inserted in the formModel on my summaryPage, but if the formModels are created as childFormModel, i get a uncommitable-exception, because the whole model isn't totally filled. so in this case the inserted data on a single page is valid, but the parent-Object isn't yet...
    2. i don't know how to add a rule, which says that there has to be at least one orderdetail before enabling the next-button, which would be a contraint on the size of a collection... is that possible?
    3. there is a point, where i have to define the next-page dynamiclly, because it depends on a previous selection. (e.g. payMethod)... the petclinic example only has static pages which are aded at startup, hopefully there is a way to have a default-page and others to which i can switch, when the payMethod is selected...

    any hints would be helpful...
    thanks sebastian
    Hi Sebastian,

    You should take a look at the Wizard, WizardPage, and WizardDialog classes for some more details on how things work, but I'll try to provide some pointers.

    1. Since you really have independent models, you will need to create separate form models to back the various wizard pages.

    2. Take a look at the "required" constraint. It is clever enough to ensure that properties that are collections or arrays contain elements if the required constraint is applied to them.

    3. In the Wizard interface, there are methods getNextPage and getPreviousPage that should provide you with the control you need to determine where to send the user next.

    HTH,
    Larry.

  10. #10

    Default

    thanks for the hints, larry...
    i took a short look in the code last evening, and i think i will start with extending wizard-page... anyway... the man which pays my roll wants to play with his little new baby on tuesday, so there won't be the time, implementing the new wizard...

    and i just noticed, that my dirty- and enabled-state seems to change right in the added master/detail chilForms, but reverting the parentModel does not revert stale details from the masterlists in childForms... there seems to be a hole in my usage of the formModel-concept... :/
    will get there... :-D

    happy easter...
    sebastian

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •