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

  • JTable Binding

    Hi all,

    While I was treating to bind a JTable to a formModel I have realized the method
    org.springframework.binding.form.support.AbstractF ormModel#add(String,ValueModel, FieldMetadata) doesn't register a dirty property change listener as org.springframework.binding.form.support.AbstractF ormModel#add(String,ValueModel, FieldMetadata) does.

    I need it because otherwise dirty tracking is lost.

    Thank you very much

  • #2
    You will want to bind to your collection (or array or whatever) and have your JTable/TableModel work with either the same collection or a copy. The control that your custom binding uses will be a JTable. More than likely most of the smarts will be in the custom TableModel that works with the table. My custom table mostly just configures its cell renderers and editors.

    Here's the basics of how I do it.

    1. My table model calls fireTableXXX() to notify of changes (and to get the ui to update).
    2. My JTable overrides tableChanged() to A: call super.tableChanged() B: firePropertyChange() to notify the binding of a change/dirty.
    3. The propertyChange() method in the binding sets the new value in the bound ValueModel.

    Note that when you call ValueModel.setValue() it checks if the new value is different. This difference is evaluated by calling .equals() if your class is known to implement equals (see DefaultValueChangeDetector) or just uses (oldValue != newValue) and therefore you would need to pass in a new object. Since I thought that creating a new collection each time was dumb I added my class to the list via:

    Code:
    ValueChangeDetector valueChangeDetector = (ValueChangeDetector) ApplicationServicesLocator.services().getServiceValueChangeDetector.class);
    if (valueChangeDetector instanceof DefaultValueChangeDetector) {
        DefaultValueChangeDetector o = (DefaultValueChangeDetector) valueChangeDetector;
        Set<Class> safeClasses = new HashSet<Class>();
        safeClasses.addAll(o.getClassesWithSafeEquals());
        safeClasses.add(GenericLineItems.class); //my collection class
        o.setClassesWithSafeEquals(safeClasses);
    }
    and implement equals() in my collection class to return false when dirty.

    You will probably need to give a little more info on what you are having problems with and show what you have implemented so far. From your other posts I am not sure you understand custom bindings.

    - Brad

    Comment


    • #3
      Than you very much

      I have spent a lot of time trying to resolve this issue before your answer. My solution is similar to yours, however I think this kind of situtations should be solved directly by the framework. Spring RCP is great but however is incomplete.

      In a typical binding there is a FieldMetadata instance that is notified about changes in the value model, later on the form model is notified by the field metada. So, there are two steps communication, well, in my opinion if you want to create a binding for collections using tables then you need to make fixes in each step in order to make it run.

      If someone needs more information I will be pleased to help you.

      Comment


      • #4
        After taking a look to this problem I suggest the following solution:

        Since the second add method signature is public the red line should be moved from the first method to the second one.

        Thank you very much!!!

        Code:
        public ValueModel add(String formProperty, ValueModel valueModel) {
        		// XXX: this assert should be active but it breaks the
        		// code in SwingBindingFactory#createBoundListModel
        		// Assert.isTrue(!hasValueModel(formProperty), "A property called '" +
        		// formProperty + "' already exists.");
        		if (valueModel instanceof BufferedValueModel) {
        			((BufferedValueModel) valueModel).setCommitTrigger(commitTrigger);
        		}
        
        		PropertyMetadataAccessStrategy metadataAccessStrategy = getFormObjectPropertyAccessStrategy()
        				.getMetadataAccessStrategy();
        
        		FormModelMediatingValueModel mediatingValueModel = new FormModelMediatingValueModel(valueModel,
        				metadataAccessStrategy.isWriteable(formProperty));
        		mediatingValueModels.put(formProperty, mediatingValueModel);
        
        		FieldMetadata metadata = new DefaultFieldMetadata(this, mediatingValueModel, metadataAccessStrategy
        				.getPropertyType(formProperty), !metadataAccessStrategy.isWriteable(formProperty),
        				metadataAccessStrategy.getAllUserMetadata(formProperty));
        		metadata.addPropertyChangeListener(FieldMetadata.DIRTY_PROPERTY,childStateChangeHandler);
        		return add(formProperty, mediatingValueModel, metadata);
        	}
        
        	/**
        	 * {@inheritDoc}
        	 */
        	public ValueModel add(String propertyName, ValueModel valueModel, FieldMetadata metadata) {
        
                        // Here
        		fieldMetadata.put(propertyName, metadata);
        
        		valueModel = preProcessNewValueModel(propertyName, valueModel);
        		propertyValueModels.put(propertyName, valueModel);
        
        		if (logger.isDebugEnabled()) {
        			logger.debug("Registering '" + propertyName + "' form property, property value model=" + valueModel);
        		}
        		postProcessNewValueModel(propertyName, valueModel);
        		return valueModel;
        	}

        Comment

        Working...
        X