001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 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, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.modifier; 017 018import org.kuali.rice.krad.uif.view.View; 019import org.kuali.rice.krad.uif.component.Component; 020import org.kuali.rice.krad.uif.util.ComponentUtils; 021import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 022 023import java.util.ArrayList; 024import java.util.HashSet; 025import java.util.List; 026import java.util.Set; 027 028/** 029 * For a given <code>Component</code> instance converts all component properties 030 * of a certain type to instances of another configured <code>Component</code>. 031 * The conversion is performed recursively down all the component children 032 * 033 * <p> 034 * Some example uses of this are converting all checkbox controls to radio group 035 * controls within a group and replacement of a widget with another 036 * </p> 037 * 038 * @author Kuali Rice Team (rice.collab@kuali.org) 039 */ 040public class ComponentConvertModifier extends ComponentModifierBase { 041 private static final long serialVersionUID = -7566547737669924605L; 042 043 private Class<? extends Component> componentTypeToReplace; 044 045 private Component componentReplacementPrototype; 046 047 public ComponentConvertModifier() { 048 super(); 049 } 050 051 /** 052 * @see org.kuali.rice.krad.uif.modifier.ComponentModifier#performModification(org.kuali.rice.krad.uif.view.View, 053 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 054 */ 055 @Override 056 public void performModification(View view, Object model, Component component) { 057 if (component == null) { 058 return; 059 } 060 061 int idSuffix = 0; 062 convertToReplacement(component, idSuffix); 063 } 064 065 /** 066 * Reads the component properties and looks for types that match the 067 * configured type to replace. If a match is found, a new instance of the 068 * replacement component prototype is created and set as the property value. 069 * The method is then called for each of the component's children 070 * 071 * @param component 072 * - component instance to inspect properties for 073 * @param idSuffix 074 * - suffix string to use for any generated component 075 * replacements 076 */ 077 protected void convertToReplacement(Component component, int idSuffix) { 078 if (component == null) { 079 return; 080 } 081 082 // check all component properties for the type to replace 083 List<String> componentProperties = ComponentUtils.getComponentPropertyNames(component.getClass()); 084 for (String propertyPath : componentProperties) { 085 Object propValue = ObjectPropertyUtils.getPropertyValue(component, propertyPath); 086 087 if (propValue != null) { 088 if (getComponentTypeToReplace().isAssignableFrom(propValue.getClass())) { 089 // types match, convert the component 090 performConversion(component, propertyPath, idSuffix++); 091 } 092 } 093 } 094 095 // recursively update components 096 for (Component nestedComponent : component.getComponentsForLifecycle()) { 097 convertToReplacement(nestedComponent, idSuffix); 098 } 099 } 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}