Community
Participate
Working Groups
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.
Why is it not sufficient to have isDirty() and save() on IDataBindingContext?
(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.
s/lower level of granularity/finer level of granulatity/
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.
(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.
> 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.
(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?
>> Returning an IBinding is definitely nicer. should be: Returning an IUpdatable is definitely nicer. Sorry. My brain isn't working today. :-(
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.
Proposed solution: Add boolean isDirty(); boolean canSave(); boolean save(); to IBinding and IDataBindingContext. Also, possibly add dirtiness information to the binding event.
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?
> Is there any other possibility to recognize, that a validation has failed? Binding.getValidationError()?
(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).
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?
(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)
Changing priority to P2.
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.
Oops, meant: IObservableValue<Boolean> getTargetToModelUpdatesPending(); IObservableValue<Boolean> getModelToTargetUpdatesPending();
Andrey, would you be interested in contributing a solution for this?
Yes. Any suggestions before I start?
> 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.
For the Eclipse Project, P2 means "we'd rather not ship without fixing these". Adjusting priority accordingly.
lafeuil@gmail.com: this conversation has been wide ranging--would you clarify what exactly you voted for?
(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.
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.
(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?
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.
(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.
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.