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 }