View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    * <p/>
7    * http://www.osedu.org/licenses/ECL-2.0
8    * <p/>
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"                       
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   * <p/>
15   */
16  package org.kuali.student.common.ui.client.configurable.mvc.multiplicity;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.kuali.student.common.assembly.data.Metadata;
24  import org.kuali.student.common.assembly.data.QueryPath;
25  import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
26  import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
27  import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
28  
29  /**
30    *
31    * MultiplicityConfiguration is passed into a MultiplicitySection to control the creation of the multiplicity.
32    *
33    * This class is used to control the Multiplicity, e.g. if its updateable, has headers, min number of items, labels etc.
34    * It also holds FieldDescriptors for the fields required to be included in the multiplicity. They are
35    * held in a HashMap keyed by rows, i.e. {@literal Map<Integer, List<FieldDescriptor>>} .
36    *
37    * The parent for the multiplicity refers to the path to the high level field that owns
38    * the repeating elements, e.g. course/versions is the parent field for course version fields versionCode and
39    * versionTitle
40    *
41    * For multiplicities nested inside another multiplicity, create a MultiplicityConfiguration for the nested
42    * multiplicity and call setNestedConfig to add the lower level multiplicity
43    *
44    *
45   */
46  public class MultiplicityConfiguration {
47  
48      private MultiplicityType multiplicityType;
49      
50      private StyleType styleType;
51      private boolean updateable = false;
52  
53      private String itemLabel;
54      private String addItemLabel;
55      
56      private Metadata metaData;
57      
58      private SectionTitle title;
59      private int defaultItemsCreated = 0;
60  
61      int row = 0;
62      
63      private FieldDescriptor parentFd;
64      private Map<Integer, List<MultiplicityFieldConfiguration>> fields = new HashMap<Integer, List<MultiplicityFieldConfiguration>>();
65      private Map<String, FieldDescriptor> fieldMap = new HashMap<String, FieldDescriptor>();
66      protected Map<String, String> concatenatedFields = new HashMap<String, String>();
67      
68      private MultiplicityConfiguration nestedConfig ;
69      private MultiplicityGroup customMultiplicityGroup;
70      private boolean showHeaders;
71  
72      public static enum MultiplicityType {GROUP, TABLE }
73      public static enum StyleType {
74          TOP_LEVEL_GROUP, SUB_LEVEL_GROUP, BORDERLESS_TABLE, BORDERED_TABLE
75      }
76  
77  
78       /**
79       *
80       * Creates a new MultiplicityConfiguration.
81       *
82       *
83       * @param multiplicityType      the type of multiplicity required, MultiplicityType
84       * @param styleType             the style type for this multiplicity, StyleType
85       * @param metaData              the metadata for the parentFd
86       */
87       public MultiplicityConfiguration(MultiplicityType multiplicityType, StyleType styleType, Metadata metaData) {
88          this.multiplicityType = multiplicityType;
89          this.styleType = styleType;
90          this.metaData = metaData;
91      }
92  
93      /**
94       * Causes a line throw so that the subsequent fields are placed on the next line of the screen
95       *
96       */
97      public void nextLine() {
98      	row++;
99      }
100 
101     /**
102      * Includes this field (as defined by the FieldDescriptor) on the current line at the next horizontal position
103      *
104      *
105      * @param fieldDescriptor
106      */
107     public void addFieldConfiguration(MultiplicityFieldConfiguration fieldDescriptor) {
108     	
109         List<MultiplicityFieldConfiguration> fds;
110         if (fields.containsKey(row)) {
111             fds = fields.get(row);
112         }
113         else {
114             fds = new ArrayList<MultiplicityFieldConfiguration>();
115         }
116         fds.add(fieldDescriptor);
117         fields.put(row, fds);
118     }
119     
120     public void setFields(Map<Integer, List<MultiplicityFieldConfiguration>> fields) {
121         if (fields == null || fields.isEmpty()) {
122             row = 0;
123         } else {
124             row = fields.size() - 1;
125         }
126         this.fields = fields;
127     }
128 
129 	/**
130 	 * Concatenates multiple field values into a single table cell
131      *
132      *  !!!!!  Currently only implemented for MultiplicityTable !!!!!
133      *
134      * The parentField should define a field with a Data value. The fieldKey should resolve to a single value
135 	 * field in that Data value. The binding will iterate the values in the Data object
136 	 * and concatenate the named fieldKeys into the same cell in the current row of the table
137 	 * separated by commas.
138      *
139      * e.g. parentFD = "course/versions", fieldKey = "versionCode", version codes will be concatenated to
140      * display "code1, code2, code3" in a single table cell
141 	 *
142 	 * @param fieldKey
143 	 */
144 	public void addConcatenatedField(MultiplicityFieldConfiguration parentField, String fieldKey){
145 		addFieldConfiguration(parentField);
146 		concatenatedFields.put(parentField.getFieldPath(), fieldKey);
147 	}
148 
149     /**
150      * Creates a copy of this MultiplicityConfiguration. Used when creating a new MultiplicityItem
151      *
152      * @return  MultiplicityConfiguration
153      */
154     public MultiplicityConfiguration copy() {
155         MultiplicityConfiguration copy = new MultiplicityConfiguration(getMultiplicityType(), getStyleType(), getMetaData());
156         copy.setAddItemLabel(getAddItemLabel());
157         copy.setItemLabel(getItemLabel());
158         copy.setMetaData(getMetaData());
159         copy.setUpdateable(isUpdateable());
160         copy.setDefaultItemsCreated(getDefaultItemsCreated());
161         if (getNestedConfig() != null) {
162             copy.setNestedConfig(getNestedConfig().copy());
163         }
164         FieldDescriptor parent = new FieldDescriptor(getParentFd().getFieldKey(), getParentFd().getMessageKey(), getParentFd().getMetadata());
165         if(!getParentFd().isLabelShown()){
166         	parent.hideLabel();
167         }
168         copy.setParent(parent);
169         for (Integer row  : getFields().keySet()) {
170             List<MultiplicityFieldConfiguration> fields = getFields().get(row);
171             for (MultiplicityFieldConfiguration fieldConfig : fields) {
172                 MultiplicityFieldConfiguration newfieldConfig = new MultiplicityFieldConfiguration(fieldConfig.getFieldPath(), fieldConfig.getMessageKeyInfo(), fieldConfig.getMetadata(), fieldConfig.getFieldWidgetInitializer());
173                 newfieldConfig.setOptional(fieldConfig.isOptional());
174                 newfieldConfig.setModelWidgetBinding(fieldConfig.getModelWidgetBinding());
175                 copy.addFieldConfiguration(newfieldConfig);
176             }
177             copy.nextLine();
178         }
179         return copy;
180     }
181 
182     public MultiplicityType getMultiplicityType() {
183         return multiplicityType;
184     }
185 
186      /**
187       * Sets the MultiplicityType required for this config
188       *
189       * Valid values are defined in {@link #MultiplicityConfiguration.MultiplicityType}
190       * @param multiplicityType
191       */
192      public void setMultiplicityType(MultiplicityType multiplicityType) {
193         this.multiplicityType = multiplicityType;
194     }
195 
196 	public FieldDescriptor getParentFd() {
197 		return parentFd;
198 	}
199 
200     /**
201      * The parent fd defines the high level parent field that contains the repeating elements
202      *
203      * @param parentFd
204      */
205     public void setParent(FieldDescriptor parentFd) {
206 		this.parentFd = parentFd;
207 	}
208 
209 //	public Map<Integer, List<FieldDescriptor>> getFields() {return null;}
210 
211 	public Map<Integer, List<MultiplicityFieldConfiguration>> getFields() {
212 		return fields;
213 	}
214 
215     public String getItemLabel() {
216         return itemLabel;
217     }
218 
219     /**
220      * Sets text to be used as the header for each multiplicity item
221      * @param itemLabel
222      */
223     public void setItemLabel(String itemLabel) {
224         this.itemLabel = itemLabel;
225     }
226 
227     public String getAddItemLabel() {
228         return addItemLabel;
229     }
230 
231     /**
232      * Sets text to be used as the button text to add a new empty item in the multiplicity
233      * @param addItemLabel
234      */
235     public void setAddItemLabel(String addItemLabel) {
236         this.addItemLabel = addItemLabel;
237     }
238 
239 	public StyleType getStyleType() {
240 		return styleType;
241 	}
242 
243 	public void setStyleType(StyleType styleType) {
244 		this.styleType = styleType;
245 	}
246 
247 	public MultiplicityConfiguration getNestedConfig() {
248 		return nestedConfig;
249 	}
250 
251     /**
252      * If this multiplicity is to contain other nested multiplicities, create a MultiplicityConfiguration for the child
253      * multiplicity and set as a nested config in the parent.
254      *
255      * @param config
256      */
257     public void setNestedConfig(MultiplicityConfiguration config) {
258 		this.nestedConfig = config;
259 	}
260 
261     public boolean isShowHeaders() {
262          return showHeaders;
263     }
264 
265     /**
266      *
267      * @param showHeaders
268      */
269     public void setShowHeaders(boolean showHeaders) {
270         this.showHeaders = showHeaders;
271     }
272 
273 	public Map<String, String> getConcatenatedFields() {
274 		return concatenatedFields;
275 	}
276 
277     public boolean isUpdateable() {
278         return updateable;
279     }
280 
281     /**
282      * Sets if this multiplicity will be updateable or display.
283      * Add delete buttons/links will not be shown for display multiplicities
284      *
285      * @param updateable
286      */
287     public void setUpdateable(boolean updateable) {
288         this.updateable = updateable;
289     }
290 
291     public MultiplicityType getLayoutType() {
292         return multiplicityType;
293     }
294 
295     public void setLayoutType(MultiplicityType multiplicityType) {
296         this.multiplicityType = multiplicityType;
297     }
298 
299 	public Metadata getMetaData() {
300 		return metaData;
301 	}
302 
303 	public void setMetaData(Metadata metaData) {
304 		this.metaData = metaData;
305 	}
306 
307 
308      public SectionTitle getTitle() {
309         return title;
310     }
311 
312     public void setTitle(SectionTitle title) {
313         this.title = title;
314     }
315 
316     /**
317      * Creates a field descriptor for the parent for this multiplicity
318      * This defines the high level parent field that contains the repeating elements
319      * Will use default widget and binding. For more complex fields create your own
320      * fieldDescriptor and use the other setParent method
321      *
322      * @param fieldKey
323      * @param messageKey
324      * @param parentPath
325      * @param meta
326      */
327     public void setParent(String fieldKey, String messageKey,  String parentPath, Metadata meta) {
328 
329         QueryPath path = QueryPath.concat(parentPath, fieldKey);
330         FieldDescriptor fd = new FieldDescriptor(path.toString(), new MessageKeyInfo(messageKey), meta);
331         fd.getFieldElement().setRequired(false);
332 
333         setParent(fd);
334 
335     }
336 
337     /**
338      * Includes this field on the current line at the next horizontal position
339      *
340      * Will use default widget and binding. For more complex fields create your own
341      * FieldDescriptor and pass it in using the other addField method
342      *
343      * @param fieldKey
344      * @param messageKey
345      * @param parentPath
346      * @param meta
347      */
348     public void addField(String fieldKey, String messageKey,  String parentPath, Metadata meta) {
349 
350         QueryPath path = QueryPath.concat(parentPath, QueryPath.getWildCard(), fieldKey);
351 
352         MultiplicityFieldConfiguration fieldConfig = new MultiplicityFieldConfiguration(path.toString(), new MessageKeyInfo(messageKey), meta, null);
353         fieldConfig.setRequired(false);
354         addFieldConfiguration(fieldConfig);
355     }
356 
357 //    private String translatePath(String path, Metadata metadata) {
358 //
359 //        String result = path;
360 //
361 //        QueryPath qPath = QueryPath.parse(path);
362 //
363 //        if(metadata!=null&&metadata.getInitialLookup()!=null){
364 //            QueryPath translationPath = qPath.subPath(0, qPath.size()-1);
365 //            if (metadata.getDataType().equals(Data.DataType.STRING)) {
366 //                translationPath.add(new Data.StringKey("_runtimeData"));
367 //                translationPath.add(new Data.StringKey((String)qPath.get(qPath.size() - 1).get()));
368 //                translationPath.add(new Data.StringKey("id-translation"));
369 //                result = translationPath.toString();
370 //            }
371 //        }
372 //        return result;
373 //    }
374 
375     public MultiplicityGroup getCustomMultiplicityGroup() {
376         return customMultiplicityGroup;
377     }
378 
379     public void setCustomMultiplicityGroup(MultiplicityGroup customMultiplicityGroup) {
380         this.customMultiplicityGroup = customMultiplicityGroup;
381     }
382 
383 	public void setDefaultItemsCreated(int defaultItemsCreated) {
384 		this.defaultItemsCreated = defaultItemsCreated;
385 	}
386 
387 	public int getDefaultItemsCreated() {
388 		return defaultItemsCreated;
389 	}
390     
391     
392 }
393