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