View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.modifier;
17  
18  import org.kuali.rice.krad.uif.view.View;
19  import org.kuali.rice.krad.uif.component.Component;
20  import org.kuali.rice.krad.uif.util.ComponentUtils;
21  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
22  
23  import java.util.ArrayList;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Set;
27  
28  /**
29   * For a given <code>Component</code> instance converts all component properties
30   * of a certain type to instances of another configured <code>Component</code>.
31   * The conversion is performed recursively down all the component children
32   * 
33   * <p>
34   * Some example uses of this are converting all checkbox controls to radio group
35   * controls within a group and replacement of a widget with another
36   * </p>
37   * 
38   * @author Kuali Rice Team (rice.collab@kuali.org)
39   */
40  public class ComponentConvertModifier extends ComponentModifierBase {
41  	private static final long serialVersionUID = -7566547737669924605L;
42  
43  	private Class<? extends Component> componentTypeToReplace;
44  
45  	private Component componentReplacementPrototype;
46  
47  	public ComponentConvertModifier() {
48  		super();
49  	}
50  
51  	/**
52  	 * @see org.kuali.rice.krad.uif.modifier.ComponentModifier#performModification(org.kuali.rice.krad.uif.view.View,
53  	 *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
54  	 */
55  	@Override
56  	public void performModification(View view, Object model, Component component) {
57  		if (component == null) {
58  			return;
59  		}
60  
61  		int idSuffix = 0;
62  		convertToReplacement(component, idSuffix);
63  	}
64  
65  	/**
66  	 * Reads the component properties and looks for types that match the
67  	 * configured type to replace. If a match is found, a new instance of the
68  	 * replacement component prototype is created and set as the property value.
69  	 * The method is then called for each of the component's children
70  	 * 
71  	 * @param component
72  	 *            - component instance to inspect properties for
73  	 * @param idSuffix
74  	 *            - suffix string to use for any generated component
75  	 *            replacements
76  	 */
77  	protected void convertToReplacement(Component component, int idSuffix) {
78  		if (component == null) {
79  			return;
80  		}
81  
82  		// check all component properties for the type to replace
83  		List<String> componentProperties = ComponentUtils.getComponentPropertyNames(component.getClass());
84  		for (String propertyPath : componentProperties) {
85  			Object propValue = ObjectPropertyUtils.getPropertyValue(component, propertyPath);
86  
87  			if (propValue != null) {
88  				if (getComponentTypeToReplace().isAssignableFrom(propValue.getClass())) {
89  					// types match, convert the component
90  					performConversion(component, propertyPath, idSuffix++);
91  				}
92  			}
93  		}
94  
95  		// recursively update components
96  		for (Component nestedComponent : component.getComponentsForLifecycle()) {
97  			convertToReplacement(nestedComponent, idSuffix);
98  		}
99  	}
100 
101 	/**
102 	 * Creates a new instance of the replacement component prototype and sets a
103 	 * the property value for the given property name and component instance
104 	 * 
105 	 * @param component
106 	 *            - component instance to set property on
107 	 * @param componentProperty
108 	 *            - property name to set
109 	 * @param idSuffix
110 	 *            - suffix string to use for the generated component
111 	 */
112 	protected void performConversion(Component component, String componentProperty, int idSuffix) {
113 		// create new instance of replacement component
114 		Component componentReplacement = ComponentUtils.copy(getComponentReplacementPrototype(), Integer.toString(idSuffix));
115 
116 		ObjectPropertyUtils.setPropertyValue(component, componentProperty, componentReplacement);
117 	}
118 
119 	/**
120 	 * @see org.kuali.rice.krad.uif.modifier.ComponentModifier#getSupportedComponents()
121 	 */
122 	@Override
123 	public Set<Class<? extends Component>> getSupportedComponents() {
124 		Set<Class<? extends Component>> components = new HashSet<Class<? extends Component>>();
125 		components.add(Component.class);
126 
127 		return components;
128 	}
129 
130     /**
131      * @see org.kuali.rice.krad.uif.modifier.ComponentModifierBase#getComponentPrototypes()
132      */
133     public List<Component> getComponentPrototypes() {
134         List<Component> components = new ArrayList<Component>();
135 
136         components.add(componentReplacementPrototype);
137 
138         return components;
139     }
140 
141 	/**
142 	 * Type of component that should be replaced with an instance of the
143 	 * component prototype
144 	 * 
145 	 * @return Class<? extends Component> component type to replace
146 	 */
147 	public Class<? extends Component> getComponentTypeToReplace() {
148 		return this.componentTypeToReplace;
149 	}
150 
151 	/**
152 	 * Setter for the component type to replace
153 	 * 
154 	 * @param componentTypeToReplace
155 	 */
156 	public void setComponentTypeToReplace(Class<? extends Component> componentTypeToReplace) {
157 		this.componentTypeToReplace = componentTypeToReplace;
158 	}
159 
160 	/**
161 	 * Prototype for the component replacement
162 	 * 
163 	 * <p>
164 	 * Each time the type to replace if found a new instance of the component
165 	 * prototype will be created and set as the new property value
166 	 * </p>
167 	 * 
168 	 * @return
169 	 */
170 	public Component getComponentReplacementPrototype() {
171 		return this.componentReplacementPrototype;
172 	}
173 
174 	/**
175 	 * Setter for the replacement component prototype
176 	 * 
177 	 * @param componentReplacementPrototype
178 	 */
179 	public void setComponentReplacementPrototype(Component componentReplacementPrototype) {
180 		this.componentReplacementPrototype = componentReplacementPrototype;
181 	}
182 
183 }