001 /*
002 * Copyright 2002-2005 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.richclient.form;
017
018 import java.beans.PropertyChangeEvent;
019 import java.beans.PropertyChangeListener;
020 import java.util.Collections;
021 import java.util.HashMap;
022 import java.util.Iterator;
023 import java.util.Map;
024
025 import org.springframework.binding.form.FormModel;
026 import org.springframework.binding.form.ValidatingFormModel;
027 import org.springframework.binding.validation.ValidationResultsModel;
028 import org.springframework.richclient.core.Guarded;
029
030 /**
031 * Actually enables/disables registered 'guarded' objects based on the state of a
032 * {@link org.springframework.binding.form.ValidatingFormModel}.
033 *
034 * One instance of this FormGuard supports multiple guarded objects on one formModel. Each guarded object can
035 * specify upon which state of the formModel it wants to be enabled:
036 */
037 public class FormGuard implements PropertyChangeListener {
038
039 /** Guard-registration mask-bit indicating enabled() will be set only if the formmodel has no errors. */
040 public static final int ON_NOERRORS = 1;
041 /**
042 * Guard-registration mask-bit indicating enabled() will be set only if the formmodel has changes (is
043 * dirty).
044 */
045 public static final int ON_ISDIRTY = 1 << 1;
046 /** Guard-registration mask-bit indicating enabled() will be set only if the formmodel is enabled. */
047 public static final int ON_ENABLED = 1 << 2;
048
049 /**
050 * Guard-registration mask-pattern indicating enabled() will be set just like is the case for the new-form
051 * command. i.e. as soon as the formmodel is enabled.
052 */
053 public static final int LIKE_NEWFORMOBJCOMMAND = ON_ENABLED;
054 /**
055 * Guard-registration mask-pattern indicating enabled() will be set just like is the case for the revert
056 * command. i.e. only if the formmodel is enabled AND uncommitted changes are present.
057 */
058 public static final int LIKE_REVERTCOMMAND = ON_ISDIRTY + LIKE_NEWFORMOBJCOMMAND;
059 /**
060 * Guard-registration mask-pattern indicating enabled() will be set just like is the case for the commit
061 * command. i.e. only if the formmodel is enabled AND uncomitted changes are presenent AND the model is
062 * valid.
063 */
064 public static final int LIKE_COMMITCOMMAND = ON_NOERRORS + LIKE_REVERTCOMMAND;
065
066 /**
067 * Guard-registration mask-pattern indicating enabled() will be set only if the formmodel is both enabled
068 * and has no errors.
069 */
070 public static final int FORMERROR_GUARDED = ON_ENABLED + ON_NOERRORS;
071
072 private final ValidatingFormModel formModel;
073
074 private final Map guardedEntries = Collections.synchronizedMap(new HashMap());
075
076 /**
077 * Creates the FormGuard monitoring the passed formModel.
078 *
079 * @param formModel
080 * which state-changes should be passed to registered guarded objects.
081 */
082 public FormGuard(ValidatingFormModel formModel) {
083 this.formModel = formModel;
084
085 this.formModel.addPropertyChangeListener(FormModel.ENABLED_PROPERTY, this);
086 this.formModel.addPropertyChangeListener(ValidationResultsModel.HAS_ERRORS_PROPERTY, this);
087 this.formModel.addPropertyChangeListener(FormModel.DIRTY_PROPERTY, this);
088 }
089
090 /**
091 * Creates the FormGuard monitoring the passed formModel, and adds the passed guarded-object.
092 *
093 * For backwards compatibility this assumes the {@link #FORMERROR_GUARDED} mask.
094 *
095 * @param formModel
096 * which state-changes should be passed to registered guarded objects.
097 * @param guarded
098 * object that will get en/dis-abled
099 */
100 public FormGuard(ValidatingFormModel formModel, Guarded guarded) {
101 this(formModel, guarded, FORMERROR_GUARDED);
102 }
103
104 /**
105 * Creates the FormGuard monitoring the passed formModel, and adds the passed guarded-object using the
106 * specified mask.
107 *
108 * @param formModel
109 * which state-changes should be passed to registered guarded objects.
110 * @param guarded
111 * object that will get en/dis-abled
112 * @param mask
113 * specifying what formModel state should enable the guarded object.
114 */
115 public FormGuard(ValidatingFormModel formModel, Guarded guarded, int mask) {
116 this(formModel);
117 addGuarded(guarded, mask);
118 }
119
120 private void updateAllGuarded() {
121 int formState = getFormModelState();
122
123 Iterator guardedIter = this.guardedEntries.keySet().iterator();
124 while (guardedIter.hasNext()) {
125 Guarded guarded = (Guarded) guardedIter.next();
126 int mask = ((Integer) this.guardedEntries.get(guarded)).intValue();
127
128 boolean b = stateMatchesMask(formState, mask);
129 guarded.setEnabled(b);
130 }
131 }
132
133 private boolean stateMatchesMask(int formState, int mask) {
134 return ((mask & formState) == mask);
135 }
136
137 private int getFormModelState() {
138 int formState = 0;
139 if (!formModel.getHasErrors())
140 formState += ON_NOERRORS;
141 if (formModel.isDirty())
142 formState += ON_ISDIRTY;
143 if (formModel.isEnabled())
144 formState += ON_ENABLED;
145 return formState;
146 }
147
148 /**
149 * @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
150 */
151 public void propertyChange(PropertyChangeEvent e) {
152 updateAllGuarded();
153 }
154
155 /**
156 * Adds a guarded object to be guarded by this FormGuard
157 *
158 * @param newGuarded
159 * object to be guarded
160 * @param mask
161 * indicating which state of the formModel should enable the guarded obhject
162 */
163 public void addGuarded(Guarded newGuarded, int mask) {
164 this.guardedEntries.put(newGuarded, new Integer(mask));
165 newGuarded.setEnabled(stateMatchesMask(getFormModelState(), mask));
166 }
167
168 /**
169 * Removes the guarded object from the management of this FormGuard.
170 *
171 * @param toRemove
172 * object that no longer should be managed
173 *
174 * @return <code>false</code> if the object toRemove was not present in the list of managed guarded objects.
175 */
176 public boolean removeGuarded(Guarded toRemove) {
177 Object mask = this.guardedEntries.remove(toRemove);
178 return mask != null;
179 }
180 }