Announcement Announcement Module
Collapse
No announcement yet.
Updating old code: what happened with ListBinder.MODEL_KEY in v0.2 ? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Updating old code: what happened with ListBinder.MODEL_KEY in v0.2 ?

    Hi,

    I'm migrating from a very old, previous version of 0.1 to the head of the project and I'm experiencing some problems. One thing I can't get to work is the ListBinder.

    Previously, to create a JList I did the follow:
    Code:
    final SwingBindingFactory factory = (SwingBindingFactory) getBindingFactory();
    this.selectedPCsObservableList = factory
      .createBoundListModel(LineForm.SELECTED_PCS);
    
    Map<String, Object> context = new HashMap<String, Object>();
    context.put(AbstractListBinder.SELECTABLE_ITEMS_KEY, null);
    context.put(ListBinder.RENDERER_KEY, new BeanPropertyValueListRenderer(
      "code"));
    context.put(ListBinder.MODEL_KEY, this.selectedPCsObservableList);
    
    final Binding nodes = factory.createBinding(JList.class,
    LineForm.SELECTED_PCS, context);
    this.jlSelectedPCs = (JList) nodes.getControl();
    But ListBinder.MODEL_KEY doesn't exist anymore, and everytime I select one item in the list, instead of been selected, it disappears.
    The new code I'm trying is the follow:
    Code:
    final SwingBindingFactory factory = (SwingBindingFactory) getBindingFactory();
    this.selectedPCsObservableList = factory
      .createBoundListModel(LineForm.SELECTED_PCS);
    
    final Binding nodes = factory.createBoundList(LineForm.SELECTED_PCS,
    this.selectedPCsObservableList, "code",
    ListSelectionModel.SINGLE_SELECTION);
    I've tried some other signatures of SwingBindingFactory.createBoundList but them doesn't work as well.

    What should I do to keep the previous behaviour of JList?

    Thanks,

    Mauro.

  • #2
    I had some similar problems, but Matthias helped me and I 've documented them in /src/site/user/upgrading.apt (the SVN version).

    If it's not in there and you find a solution, could you provide a bit of text which I can add there if other users have this problem?

    Comment


    • #3
      please use

      ListBinder.SELECTABLE_ITEMS_KEY instead of ListBinder.MODEL_KEY. SELECTABLE_ITEMS_KEY now accepts any collection type including ListModel or ValueModel.

      Comment


      • #4
        Hi,

        Thanks for the replies! I've fixed the problem.
        I was doing right, the problem is the deprecated SwingBindingFactory.createBoundListModel(...), it should be avoided. The BufferedCollectionValueModel created by this method causes the strange "desapearing behaviour".
        Maybe this method should be removed. The only problem is that I don't know other Model with the same behaviour of BufferedCollectionValueModel.
        The great insight of BufferedCollectionValueModel is that when a form is commited the differences in the list are computed and the ValueObject is updated by consequence.
        I've tried to reproduce this behaviour with ListListModel, ValueHolder and DynamicListModel but them just commit the selected items, so I have to compute the differences manually.

        There's a good way to avoid this workaround?

        Thanks,

        Mauro Ransolin.

        Comment


        • #5
          IMO BufferedCollectionValueModel does a lot of (maybe unnecessary) things if only the changes of a collection should be "commited". BTW it also contains hacks to support some special use case like SortedSet ...

          I've not tested it but that should work without the use of BufferedCollectionValueModel to modify an existing collection:

          Code:
          Collection getSelection() {
            return mySelection; // no copy needed for this
          }
          
          void setSelection(Collection selection) {
            mySelection.retainAll(selection); // removes any "deselected" value
          
            // optional step if mySelection is not a Set
            selection.removeAll(mySelection); // removes all existing selected elements - the given collection can be modified without side effects if only used for bindings
          
            mySelection.addAll(selection); // add all new "selected" values
          }
          But I'm still not sure if I really understand the usecase for BufferedCollectionValueModel ...

          Comment


          • #6
            Hi Mathias,

            Thanks for the reply.

            My use case is the follow:
            In a screen, on the left side is a list with all possible values to be choosen. On the right side is another list with 'choosen' values (not graphicaly selected, but choosen by the user).
            The user have 2 commands, one add values to choosen list, other to remove. The user change the list of choosen values by adding and removing.
            Previously to V 0.2.0 when a form had been commited all the values of 'choosen' collection were commited, without the need of been selected.
            Now, it's necessary to force the selection of all elements of the list before commiting. This happens to be because the list now commits the selected values only.
            What I'm looking for is a easy method to keep the previous behaviour without the need of workarrounds like force the selection of all values. Furthermore, to force the selection would be a problem if the selection mode is single_selection.

            Thanks,

            Mauro.

            Comment


            • #7
              Try using ShuttleList

              Hi Mauro,

              Your described use case sounds like you could use a ShuttleList component. It is in the sandbox, package org.sprinframework.richclient.components, together with a ShuttleListBinder and ShuttleListBinding. Have a look at that stuff. I have not used it myself yet , so I'd be interested to hear whether it helped you.

              Andrius

              Comment


              • #8
                A proposal to ListBinder

                Hi Andrius,

                Thanks for the tip! ShuttleList is a very nice component and reflects exactly my use case, but unfortunately due to the schedule of the project I can't refactor the interfaces at this time.
                Also, I have other use cases with lists where I'm having to force the full selection, but it's an ugly workarround.
                I think the ListBinder could have a property called "COMMIT_MODE" (or "HOLDING_MODE") with values "ALL_ITEMS" and "SELECTED_ITEMS". If ALL_ITEMS is choosen, the ValueModel holds all the items of the list, otherwise, it holds the values according with the selection mode. The default could be SELECTED_ITEMS.

                I would like to know what you and Mathias think about the idea. If do you think it's a good one, I could propose a voting at dev-list.

                Thanks,

                Mauro.

                Comment


                • #9
                  IMO a custom binder for your use case would be the best.

                  Comment


                  • #10
                    Hi,

                    Thanks Mathias, sometimes someone have to tell what you have to do!
                    I've created the binding.
                    It's very nice to see how easy is to customize the Spring RCP. Congratulations to the RCP Team!

                    Code:
                    /*
                     * $Id:$
                     * Wplex Software Ltda.
                     */
                    
                    package com.wplex.framework.client.form.binding;
                    
                    /**
                     * Binder for <code>FullSelectionListBinding</code>.
                     * 
                     * @author Mauro Ransolin
                     * @version $Revision:$
                     */
                    public class FullSelectionListBinder extends ListBinder {
                        /**
                         * Key for holdingMode.
                         * @see FullSelectionListBinding.ListHoldingMode
                         */
                        public static final String HOLDING_MODE_KEY = "holdingMode"; //$NON-NLS-1$
                    
                        /**
                         * @see ListBinder#ListBinder()
                         */
                        public FullSelectionListBinder() {
                            this(null, new String[] { SELECTABLE_ITEMS_KEY, COMPARATOR_KEY,
                                RENDERER_KEY, FILTER_KEY, SELECTION_MODE_KEY, HOLDING_MODE_KEY });
                        }
                    
                        /**
                         * @see ListBinder#ListBinder(String[])
                         */
                        public FullSelectionListBinder(String[] supportedContextKeys) {
                            this(null, supportedContextKeys);
                        }
                    
                        /**
                         * @see ListBinder#ListBinder(Class, String[])
                         */
                        public FullSelectionListBinder(Class requiredSourceClass,
                            String[] supportedContextKeys) {
                            super(requiredSourceClass, supportedContextKeys);
                        }
                    
                        protected AbstractListBinding createListBinding(JComponent control,
                            FormModel formModel, String formPropertyPath) {
                            Assert.isInstanceOf(JList.class, control);
                            return new FullSelectionListBinding((JList) control, formModel,
                                formPropertyPath, getRequiredSourceClass());
                        }
                    
                        protected void applyContext(AbstractListBinding binding, Map context) {
                            super.applyContext(binding, context);
                    
                            FullSelectionListBinding listBinding = (FullSelectionListBinding) binding;
                    
                            if (context.containsKey(HOLDING_MODE_KEY))
                                listBinding.setHoldingMode((ListHoldingMode) context
                                    .get(HOLDING_MODE_KEY));
                            else
                                listBinding.setHoldingMode(ListHoldingMode.ALL_ITEMS);
                        }
                    
                    }
                    Code:
                    /*
                     * $Id:$
                     * Wplex Software Ltda.
                     */
                    package com.wplex.framework.client.form.binding;
                    
                    /**
                     * A Binding that provides the option to hold all the values of the list,
                     * without the need of forcing full selection.
                     * 
                     * @author Mauro Ransolin
                     * @version $Revision:$
                     */
                    public class FullSelectionListBinding extends ListBinding {
                        private static final Object[] EMPTY_VALUES = new Object[0];
                    
                        private final PropertyChangeListener valueModelListener = new ValueModelListener();
                    
                        private final ListSelectionListener selectionListener = new SelectionListener();
                    
                        private final ValueListener valueListener = new ValueListener();
                    
                        boolean selectingValues;
                    
                        private ListHoldingMode holdingMode;
                    
                        public FullSelectionListBinding(JList list, FormModel formModel,
                            String formFieldPath, Class requiredSourceClass) {
                            super(list, formModel, formFieldPath, requiredSourceClass);
                        }
                    
                        protected void updateSelectedItemsFromSelectionModel() {
                            if (ListHoldingMode.ALL_ITEMS.equals(this.holdingMode)) {
                                ListModel model = getList().getModel();
                                Object[] values;
                    
                                if (model instanceof ObservableList) {
                                    ObservableList oList = (ObservableList) model;
                                    values = oList.toArray();
                                }
                                else
                                    values = toArray(model);
                    
                                if (!updateCollectionValue(values))
                                    getValueModel().setValueSilently(convertSelectedValues(values),
                                        this.valueModelListener);
                            }
                            else {
                                if (getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
                                    Object singleValue = getList().getSelectedValue();
                                    if (!updateCollectionValue(new Object[] { singleValue }))
                                        getValueModel().setValueSilently(singleValue,
                                            this.valueModelListener);
                                }
                                else {
                                    Object[] values = getList().getSelectedValues();
                                    if (!updateCollectionValue(values))
                                        getValueModel().setValueSilently(
                                            convertSelectedValues(getList().getSelectedValues()),
                                            this.valueModelListener);
                                }
                            }
                        }
                    
                        private Object[] toArray(ListModel model) {
                            Object[] array = new Object[model.getSize()];
                    
                            for (int i = 0; i < model.getSize(); i++)
                                array[i] = model.getElementAt(i);
                    
                            return array;
                        }
                    
                        private boolean updateCollectionValue(Object[] values) {
                            if (Collection.class.isAssignableFrom(getPropertyType())) {
                                Collection<Object> value = (Collection<Object>) getValue();
                                if (value != null) {
                                    try {
                                        value.clear();
                                        value.addAll(Arrays.asList(values));
                                        return true;
                                    }
                                    catch (UnsupportedOperationException e) {
                                        return false;
                                    }
                                }
                            }
                            return false;
                        }
                    
                        protected void doBindControl(ListModel bindingModel) {
                            JList list = getList();
                            list.setModel(bindingModel);
                            if (ListHoldingMode.ALL_ITEMS.equals(this.holdingMode))
                                getList().getModel().addListDataListener(this.valueListener);
                            else
                                list.getSelectionModel().addListSelectionListener(
                                    this.selectionListener);
                            getValueModel().addValueChangeListener(this.valueModelListener);
                    
                            if (!isPropertyConversionExecutorAvailable()
                                && getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) {
                                if (this.logger.isWarnEnabled()) {
                                    this.logger.warn("Selection mode for list field " //$NON-NLS-1$
                                        + getProperty() + " forced to single selection." //$NON-NLS-1$
                                        + " If multiple selection is needed" //$NON-NLS-1$
                                        + " use a collection type" //$NON-NLS-1$
                                        + " (List, Collection, Object[])" //$NON-NLS-1$
                                        + " or provide a suitable converter" //$NON-NLS-1$
                                        + " to convert Object[] instances to property type " //$NON-NLS-1$
                                        + getPropertyType());
                                }
                                setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                            }
                            updateSelectedItemsFromValueModel();
                        }
                    
                        /**
                         * Updates the selection model with the selected values from the value model.
                         */
                        protected void updateSelectedItemsFromValueModel() {
                            Object value = getValue();
                            Object[] selectedValues = EMPTY_VALUES;
                            if (value != null) {
                                selectedValues = (Object[]) convertValue(value, Object[].class);
                            }
                    
                            this.selectingValues = true;
                            try {
                                JList list = getList();
                                ListSelectionModel selectionModel = list.getSelectionModel();
                                selectionModel.setValueIsAdjusting(true);
                                try {
                                    int[] valueIndexes = determineValueIndexes(selectedValues);
                                    int selectionMode = getSelectionMode();
                                    if (ListHoldingMode.SELECTED_ITEMS.equals(this.holdingMode)) {
                                        if (selectionMode == ListSelectionModel.SINGLE_SELECTION
                                            && valueIndexes.length > 1)
                                            list.setSelectedIndex(valueIndexes[0]);
                                        else
                                            list.setSelectedIndices(valueIndexes);
                                    }
                    
                                    if (valueIndexes.length != selectedValues.length
                                        && !isReadOnly()
                                        && isEnabled()
                                        || (selectionMode == ListSelectionModel.SINGLE_SELECTION && valueIndexes.length > 1)) {
                                        updateSelectedItemsFromSelectionModel();
                                    }
                                }
                                finally {
                                    selectionModel.setValueIsAdjusting(false);
                                }
                            }
                            finally {
                                this.selectingValues = false;
                            }
                        }
                    
                        /**
                         * @param holdingMode
                         */
                        public void setHoldingMode(ListHoldingMode holdingMode) {
                            this.holdingMode = holdingMode;
                        }
                    
                        /**
                         * Defines the behaviour of ValueModel.
                         */
                        public enum ListHoldingMode {
                            /**
                             * The ValueModel holds only the selected values, according with
                             * SELECTION_MODE.
                             */
                            SELECTED_ITEMS,
                    
                            /**
                             * The ValueModel holds all the values of the list, despite the
                             * SELECTION_MODE.
                             */
                            ALL_ITEMS;
                        }
                    
                       protected class ValueListener implements ListDataListener {
                    
                            public void contentsChanged(ListDataEvent e) {
                                updateSelectedItemsFromSelectionModel();
                            }
                    
                            public void intervalAdded(ListDataEvent e) {
                                updateSelectedItemsFromSelectionModel();
                            }
                    
                            public void intervalRemoved(ListDataEvent e) {
                                updateSelectedItemsFromSelectionModel();
                            }
                        }
                    
                        protected class ValueModelListener implements PropertyChangeListener {
                    
                            public void propertyChange(PropertyChangeEvent evt) {
                                updateSelectedItemsFromValueModel();
                            }
                        }
                    
                        protected class SelectionListener implements ListSelectionListener {
                    
                            public void valueChanged(ListSelectionEvent e) {
                                if (!FullSelectionListBinding.this.selectingValues
                                    && !e.getValueIsAdjusting()) {
                                    updateSelectedItemsFromSelectionModel();
                                }
                            }
                        }
                    }
                    BTW, if someone is interested, I've created the BinderSelectionStrategy, BinderFactory and the BinderFactoryProvider and can send by mail.

                    Thanks,

                    Mauro.
                    Last edited by Manus; Sep 14th, 2006, 12:48 PM.

                    Comment

                    Working...
                    X