001    /*
002     * Copyright 2007 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 1.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/ecl1.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     */
016    package org.kuali.rice.krad.uif.container;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.uif.component.Component;
020    import org.kuali.rice.krad.uif.component.ComponentBase;
021    import org.kuali.rice.krad.uif.field.AttributeField;
022    import org.kuali.rice.krad.uif.field.ErrorsField;
023    import org.kuali.rice.krad.uif.field.HeaderField;
024    import org.kuali.rice.krad.uif.field.MessageField;
025    import org.kuali.rice.krad.uif.layout.LayoutManager;
026    import org.kuali.rice.krad.uif.util.ComponentUtils;
027    import org.kuali.rice.krad.uif.view.View;
028    import org.kuali.rice.krad.uif.widget.Help;
029    
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    /**
034     * Base <code>Container</code> implementation which container implementations
035     * can extend
036     * 
037     * <p>
038     * Provides properties for the basic <code>Container</code> functionality in
039     * addition to default implementation of the lifecycle methods including some
040     * setup of the header, items list, and layout manager
041     * </p>
042     * 
043     * @author Kuali Rice Team (rice.collab@kuali.org)
044     */
045    public abstract class ContainerBase extends ComponentBase implements Container {
046            private static final long serialVersionUID = -4182226230601746657L;
047    
048            private int itemOrderingSequence;
049    
050            private String additionalMessageKeys;
051            private ErrorsField errorsField;
052    
053            private Help help;
054            private LayoutManager layoutManager;
055    
056            private HeaderField header;
057            private Group footer;
058    
059            private String summary;
060            private MessageField summaryMessageField;
061    
062            private boolean fieldContainer;
063    
064            /**
065             * Default Constructor
066             */
067            public ContainerBase() {
068                    itemOrderingSequence = 1;
069            }
070    
071            /**
072             * The following initialization is performed:
073             * 
074             * <ul>
075             * <li>Sorts the containers list of components</li>
076             * <li>Initializes LayoutManager</li>
077             * </ul>
078             * 
079             * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View)
080             */
081            @SuppressWarnings("unchecked")
082            @Override
083            public void performInitialization(View view) {
084                    super.performInitialization(view);
085    
086                    // sort items list by the order property
087                    List<? extends Component> sortedItems = (List<? extends Component>) ComponentUtils.sort(getItems(),
088                                    itemOrderingSequence);
089                    setItems(sortedItems);
090    
091                    if (layoutManager != null) {
092                            layoutManager.performInitialization(view, this);
093                    }
094            }
095    
096            /**
097             * @see org.kuali.rice.krad.uif.component.ComponentBase#performApplyModel(org.kuali.rice.krad.uif.view.View,
098             *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
099             */
100            @Override
101            public void performApplyModel(View view, Object model, Component parent) {
102                    super.performApplyModel(view, model, parent);
103    
104                    if (layoutManager != null) {
105                            layoutManager.performApplyModel(view, model, this);
106                    }
107            }
108    
109            /**
110             * The following finalization is performed:
111             * 
112             * <ul>
113             * <li>Sets the headerText of the header Group if it is blank</li>
114             * <li>Set the messageText of the summary MessageField if it is blank</li>
115             * <li>Finalizes LayoutManager</li>
116             * </ul>
117             * 
118             * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
119             *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
120             */
121            @Override
122            public void performFinalize(View view, Object model, Component parent) {
123                    super.performFinalize(view, model, parent);
124    
125                    // if header title not given, use the container title
126                    if (header != null && StringUtils.isBlank(header.getHeaderText())) {
127                            header.setHeaderText(this.getTitle());
128                    }
129    
130                    // setup summary message field if necessary
131                    if (summaryMessageField != null && StringUtils.isBlank(summaryMessageField.getMessageText())) {
132                            summaryMessageField.setMessageText(summary);
133                    }
134    
135                    if (layoutManager != null) {
136                            layoutManager.performFinalize(view, model, this);
137                    }
138            }
139    
140            /**
141             * @see org.kuali.rice.krad.uif.component.ComponentBase#getNestedComponents()
142             */
143            @Override
144            public List<Component> getNestedComponents() {
145                    List<Component> components = super.getNestedComponents();
146    
147                    components.add(header);
148                    components.add(footer);
149                    components.add(errorsField);
150                    components.add(help);
151                    components.add(summaryMessageField);
152    
153                    for (Component component : getItems()) {
154                            components.add(component);
155                    }
156    
157                    if (layoutManager != null) {
158                            components.addAll(layoutManager.getNestedComponents());
159                    }
160    
161                    return components;
162            }
163    
164            /**
165             * Additional keys that should be matching on when gathering errors or other
166             * messages for the <code>Container</code>
167             * 
168             * <p>
169             * Messages associated with the container will be displayed with the
170             * container grouping in the user interface. Typically, these are a result
171             * of problems with the containers fields or some other business logic
172             * associated with the containers information. The framework will by default
173             * include all the error keys for fields in the container, and also an
174             * errors associated with the containers id. Keys given here will be matched
175             * in addition to those defaults.
176             * </p>
177             * 
178             * <p>
179             * Multple keys can be given using the comma delimiter, the * wildcard is
180             * also allowed in the message key
181             * </p>
182             * 
183             * @return String additional message key string
184             */
185            public String getAdditionalMessageKeys() {
186                    return this.additionalMessageKeys;
187            }
188    
189            /**
190             * Setter for the components additional message key string
191             * 
192             * @param additionalMessageKeys
193             */
194            public void setAdditionalMessageKeys(String additionalMessageKeys) {
195                    this.additionalMessageKeys = additionalMessageKeys;
196            }
197    
198            /**
199             * @see org.kuali.rice.krad.uif.container.Container#getErrorsField()
200             */
201            @Override
202            public ErrorsField getErrorsField() {
203                    return this.errorsField;
204            }
205    
206            /**
207             * @see org.kuali.rice.krad.uif.container.Container#setErrorsField(org.kuali.rice.krad.uif.field.ErrorsField)
208             */
209            @Override
210            public void setErrorsField(ErrorsField errorsField) {
211                    this.errorsField = errorsField;
212            }
213    
214            /**
215             * @see org.kuali.rice.krad.uif.container.Container#getHelp()
216             */
217            @Override
218            public Help getHelp() {
219                    return this.help;
220            }
221    
222            /**
223             * @see org.kuali.rice.krad.uif.container.Container#setHelp(org.kuali.rice.krad.uif.widget.Help)
224             */
225            @Override
226            public void setHelp(Help help) {
227                    this.help = help;
228            }
229    
230            /**
231             * @see org.kuali.rice.krad.uif.container.Container#getItems()
232             */
233            @Override
234            public abstract List<? extends Component> getItems();
235    
236            /**
237             * Setter for the containers list of components
238             * 
239             * @param items
240             */
241            public abstract void setItems(List<? extends Component> items);
242    
243            /**
244             * For <code>Component</code> instances in the container's items list that
245             * do not have an order set, a default order number will be assigned using
246             * this property. The first component found in the list without an order
247             * will be assigned the configured initial value, and incremented by one for
248             * each component (without an order) found afterwards
249             * 
250             * @return int order sequence
251             */
252            public int getItemOrderingSequence() {
253                    return this.itemOrderingSequence;
254            }
255    
256            /**
257             * Setter for the container's item ordering sequence number (initial value)
258             * 
259             * @param itemOrderingSequence
260             */
261            public void setItemOrderingSequence(int itemOrderingSequence) {
262                    this.itemOrderingSequence = itemOrderingSequence;
263            }
264    
265            /**
266             * @see org.kuali.rice.krad.uif.container.Container#getLayoutManager()
267             */
268            @Override
269            public LayoutManager getLayoutManager() {
270                    return this.layoutManager;
271            }
272    
273            /**
274             * @see org.kuali.rice.krad.uif.container.Container#setLayoutManager(org.kuali.rice.krad.uif.layout.LayoutManager)
275             */
276            @Override
277            public void setLayoutManager(LayoutManager layoutManager) {
278                    this.layoutManager = layoutManager;
279            }
280    
281            /**
282             * @see org.kuali.rice.krad.uif.container.Container#getHeader()
283             */
284            @Override
285            public HeaderField getHeader() {
286                    return this.header;
287            }
288    
289            /**
290             * @see org.kuali.rice.krad.uif.container.Container#setHeader(org.kuali.rice.krad.uif.field.HeaderField)
291             */
292            @Override
293            public void setHeader(HeaderField header) {
294                    this.header = header;
295            }
296    
297            /**
298             * @see org.kuali.rice.krad.uif.container.Container#getFooter()
299             */
300            @Override
301            public Group getFooter() {
302                    return this.footer;
303            }
304    
305            /**
306             * @see org.kuali.rice.krad.uif.container.Container#setFooter(org.kuali.rice.krad.uif.container.Group)
307             */
308            @Override
309            public void setFooter(Group footer) {
310                    this.footer = footer;
311            }
312    
313            /**
314             * Convenience setter for configuration to turn rendering of the header
315             * on/off
316             * 
317             * <p>
318             * For nested groups (like Field Groups) it is often necessary to only show
319             * the container body (the contained components). This method allows the
320             * header to not be displayed
321             * </p>
322             * 
323             * @param renderHeader
324             */
325            public void setRenderHeader(boolean renderHeader) {
326                    if (header != null) {
327                            header.setRender(renderHeader);
328                    }
329            }
330    
331            /**
332             * Convenience setter for configuration to turn rendering of the footer
333             * on/off
334             * 
335             * <p>
336             * For nested groups it is often necessary to only show the container body
337             * (the contained components). This method allows the footer to not be
338             * displayed
339             * </p>
340             * 
341             * @param renderFooter
342             */
343            public void setRenderFooter(boolean renderFooter) {
344                    if (footer != null) {
345                            footer.setRender(renderFooter);
346                    }
347            }
348    
349            /**
350             * Summary text for the container which will be used to set the summary
351             * message field
352             * 
353             * @return String summary text
354             * @see org.kuali.rice.krad.uif.container.Container#getSummaryMessageField()
355             */
356            public String getSummary() {
357                    return this.summary;
358            }
359    
360            /**
361             * Setter for the containers summary text
362             * 
363             * @param summary
364             */
365            public void setSummary(String summary) {
366                    this.summary = summary;
367            }
368    
369            /**
370             * @see org.kuali.rice.krad.uif.container.Container#getSummaryMessageField()
371             */
372            @Override
373            public MessageField getSummaryMessageField() {
374                    return this.summaryMessageField;
375            }
376    
377            /**
378             * @see org.kuali.rice.krad.uif.container.Container#setSummaryMessageField(org.kuali.rice.krad.uif.field.MessageField)
379             */
380            @Override
381            public void setSummaryMessageField(MessageField summaryMessageField) {
382                    this.summaryMessageField = summaryMessageField;
383            }
384    
385            /**
386             * Gets only the attribute fields that are nested in this container.  This is a subset of
387             * what getNestedComponents() returns.
388             * 
389             * @return
390             */
391            public List<AttributeField> getAttributeFields(){
392                    List<AttributeField> attributeFields = new ArrayList<AttributeField>();
393                    for(Component c: this.getNestedComponents()){
394                            if(c instanceof AttributeField){
395                                    attributeFields.add((AttributeField)c);
396                            }
397                    }
398                    return attributeFields;
399                    
400            }
401    
402            /**
403             * This property is true if the container is used to display a group of fields that is visually a single
404             * field.
405             * @return the fieldContainer
406             */
407            public boolean isFieldContainer() {
408                    return this.fieldContainer;
409            }
410    
411            /**
412             * @param fieldContainer the fieldContainer to set
413             */
414            public void setFieldContainer(boolean fieldContainer) {
415                    this.fieldContainer = fieldContainer;
416            }
417    
418    }