Search code examples
data-bindingeclipse-emfemfeclipse-databinding

Validation errors block undo


I have the following problem with my EMF based Eclipse application:

Undo works fine. Validation works fine. But when there is a validation error for the data in a GUI field, this blocks the use of the undo action. For example, it is not possible to undo to get back to a valid state for that field.

In this picture it is not possible to use undo:

Not very informative image which hopefully makes the question a little more fun to look at.


Tools that are used in the application:

  • Eclipse data binding
  • UpdateValueStrategys on the bindings for validation
  • Undo is implemented using standard UndoAction that calls CommandStack.undo
  • A MessageManagerSupport class that connects the validation framework to the Eclipse Forms based GUI.

The data bindings look like this:

dataBindingContext.bindValue(WidgetProperties.text(...), 
    EMFEditProperties.value(...), validatingUpdateStrategy, null);

The problem is this:

  • The undo system works on the commands that change the model.
  • The validation system stops updates from reaching to model when there are validation errors.

To make undos work when there are validation errors I think I could do one of these different things:

  1. Make undo system work on the GUI layer. (This would be a huge change, it's probably not possible to use EMF for this at all.)
  2. Make the invalid data in the GUI trigger commands that change the model data, in the same way as valid data does. (This would be okay as long as the data can not be saved to disk. But I can't find a way to do this.)
  3. Make the validation work directly on the model, maybe triggered by a content listener on the Resource. (This is a big change of validation strategy. It doesn't seem possible to track the source GUI control in this stage.)

These solutions either seem impossible or have severe disadvantages.

What is the best way to make undo work even when there are validation errors?


NOTE: I accept Mad Matts answer because their suggestions lead me to my solution. But I'm not really satisfied with that and I wish there was a better one.

If someone at some time finds a better solution I'd be happy to consider to accept it instead of the current one!


Solution

  • It makes sense that the Validator protects your Target value from invalid values. Therefor the target commandstack remains untouched in case of an invalid value. Why would you like to force invalid values being set? Isn't ctrl + z in the GUI enough to reset the last valid state?

    If you still want to set these values to your actual Target model, you can play around with the UpdateValueStrategy.

    The update phases are:

    1. Validate after get - validateAfterGet(Object)

    2. Conversion - convert(Object)

    3. Validate after conversion - validateAfterConvert(Object)

    4. Validate before set - validateBeforeSet(Object)

    5. Value set - doSet(IObservableValue, Object)

    I'm not sure where the validation error (Status.ERROR) occurs exactly, but you could check where and then force a SetCommand manually. You can set custom IValidator for each step to your UpdateValueStrategy to do that.