Bug 119791 - [DataBinding] Need isDirty() and save()
Summary: [DataBinding] Need isDirty() and save()
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.1   Edit
Hardware: PC Linux
: P3 enhancement with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: Dave Orme CLA
QA Contact:
URL:
Whiteboard:
Keywords: helpwanted
Depends on:
Blocks:
 
Reported: 2005-12-07 22:48 EST by Dave Orme CLA
Modified: 2019-09-06 16:19 EDT (History)
14 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dave Orme CLA 2005-12-07 22:48:59 EST
Jim Leotta in the newsgroup inquired about if we have a concept of isDirty() in the JFace data binding framework.  The current answer is "no" and I agree that we need one.

Here is how I suggest we make it work:

1) IUpdatables should have an isDirty() and a save() method.

2) We should return the Binding object we create or some interface that defines the external API to this binding object.  This Binding object should also define isDirty() and save() methods.

3) An IDataBindingContext should keep track of the Bindings it has created, and also have API for isDirty() (that would query each Binding it owns) and for save().

4) These would provide the places we could put the life cycle events described in bug #118323.
Comment 1 Boris Bokowski CLA 2005-12-08 08:33:42 EST
Why is it not sufficient to have isDirty() and save() on IDataBindingContext?
Comment 2 Dave Orme CLA 2005-12-08 09:12:48 EST
(In reply to comment #1)
> Why is it not sufficient to have isDirty() and save() on IDataBindingContext?

1) We will need isDirty() and save() on an IUpdatable and/or a Binding anyway in order to implement it on IDataBindingContext.  (Otherwise, what will IDataBindingContext delegate to?)

2) Sometimes one would like to know about isDirty() and save() at a lower level of granularity than IDataBindingContext.
Comment 3 Dave Orme CLA 2005-12-08 09:13:13 EST
s/lower level of granularity/finer level of granulatity/
Comment 4 Boris Bokowski CLA 2005-12-08 09:50:00 EST
Yes, I agree we will need isDirty() and save() on Binding. However, this class is internal, and if possible, I would like to keep it internal for now. If you need a finer level of granularity, you can create a child databinding context (do we still support that?).

I don't know what isDirty() or save() would mean for an IUpdatable. To me, these methods are an "edge" thing.
Comment 5 Dave Orme CLA 2005-12-08 10:12:06 EST
(In reply to comment #4)
> Yes, I agree we will need isDirty() and save() on Binding. However, this class
> is internal, and if possible, I would like to keep it internal for now.

Agreed.  Suggest that we have an IBinding interface (implemented by Binding) and return that instead of returning the actual Binding object.

> If you
> need a finer level of granularity, you can create a child databinding context
> (do we still support that?).

I don't think we do.  But I think that having Binding and DBC-level granularity is probably adaquate.

> I don't know what isDirty() or save() would mean for an IUpdatable. To me,
> these methods are an "edge" thing.

Hmmmmm....  On second thought, I think you're right about this.
Comment 6 Boris Bokowski CLA 2005-12-08 10:36:29 EST
> Agreed.  Suggest that we have an IBinding interface (implemented by Binding)
> and return that instead of returning the actual Binding object.

I suggest that we reintroduce parent binding contexts (so that you can set up your factories once per application, and have finer level of granularity for save() if needed), and that we don't expose Binding at all (not even as IBinding).

Now that I think about it, I would suggest just one new method on IDatabindingContext:
public IUpdatableValue getDirtyState()

The use case I have in mind for isDirty(), save(), and potentially , is a dialog or preference page where you would like to enable the "OK" or "Save" button when there are changes, and only when you click the button should the model be updated. You could bind the enablement state of the OK button to the updatable returned by getDirtyState(), and call getDirtyState().setValue(Boolean.FALSE) to have the model updated.

What are the use cases you had in mind? What do you need the IBinding type for? If you need it, wouldn't you be interested in state changes (i.e. a listener on an IBinding that is notified when isDirty() becomes true)?

Note that by returning an updatable from getDirtyState(), you get the equivalents of isDirty() and save(), and you get notification support.
Comment 7 Dave Orme CLA 2005-12-08 13:43:42 EST
(In reply to comment #6)
> > Agreed.  Suggest that we have an IBinding interface (implemented by Binding)
> > and return that instead of returning the actual Binding object.
> 
> I suggest that we reintroduce parent binding contexts (so that you can set up
> your factories once per application, and have finer level of granularity for
> save() if needed), and that we don't expose Binding at all (not even as
> IBinding).

I'm not thrilled with this but I can live with it.  From an API perspective, it seems cleaner to return an IBinding that one can ask isDirty(), validate(), and save().

> Now that I think about it, I would suggest just one new method on
> IDatabindingContext:
> public IUpdatableValue getDirtyState()
> 
> The use case I have in mind for isDirty(), save(), and potentially , is a
> dialog or preference page where you would like to enable the "OK" or "Save"
> button when there are changes, and only when you click the button should the
> model be updated. You could bind the enablement state of the OK button to the
> updatable returned by getDirtyState(), and call
> getDirtyState().setValue(Boolean.FALSE) to have the model updated.

This is nice!

> What are the use cases you had in mind? What do you need the IBinding type for?
> If you need it, wouldn't you be interested in state changes (i.e. a listener on
> an IBinding that is notified when isDirty() becomes true)?

Returning an IBinding is definitely nicer.

The use-case is where you need to iterate through a bunch of fields, and call validate() on each one of them.  And only if they all validate() do you then call save().

> Note that by returning an updatable from getDirtyState(), you get the
> equivalents of isDirty() and save(), and you get notification support.

Yes.  I like this.

But we need validation support too so you can implement only-save-if-a-bunch-of-things-are-valid semantics.

But I have a question:  Sometimes you need to force the dirty flag to false.  How would we handle this?

Comment 8 Dave Orme CLA 2005-12-08 13:47:20 EST
>> Returning an IBinding is definitely nicer.

should be:

Returning an IUpdatable is definitely nicer.

Sorry.  My brain isn't working today.  :-(
Comment 9 Wolfgang Herr CLA 2006-01-19 11:31:09 EST
Our requirement include:

When the validation of a user input has failed, the user should be notified about the validation error and the control should be marked accordingly (
for example with a yellow background of the swt control).

We think that the developer must be able to find out about which elements are dirty and which are not. Although sometimes the global information about the "dirtiness" of the overall binding may be sufficient.

We think that the dirty information of the IUpdate-able or binding must be combined with the possibility to mark the swt-control visibly as invalid, as it is usually or often done in thin and rich clients.

We do not think that the split up of the binding context is not the right way, because it would end up with a solution of using a binding context for each binding.

Additionally it would be useful to know more about an error than only the String-message. Returning an error Object may be useful, e.g. the error Object could include a severity code (warning or error), a error ID, style information, ...

We think, the following extensions are useful to fulfill the requirements above:
1.) isDirty() for IUpdatable and IDataBindingContext
2.) set/clear the isDirty Flag after Validation within updateModelFromTarget and updateTargetFromModel in the Binding class
3.) automatic, configerable feedback to the swt-control, that the validation failed and the target could not be updated and the IUpdatable is in a dirty state
4.) The validation error object could be available additional to the dirty state, so you can find out, why the error happened.

Comment 10 Dave Orme CLA 2006-02-07 22:21:50 EST
Proposed solution:

Add

boolean isDirty();
boolean canSave();
boolean save();

to IBinding and IDataBindingContext.

Also, possibly add dirtiness information to the binding event.
Comment 11 Wolfgang Herr CLA 2006-03-28 07:54:36 EST
very nice would be an active Information, if the validation (and also business-validation) has failed in the ValueBinding:
eg:
public void updateModelFromTarget(...) {
...
  validationError = doValidate(e.originalValue);
  if (validationError != null) {
    e.pipelinePosition = BindingEvent.PIPELINE_AFTER_VALIDATION_FAILED;
    fireBindingEvent(e);
    context.updatePartialValidationError(targetChangeListener, validationError);
    return;
  }
...
}

Is there any other possibility to recognize, that a validation has failed?
Comment 12 Boris Bokowski CLA 2006-03-29 08:52:04 EST
> Is there any other possibility to recognize, that a validation has failed?

Binding.getValidationError()?
Comment 13 Wolfgang Herr CLA 2006-03-30 07:55:36 EST
(In reply to comment #12)
> > Is there any other possibility to recognize, that a validation has failed?
> 
> Binding.getValidationError()?
> 

Ok, one requirement is, to mark an Control, if the validation fails. So my way to solve this problem was the following:

Having a BindindListener that does this for me:
  public String bindingEvent(BindingEvent event) {
    ...
    if (event.eventType == BindingEvent.EVENT_COPY_TO_MODEL && 
       (event.pipelinePosition == BindingEvent.PIPELINE_AFTER_VALIDATION_FAILED)  {
      // set the controls Background to yellow
    }
    ...
  }


> Binding.getValidationError()?
What do you think, this method should do?

Maybe it can be useful, to have a possibility to trigger a validation by hand from my BindingListener after the PIPELINE_AFTER_GET-Event is fired, but then the validation would run twice (if it is succesful), so i think it would make much more sense to be informed from the editing lifecycle (https://bugs.eclipse.org/bugs/show_bug.cgi?id=118323).
Comment 14 Boris Bokowski CLA 2006-03-30 08:31:20 EST
Binding.getValidationError already exists, it returns an IObservableValue that holds a ValidationError, or null if validation succeeded.

One way to use this observable is as follows:

Text text = ...;
final IObservableValue val =
        dbc.bind(text, property, null).getValidationError();
new ControlUpdater(text) {
  protected void updateControl() {
    text.setBackground(b.getValidationError().getValue()==null?white:yellow);
  }
}

I admit that this feels a little heavyweight, so we might want to add the additional event type too. Dave, what do you think?
Comment 15 Dave Orme CLA 2006-03-30 08:46:44 EST
(In reply to comment #14)
> I admit that this feels a little heavyweight, so we might want to add the
> additional event type too. Dave, what do you think?

I think we need the additional event type.  It's not a hard change either.

I've copied this comment over to the bug about the binding events so we don't forget. (bug 118323)
Comment 16 Boris Bokowski CLA 2006-05-10 23:21:14 EDT
Changing priority to P2.
Comment 17 Andrey Tarantsov CLA 2007-07-29 17:51:11 EDT
I think that dirty state makes sense only if you have specified a POLICY_CONVERT policy for the update strategy. So I think that a dirty state concept applies to each side of the two-way Binding, not to observables themselve.

Based on that, I think that a DataBindingContext could have two aggregate methods, like:

IObservableValue<Boolean> getTargetToModelUpdatesPending();
IObservableValue<Boolean> getTargetToModelUpdatesPending();

Actually it could be observable sets of dirty Bindings, rather than observable boolean values.

What I don't see is a need for a new event type in observables (I can't imagine what 'dirty' could mean for an arbitrary observable), or a notion of a dirty state of an observable.
Comment 18 Andrey Tarantsov CLA 2007-07-29 17:51:57 EDT
Oops, meant:

IObservableValue<Boolean> getTargetToModelUpdatesPending();
IObservableValue<Boolean> getModelToTargetUpdatesPending();
Comment 19 Boris Bokowski CLA 2007-08-03 08:25:07 EDT
Andrey, would you be interested in contributing a solution for this?
Comment 20 Andrey Tarantsov CLA 2007-08-03 14:01:46 EDT
Yes. Any suggestions before I start?
Comment 21 Boris Bokowski CLA 2007-08-03 18:28:32 EDT
> Actually it could be observable sets of dirty Bindings, rather than observable
> boolean values.

I would prefer this solution over the one that returns IObservable<Boolean>. Other than that, it would be good to have an example or snippet with which we can demonstrate what this API can be used for in practice.
Comment 22 Boris Bokowski CLA 2008-04-13 01:45:05 EDT
For the Eclipse Project, P2 means "we'd rather not ship without fixing these". Adjusting priority accordingly.
Comment 23 Matthew Hall CLA 2009-07-03 13:23:25 EDT
lafeuil@gmail.com: this conversation has been wide ranging--would you clarify what exactly you voted for?
Comment 24 Thomas Champagne CLA 2009-07-08 08:33:24 EDT
(In reply to comment #23)
> lafeuil@gmail.com: this conversation has been wide ranging--would you clarify
> what exactly you voted for?
> 

I try to create an editor for my model and I use the databinding API to validate and to bind my object with my model. 
But, I don't find a way to override the method isDirty in the EditorPart. 

So, I voted for this bug because I think it is a good solution if the IDataBindingContext have a isDirty() method. 

I'm very newbie with DataBinding, it is possible I say bullshit.
Comment 25 Matthew Hall CLA 2009-07-09 19:53:19 EDT
Thomas, I don't think that DataBindingContext can really help you here--the class isn't really designed for the editor lifecycle.  A better approach would be to observe all your model objects inside your editor model, and set the dirty flag the first time your model is modified.  Then clear the flag on save / revert.  If you care to post some example code outlining your editor model to the eclipse.platform.jface newsgroup I'd be happy to assist you there.  Please put "[DataBinding]" at the beginning of the subject to make sure we notice your question.
Comment 26 James Leotta CLA 2009-07-09 23:05:09 EDT
(In reply to comment #25)
> Thomas, I don't think that DataBindingContext can really help you here--the
> class isn't really designed for the editor lifecycle.  A better approach would
> be to observe all your model objects inside your editor model, and set the
> dirty flag the first time your model is modified.  Then clear the flag on save
> / revert.  If you care to post some example code outlining your editor model to
> the eclipse.platform.jface newsgroup I'd be happy to assist you there.  Please
> put "[DataBinding]" at the beginning of the subject to make sure we notice your
> question.

So are you saying we should duplicate all the listeners that are already in the databindind framework so that we know when a object is changed?
Comment 27 Boris Bokowski CLA 2009-07-10 11:42:45 EDT
Typically, you will want to support undo/redo in an editor, which means that you need a representation of the edit operations anyway. If there are no operations to undo, your editor is not dirty.
Comment 28 Matthew Hall CLA 2009-07-10 13:02:25 EDT
(In reply to comment #26)
> So are you saying we should duplicate all the listeners that are already in the
> databindind framework so that we know when a object is changed?

For the moment, yes.  There are still certain scenarios that DataBinding is not well equipped to handle yet, and the dirty/saved editor scenario is one of them.

If you use the Eclipse undo/redo command stack, you may want to participate in bug 116465 which I think we will be able to move forward on during 3.6.

Also, EMF already supports undo/redo integration if that is a possibility on your project.
Comment 29 Eclipse Webmaster CLA 2019-09-06 16:19:02 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.