1 /**
2 * Copyright 2005-2012 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 }