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 }