Ошибки проверки блокируют отмену

У меня есть следующая проблема с моим приложением Eclipse на основе EMF:

Отмена работает отлично. Проверка работает отлично. Но когда есть ошибка проверки данных в поле GUI, это блокирует использование действия отмены. Например, невозможно отменить, чтобы вернуться в правильное состояние для этого поля.

На этой картинке невозможно использовать отмену:

Не очень информативное изображение, которое, как мы надеемся, делает вопрос немного более интересным


Инструменты, которые используются в приложении:

  • Eclipse привязка данных
  • UpdateValueStrategys на привязках для проверки
  • Отмена реализована с использованием стандартных UndoAction что вызывает CommandStack.undo
  • MessageManagerSupport класс, который соединяет платформу валидации с графическим интерфейсом на основе Eclipse Forms.

Привязки данных выглядят так:

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

Проблема заключается в следующем:

  • Система отмены работает с командами, которые изменяют модель.
  • Система проверки останавливает доступ обновлений к модели при возникновении ошибок проверки.

Чтобы отменить работу, когда есть ошибки проверки, я думаю, я мог бы сделать одну из следующих вещей:

  1. Заставьте систему отмены работать на уровне GUI. (Это было бы огромным изменением, возможно, вообще невозможно использовать EMF для этого.)
  2. Сделайте недопустимые данные в командах запуска GUI, которые изменяют данные модели, так же, как это делают действительные данные. (Это было бы хорошо, если данные не могут быть сохранены на диск. Но я не могу найти способ сделать это.)
  3. Сделать проверку работоспособной непосредственно на модели, может быть вызвана слушателем контента на Resource, (Это большое изменение в стратегии валидации. На данном этапе не представляется возможным отследить исходный графический интерфейс пользователя.)

Эти решения либо кажутся невозможными, либо имеют серьезные недостатки.

Каков наилучший способ отменить работу, даже если есть ошибки проверки?


ПРИМЕЧАНИЕ: я принимаю ответ Mad Matts, потому что их предложения приводят меня к моему решению. Но я не очень доволен этим и хотел бы, чтобы был лучше.

Если кто-то когда-нибудь найдет лучшее решение, я буду рад принять его вместо текущего!

2 ответа

Решение

Имеет смысл, что Валидатор защищает целевое значение от недопустимых значений. Поэтому целевое командное хранилище остается нетронутым в случае недопустимого значения. Почему вы хотите установить недопустимые значения? не ctrl + z в графическом интерфейсе достаточно для сброса последнего действительного состояния?

Если вы все еще хотите установить эти значения в своей реальной целевой модели, вы можете поиграть с UpdateValueStrategy,

Фазы обновления:

  1. Подтвердить после получения - validateAfterGet(Object)

  2. Конвертация - конвертация (Объект)

  3. Проверить после преобразования - validateAfterConvert(Object)

  4. Проверка перед набором - validateBeforeSet (Object)

  5. Набор значений - doSet(IObservableValue, Object)

Я не уверен, где ошибка проверки (Status.ERROR) происходит точно, но вы можете проверить, где, а затем заставить SetCommand вручную. Вы можете установить пользовательские IValidator за каждый шаг к вашему UpdateValueStrategy сделать это.

ПРИМЕЧАНИЕ. Это решение, которое я использовал в своем приложении. Я не очень доволен этим. Я думаю, что это немного взломать.

Я принимаю Mad Matts ответ, потому что их предложения приводят меня к этому решению.

Если кто-то когда-нибудь найдет лучшее решение, я буду рад принять его вместо текущего!


Я закончил тем, что создал UpdateValueStratety подкласс, который запускает валидатор после того, как значение было установлено на объекте модели. Кажется, это работает нормально.

Я создаю этот ответ, чтобы опубликовать код, который я использовал. Вот:

/**
 * An {@link UpdateValueStrategy} that can perform validation AFTER a value is set
 * in the model. This is used because undo dosen't work if no model changed in made.
 */
public class LateValidationUpdateValueStrategy extends UpdateValueStrategy {

    private IValidator afterSetValidator;

    public void setAfterSetValidator(IValidator afterSetValidator) {
        this.afterSetValidator = afterSetValidator;
    }

    @Override
    protected IStatus doSet(IObservableValue observableValue, Object value) {
        IStatus setStatus = super.doSet(observableValue, value);

        if (setStatus.getSeverity() >= IStatus.ERROR || afterSetValidator == null) {
            return setStatus;
        }

        // I used a validator here that calls the EMF generated model validator.
        // In that way I can specify validation of the model.
        IStatus validStatus = afterSetValidator.validate(value); 

        // Merge the two statuses
        if (setStatus.isOK() && validStatus.isOK()) {
            return validStatus;
        } else if (!setStatus.isOK() && validStatus.isOK()) {
            return setStatus;
        } else if (setStatus.isOK() && !validStatus.isOK()) {
            return validStatus;
        } else {
            return new MultiStatus(Activator.PLUGIN_ID, -1, 
                new IStatus[] { setStatus, validStatus },
                setStatus.getMessage() + "; " + validStatus.getMessage(), null);
        }
    }
}
Другие вопросы по тегам