/**
* Copyright (C) 2015 Valkyrie RCP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.valkyriercp.form;
import org.valkyriercp.binding.form.FormModel;
import org.valkyriercp.binding.form.ValidatingFormModel;
import org.valkyriercp.binding.validation.ValidationResultsModel;
import org.valkyriercp.core.Guarded;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Actually enables/disables registered 'guarded' objects based on the state of a
* {@link ValidatingFormModel}.
*
* One instance of this FormGuard supports multiple guarded objects on one formModel. Each guarded object can
* specify upon which state of the formModel it wants to be enabled:
*/
public class FormGuard implements PropertyChangeListener {
/** Guard-registration mask-bit indicating enabled() will be set only if the formmodel has no errors. */
public static final int ON_NOERRORS = 1;
/**
* Guard-registration mask-bit indicating enabled() will be set only if the formmodel has changes (is
* dirty).
*/
public static final int ON_ISDIRTY = 1 << 1;
/** Guard-registration mask-bit indicating enabled() will be set only if the formmodel is enabled. */
public static final int ON_ENABLED = 1 << 2;
/**
* Guard-registration mask-pattern indicating enabled() will be set just like is the case for the new-form
* command. i.e. as soon as the formmodel is enabled.
*/
public static final int LIKE_NEWFORMOBJCOMMAND = ON_ENABLED;
/**
* Guard-registration mask-pattern indicating enabled() will be set just like is the case for the revert
* command. i.e. only if the formmodel is enabled AND uncommitted changes are present.
*/
public static final int LIKE_REVERTCOMMAND = ON_ISDIRTY + LIKE_NEWFORMOBJCOMMAND;
/**
* Guard-registration mask-pattern indicating enabled() will be set just like is the case for the commit
* command. i.e. only if the formmodel is enabled AND uncomitted changes are presenent AND the model is
* valid.
*/
public static final int LIKE_COMMITCOMMAND = ON_NOERRORS + LIKE_REVERTCOMMAND;
/**
* Guard-registration mask-pattern indicating enabled() will be set only if the formmodel is both enabled
* and has no errors.
*/
public static final int FORMERROR_GUARDED = ON_ENABLED + ON_NOERRORS;
private final ValidatingFormModel formModel;
private final Map guardedEntries = Collections.synchronizedMap(new HashMap());
/**
* Creates the FormGuard monitoring the passed formModel.
*
* @param formModel
* which state-changes should be passed to registered guarded objects.
*/
public FormGuard(ValidatingFormModel formModel) {
this.formModel = formModel;
this.formModel.addPropertyChangeListener(FormModel.ENABLED_PROPERTY, this);
this.formModel.addPropertyChangeListener(ValidationResultsModel.HAS_ERRORS_PROPERTY, this);
this.formModel.addPropertyChangeListener(FormModel.DIRTY_PROPERTY, this);
}
/**
* Creates the FormGuard monitoring the passed formModel, and adds the passed guarded-object.
*
* For backwards compatibility this assumes the {@link #FORMERROR_GUARDED} mask.
*
* @param formModel
* which state-changes should be passed to registered guarded objects.
* @param guarded
* object that will get en/dis-abled
*/
public FormGuard(ValidatingFormModel formModel, Guarded guarded) {
this(formModel, guarded, FORMERROR_GUARDED);
}
/**
* Creates the FormGuard monitoring the passed formModel, and adds the passed guarded-object using the
* specified mask.
*
* @param formModel
* which state-changes should be passed to registered guarded objects.
* @param guarded
* object that will get en/dis-abled
* @param mask
* specifying what formModel state should enable the guarded object.
*/
public FormGuard(ValidatingFormModel formModel, Guarded guarded, int mask) {
this(formModel);
addGuarded(guarded, mask);
}
private void updateAllGuarded() {
int formState = getFormModelState();
Iterator guardedIter = this.guardedEntries.keySet().iterator();
while (guardedIter.hasNext()) {
Guarded guarded = (Guarded) guardedIter.next();
int mask = ((Integer) this.guardedEntries.get(guarded)).intValue();
boolean b = stateMatchesMask(formState, mask);
guarded.setEnabled(b);
}
}
private boolean stateMatchesMask(int formState, int mask) {
return ((mask & formState) == mask);
}
private int getFormModelState() {
int formState = 0;
if (!formModel.getHasErrors())
formState += ON_NOERRORS;
if (formModel.isDirty())
formState += ON_ISDIRTY;
if (formModel.isEnabled())
formState += ON_ENABLED;
return formState;
}
/**
* @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent e) {
updateAllGuarded();
}
/**
* Adds a guarded object to be guarded by this FormGuard
*
* @param newGuarded
* object to be guarded
* @param mask
* indicating which state of the formModel should enable the guarded obhject
*/
public void addGuarded(Guarded newGuarded, int mask) {
this.guardedEntries.put(newGuarded, new Integer(mask));
newGuarded.setEnabled(stateMatchesMask(getFormModelState(), mask));
}
/**
* Removes the guarded object from the management of this FormGuard.
*
* @param toRemove
* object that no longer should be managed
*
* @return <code>false</code> if the object toRemove was not present in the list of managed guarded objects.
*/
public boolean removeGuarded(Guarded toRemove) {
Object mask = this.guardedEntries.remove(toRemove);
return mask != null;
}
}