001/**
002 * Copyright 2005-2018 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.container;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.exception.RiceRuntimeException;
020import org.kuali.rice.krad.datadictionary.parse.BeanTag;
021import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
022import org.kuali.rice.krad.datadictionary.parse.BeanTags;
023import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
024import org.kuali.rice.krad.datadictionary.validator.Validator;
025import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
026import org.kuali.rice.krad.uif.UifConstants;
027import org.kuali.rice.krad.uif.UifParameters;
028import org.kuali.rice.krad.uif.UifPropertyPaths;
029import org.kuali.rice.krad.uif.component.BindingInfo;
030import org.kuali.rice.krad.uif.component.ClientSideState;
031import org.kuali.rice.krad.uif.component.Component;
032import org.kuali.rice.krad.uif.component.ComponentSecurity;
033import org.kuali.rice.krad.uif.component.DelayedCopy;
034import org.kuali.rice.krad.uif.component.KeepExpression;
035import org.kuali.rice.krad.uif.element.Action;
036import org.kuali.rice.krad.uif.element.Message;
037import org.kuali.rice.krad.uif.field.DataField;
038import org.kuali.rice.krad.uif.field.FieldGroup;
039import org.kuali.rice.krad.uif.field.InputField;
040import org.kuali.rice.krad.uif.layout.CollectionLayoutManager;
041import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
042import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleRestriction;
043import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils;
044import org.kuali.rice.krad.uif.util.ComponentFactory;
045import org.kuali.rice.krad.uif.util.ComponentUtils;
046import org.kuali.rice.krad.uif.util.ContextUtils;
047import org.kuali.rice.krad.uif.util.LifecycleElement;
048import org.kuali.rice.krad.uif.util.ScriptUtils;
049import org.kuali.rice.krad.uif.view.View;
050import org.kuali.rice.krad.uif.view.ViewModel;
051import org.kuali.rice.krad.uif.widget.QuickFinder;
052import org.kuali.rice.krad.util.KRADUtils;
053
054import java.util.ArrayList;
055import java.util.Collection;
056import java.util.Collections;
057import java.util.List;
058
059/**
060 * Group that holds a collection of objects and configuration for presenting the
061 * collection in the UI. Supports functionality such as add line, line actions,
062 * and nested collections.
063 *
064 * <p>
065 * Note the standard header/footer can be used to give a header to the
066 * collection as a whole, or to provide actions that apply to the entire
067 * collection
068 * </p>
069 *
070 * <p>
071 * For binding purposes the binding path of each row field is indexed. The name
072 * property inherited from <code>ComponentBase</code> is used as the collection
073 * name. The collectionObjectClass property is used to lookup attributes from
074 * the data dictionary.
075 * </p>
076 *
077 * @author Kuali Rice Team (rice.collab@kuali.org)
078 */
079@BeanTags({@BeanTag(name = "collectionGroup", parent = "Uif-CollectionGroupBase"),
080        @BeanTag(name = "stacked", parent = "Uif-StackedCollectionGroup"),
081        @BeanTag(name = "stackedSection", parent = "Uif-StackedCollectionSection"),
082        @BeanTag(name = "stackedSubSection", parent = "Uif-StackedCollectionSubSection"),
083        @BeanTag(name = "stackedSubCollection-withinSection", parent = "Uif-StackedSubCollection-WithinSection"),
084        @BeanTag(name = "stackedSubCollection-withinSubSection",
085                parent = "Uif-StackedSubCollection-WithinSubSection"),
086        @BeanTag(name = "disclosureStackedSection", parent = "Uif-Disclosure-StackedCollectionSection"),
087        @BeanTag(name = "disclosureStackedSubSection",
088                parent = "Uif-Disclosure-StackedCollectionSubSection"),
089        @BeanTag(name = "disclosureStackedSubCollection-withinSection",
090                parent = "Uif-Disclosure-StackedSubCollection-WithinSection"),
091        @BeanTag(name = "disclosureStackedSubCollection-withinSubSection",
092                parent = "Uif-Disclosure-StackedSubCollection-WithinSubSection"),
093        @BeanTag(name = "table", parent = "Uif-TableCollectionGroup"),
094        @BeanTag(name = "tableSection", parent = "Uif-TableCollectionSection"),
095        @BeanTag(name = "tableSubSection", parent = "Uif-TableCollectionSubSection"),
096        @BeanTag(name = "tableSubCollection-withinSection", parent = "Uif-TableSubCollection-WithinSection"),
097        @BeanTag(name = "tableSubCollection-withinSubSection", parent = "Uif-TableSubCollection-WithinSubSection"),
098        @BeanTag(name = "disclosureTableSection", parent = "Uif-Disclosure-TableCollectionSection"),
099        @BeanTag(name = "disclosureTableSubSection",
100                parent = "Uif-Disclosure-TableCollectionSubSection"),
101        @BeanTag(name = "disclosureTableSubCollection-withinSection",
102                parent = "Uif-Disclosure-TableSubCollection-WithinSection"),
103        @BeanTag(name = "disclosureTableSubCollection-withinSubSection",
104                parent = "Uif-Disclosure-TableSubCollection-WithinSubSection"),
105        @BeanTag(name = "listCollection", parent = "Uif-ListCollectionGroup"),
106        @BeanTag(name = "listCollectionSection", parent = "Uif-ListCollectionSection"),
107        @BeanTag(name = "listCollectionSubSection", parent = "Uif-ListCollectionSubSection"),
108        @BeanTag(name = "maintenanceStackedSection", parent = "Uif-MaintenanceStackedCollectionSection"),
109        @BeanTag(name = "maintenanceStackedSubCollection-withinSection",
110                parent = "Uif-MaintenanceStackedSubCollection-WithinSection"),
111        @BeanTag(name = "maintenanceTableSection", parent = "Uif-MaintenanceTableCollectionSection"),
112        @BeanTag(name = "maintenanceTableSubCollection-withinSection",
113                parent = "Uif-MaintenanceTableSubCollection-WithinSection")})
114public class CollectionGroupBase extends GroupBase implements CollectionGroup {
115
116    private static final long serialVersionUID = -6496712566071542452L;
117
118    private Class<?> collectionObjectClass;
119
120    private String propertyName;
121    private BindingInfo bindingInfo;
122
123    private boolean renderAddLine;
124    private String addLinePropertyName;
125    private BindingInfo addLineBindingInfo;
126
127    private Message addLineLabel;
128
129    private List<? extends Component> addLineItems;
130    private List<? extends Component> addLineActions;
131
132    @KeepExpression
133    private String addLineEnterKeyAction;
134
135    @KeepExpression
136    private String lineEnterKeyAction;
137
138    private boolean renderLineActions;
139    private List<? extends Component> lineActions;
140
141    private boolean includeLineSelectionField;
142    private String lineSelectPropertyName;
143
144    private QuickFinder collectionLookup;
145
146    private boolean renderInactiveToggleButton;
147    @ClientSideState(variableName = "inactive")
148    private boolean showInactiveLines;
149    private CollectionFilter activeCollectionFilter;
150    private List<CollectionFilter> filters;
151
152    private List<String> duplicateLinePropertyNames;
153
154    private List<BindingInfo> unauthorizedLineBindingInfos;
155
156    @DelayedCopy
157    private List<CollectionGroup> subCollections;
158
159    private CollectionGroupBuilder collectionGroupBuilder;
160
161    private int displayCollectionSize = -1;
162
163    private boolean highlightNewItems;
164    private boolean highlightAddItem;
165    private String newItemsCssClass;
166    private String addItemCssClass;
167
168    private boolean renderAddBlankLineButton;
169    private Action addBlankLineAction;
170    private String addLinePlacement;
171
172    private boolean renderSaveLineActions;
173
174    // edit line properties
175    private boolean editWithDialog;
176    private boolean customEditLineDialog;
177    private DialogGroup editLineDialogPrototype;
178    private Action editWithDialogActionPrototype;
179    private Action editInDialogSaveActionPrototype;
180
181    private List<DialogGroup> lineDialogs;
182
183    private boolean addWithDialog;
184    private Action addWithDialogAction;
185    private DialogGroup addLineDialog;
186
187    private boolean useServerPaging = false;
188    private int pageSize;
189    private int displayStart = -1;
190    private int displayLength = -1;
191    private int filteredCollectionSize = -1;
192    private int totalCollectionSize = -1;
193
194    private List<String> totalColumns;
195
196    public CollectionGroupBase() {
197        renderAddLine = true;
198        renderLineActions = true;
199        renderInactiveToggleButton = true;
200        highlightNewItems = true;
201        highlightAddItem = true;
202        addLinePlacement = "TOP";
203
204        filters = Collections.emptyList();
205        duplicateLinePropertyNames = Collections.emptyList();
206        lineActions = Collections.emptyList();
207        addLineItems = Collections.emptyList();
208        addLineActions = Collections.emptyList();
209        subCollections = Collections.emptyList();
210        lineDialogs = Collections.emptyList();
211    }
212
213    /**
214     * @{inheritDoc}
215     */
216    @Override
217    public void performInitialization(Object model) {
218        View view = ViewLifecycle.getView();
219
220        setFieldBindingObjectPath(getBindingInfo().getBindingObjectPath());
221
222        super.performInitialization(model);
223
224        if (bindingInfo != null) {
225            bindingInfo.setDefaults(view, getPropertyName());
226        }
227
228        if (addLineBindingInfo != null) {
229            // add line binds to model property
230            if (StringUtils.isNotBlank(addLinePropertyName)) {
231                addLineBindingInfo.setDefaults(view, getPropertyName());
232                addLineBindingInfo.setBindingName(addLinePropertyName);
233
234                if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
235                    addLineBindingInfo.setBindByNamePrefix(getFieldBindByNamePrefix());
236                }
237            }
238        }
239
240        // if no add line items specified then assume same items showing
241        if ((addLineItems == null) || addLineItems.isEmpty()) {
242            addLineItems = getItems();
243        }
244
245        // if addWithDialog...
246        if (addWithDialog) {
247            // if not defined use default
248            if (addLineDialog == null) {
249                addLineDialog = (DialogGroup) ComponentFactory.getNewComponentInstance(
250                        ComponentFactory.ADD_LINE_DIALOG);
251            }
252            // assign this group to the layout manager
253            ((CollectionLayoutManager) getLayoutManager()).setAddLineGroup(addLineDialog);
254            // if the add dialog group had items then use them
255            if (!addLineDialog.getItems().isEmpty()) {
256                addLineItems = addLineDialog.getItems();
257            }
258        }
259
260        // if its a edit line in dialog, then set the edit line dialog and edit line action if not supplied
261        if (editWithDialog) {
262
263            // initialize edit line dialog prototype if not set
264            if (editLineDialogPrototype == null) {
265                editLineDialogPrototype = (DialogGroup) ComponentUtils.copy(ComponentFactory.
266                        getNewComponentInstance(ComponentFactory.EDIT_LINE_DIALOG));
267            } else if (editLineDialogPrototype.getItems() != null && !editLineDialogPrototype.getItems().isEmpty()) {
268                // set custom dialog flag
269                customEditLineDialog = true;
270            }
271
272            // initialize the edit line action prototype if not set
273            if (editWithDialogActionPrototype == null) {
274                editWithDialogActionPrototype = (Action) ComponentUtils.copy(ComponentFactory.
275                        getNewComponentInstance(ComponentFactory.EDIT_LINE_IN_DIALOG_ACTION));
276            }
277
278            // initialize the edit line dialog's save action prototype
279            if (editInDialogSaveActionPrototype == null) {
280                editInDialogSaveActionPrototype = ComponentUtils.copy((Action) ComponentFactory.
281                        getNewComponentInstance(ComponentFactory.EDIT_LINE_IN_DIALOG_SAVE_ACTION));
282            }
283        }
284
285        // if active collection filter not set use default
286        if (activeCollectionFilter == null) {
287            activeCollectionFilter = new ActiveCollectionFilter();
288        }
289
290        // set static collection path on items
291        String collectionPath = "";
292        if (StringUtils.isNotBlank(getBindingInfo().getCollectionPath())) {
293            collectionPath += getBindingInfo().getCollectionPath() + ".";
294        }
295
296        // Check to see if binding prefix path starts the same as the collection path,
297        // and if it does just start with that instead
298        if (StringUtils.isNotBlank(getBindingInfo().getBindByNamePrefix()) && StringUtils.isNotBlank(
299                getBindingInfo().getCollectionPath()) && getBindingInfo().getBindByNamePrefix().startsWith(
300                getBindingInfo().getCollectionPath())) {
301            collectionPath = getBindingInfo().getBindByNamePrefix() + ".";
302        } else if (StringUtils.isNotBlank(getBindingInfo().getBindByNamePrefix())) {
303            collectionPath += getBindingInfo().getBindByNamePrefix() + ".";
304        }
305
306        collectionPath += getBindingInfo().getBindingName();
307
308        List<DataField> collectionFields = ComponentUtils.getNestedNonCollectionComponents((List<Component>) getItems(),
309                DataField.class);
310        List<DataField> addLineCollectionFields = ComponentUtils.getNestedNonCollectionComponents(
311                (List<Component>) addLineItems, DataField.class);
312        if (addLineCollectionFields != null) {
313            collectionFields.addAll(addLineCollectionFields);
314        }
315
316        for (DataField collectionField : collectionFields) {
317            collectionField.getBindingInfo().setCollectionPath(collectionPath);
318
319            if (StringUtils.isBlank(collectionField.getDictionaryObjectEntry())) {
320                collectionField.setDictionaryObjectEntry(collectionObjectClass.getName());
321            }
322        }
323
324        for (CollectionGroup collectionGroup : getSubCollections()) {
325            collectionGroup.getBindingInfo().setCollectionPath(collectionPath);
326        }
327
328        // add collection entry to abstract classes
329        if (!view.getObjectPathToConcreteClassMapping().containsKey(collectionPath)) {
330            view.getObjectPathToConcreteClassMapping().put(collectionPath, getCollectionObjectClass());
331        }
332    }
333
334    /**
335     * {@inheritDoc}
336     */
337    @Override
338    public void performApplyModel(Object model, LifecycleElement parent) {
339        super.performApplyModel(model, parent);
340
341        ViewModel viewModel = (ViewModel) model;
342        View view = ViewLifecycle.getView();
343
344        // if server paging is enabled get the display start from post data so we build the correct page
345        if (this.isUseServerPaging()) {
346            Object displayStart = ViewLifecycle.getViewPostMetadata().getComponentPostData(this.getId(),
347                    UifConstants.PostMetadata.COLL_DISPLAY_START);
348            if (displayStart != null) {
349                this.setDisplayStart(((Integer) displayStart).intValue());
350            }
351
352            Object displayLength = ViewLifecycle.getViewPostMetadata().getComponentPostData(this.getId(),
353                    UifConstants.PostMetadata.COLL_DISPLAY_LENGTH);
354            if (displayLength != null) {
355                this.setDisplayLength(((Integer) displayLength).intValue());
356            }
357        }
358
359        // if we are processing a paging request for this component, invoke the layout managers to carry out the paging
360        if (viewModel.isCollectionPagingRequest() && StringUtils.equals(viewModel.getUpdateComponentId(), getId())) {
361            ((CollectionLayoutManager) getLayoutManager()).processPagingRequest(model, this);
362        }
363
364        if (StringUtils.isNotBlank(this.getId()) && viewModel.getViewPostMetadata() != null
365                && viewModel.getViewPostMetadata().getAddedCollectionObjects().get(this.getId()) != null) {
366            List<Object> newLines = viewModel.getViewPostMetadata().getAddedCollectionObjects().get(this.getId());
367
368            // if newLines is empty this means its an addLine case (no additional processing) so init collection line
369            if (newLines.isEmpty()) {
370                initializeNewCollectionLine(view, model, this, true);
371            }
372
373            for (Object newLine : newLines) {
374                ViewLifecycle.getHelper().applyDefaultValuesForCollectionLine(this, newLine);
375            }
376        }
377
378        // adds the script to the add line buttons to keep collection on the same page
379        if (this.renderAddBlankLineButton) {
380            if (this.addBlankLineAction == null) {
381                this.addBlankLineAction = (Action) ComponentFactory.getNewComponentInstance(
382                        ComponentFactory.ADD_BLANK_LINE_ACTION);
383            }
384
385            if (addLinePlacement.equals(UifConstants.Position.BOTTOM.name())) {
386                this.addBlankLineAction.setOnClickScript("writeCurrentPageToSession(this, 'last');");
387            } else {
388                this.addBlankLineAction.setOnClickScript("writeCurrentPageToSession(this, 'first');");
389            }
390        } else if (this.addWithDialog) {
391            setupAddLineDialog();
392        }
393
394        pushCollectionGroupToReference();
395
396        // set up action validation scripts to avoid bind errors
397        List<Component> allComponents = new ArrayList<Component>(getItems());
398        allComponents.addAll(getAddLineItems());
399        List<Component> allActionComponents = new ArrayList<Component>(getLineActions());
400        allActionComponents.addAll(getAddLineActions());
401        setupLineActionValidationScripts(allComponents, allActionComponents);
402
403        // if rendering the collection group, build out the lines
404        if (isRender()) {
405            getCollectionGroupBuilder().build(view, model, this);
406        }
407    }
408
409    /**
410     * Helper method to set action validation script for every action component provided to validate every
411     * input field component.
412     *
413     * @param components the components with input fields
414     * @param actionComponents the components with actions
415     */
416    protected void setupLineActionValidationScripts(List<Component> components, List<Component> actionComponents) {
417        List<InputField> inputFields = new ArrayList<InputField>();
418        for (Component component : components) {
419            if (component instanceof InputField) {
420                inputFields.add((InputField) component);
421            }
422        }
423
424        String script = buildInputFieldValidationActionScript(inputFields, null);
425        for (Component actionComponent : actionComponents) {
426            if (actionComponent instanceof Action) {
427                Action action = (Action) actionComponent;
428                String onClickScript = action.getOnClickScript();
429                if (StringUtils.isNotEmpty(onClickScript)) {
430                    script = ScriptUtils.appendScript(script, onClickScript);
431                }
432                action.setOnClickScript(script);
433            }
434        }
435    }
436
437    /**
438     * When add via dialog is true, initialize the add with dialog action (if necessary) and sets up the
439     * action script for opening the dialog.
440     */
441    protected void setupAddLineDialog() {
442        if (addWithDialogAction == null) {
443            addWithDialogAction = (Action) ComponentFactory.getNewComponentInstance(
444                    ComponentFactory.ADD_WITH_DIALOG_ACTION);
445        }
446
447        String sessionPage = "first";
448        if (addLinePlacement.equals(UifConstants.Position.BOTTOM.name())) {
449            sessionPage = "last";
450        }
451
452        String dialogId = addLineDialog.getId();
453        if (StringUtils.isNotBlank(this.getContainerIdSuffix())) {
454            dialogId = dialogId + this.getContainerIdSuffix();
455        }
456
457        // add the dialog id as additional parameters to the actions in the dialog
458        String additionalData =
459                "{ '" + UifPropertyPaths.ACTION_PARAMETERS + "[" + UifParameters.SELECTED_COLLECTION_PATH + "]' : '"
460                        + propertyName + "', '" + UifPropertyPaths.ACTION_PARAMETERS + "["
461                        + UifParameters.SELECTED_LINE_INDEX + "]' : '0', '" + UifPropertyPaths.ACTION_PARAMETERS + "["
462                        + UifParameters.DIALOG_ID + "]' : '" + dialogId + "' }";
463        String actionScript = UifConstants.JsFunctions.WRITE_CURRENT_PAGE_TO_SESSION + "(this, '" + sessionPage + "');";
464
465        actionScript = ScriptUtils.appendScript(addWithDialogAction.getActionScript(), actionScript);
466        final String showDialogScript = "showDialog('" + dialogId + "', " + additionalData + ");";
467        actionScript = ScriptUtils.appendScript(actionScript, showDialogScript);
468
469        addWithDialogAction.setActionScript(actionScript);
470    }
471
472    /**
473     * {@inheritDoc}
474     */
475    @Override
476    public void performFinalize(Object model, LifecycleElement parent) {
477        super.performFinalize(model, parent);
478
479        addCollectionPostMetadata();
480
481        // set fields to send if adding with dialog
482        if (addWithDialog && addLineDialog != null && addLineDialog.getFooter() != null) {
483            List<String> fieldsToSend = new ArrayList<String>();
484            fieldsToSend.add("#" + addLineDialog.getId());
485
486            for (Component cmpnt : addLineDialog.getFooter().getItems()) {
487                if (cmpnt instanceof  Action) {
488                    ((Action)cmpnt).setFieldsToSend(fieldsToSend);
489                }
490            }
491        }
492    }
493
494    /**
495     * Add the metadata about this collection to the ViewPostMetadata
496     * that is to be kept in memory between posts for use by other methods
497     */
498    protected void addCollectionPostMetadata() {
499        if (this.getCollectionLookup() != null) {
500            ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
501                    UifConstants.PostMetadata.COLL_LOOKUP_FIELD_CONVERSIONS,
502                    this.getCollectionLookup().getFieldConversions());
503        }
504
505        ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.COLL_OBJECT_CLASS,
506                this.getCollectionObjectClass());
507
508        ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.BINDING_INFO,
509                this.getBindingInfo());
510
511        ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.ADD_LINE_BINDING_INFO,
512                this.getAddLineBindingInfo());
513
514        ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.ADD_LINE_PLACEMENT,
515                this.getAddLinePlacement());
516
517        if (this.getHeader() != null) {
518            ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.COLL_LABEL,
519                    this.getCollectionLabel());
520        }
521
522        if (this.getDuplicateLinePropertyNames() != null) {
523            ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
524                    UifConstants.PostMetadata.DUPLICATE_LINE_PROPERTY_NAMES, this.getDuplicateLinePropertyNames());
525            ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
526                    UifConstants.PostMetadata.DUPLICATE_LINE_LABEL_STRING, this.getDuplicateLineLabelString(
527                            this.getDuplicateLinePropertyNames())
528            );
529        }
530
531        boolean hasBindingPath = getBindingInfo() != null && getBindingInfo().getBindingPath() != null;
532        if (hasBindingPath) {
533            ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.BINDING_PATH,
534                    getBindingInfo().getBindingPath());
535        }
536
537        ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.COLL_DISPLAY_START,
538                getDisplayStart());
539        ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.COLL_DISPLAY_LENGTH,
540                getDisplayLength());
541    }
542
543    /**
544     * {@inheritDoc}
545     */
546    @Override
547    public void pushCollectionGroupToReference() {
548        Collection<LifecycleElement> components = ViewLifecycleUtils.getElementsForLifecycle(this).values();
549        ContextUtils.pushObjectToContextDeep(components, UifConstants.ContextVariableNames.COLLECTION_GROUP, this);
550
551        List<Action> actions = ViewLifecycleUtils.getElementsOfTypeDeep(components, Action.class);
552        for (Action action : actions) {
553            action.addActionParameter(UifParameters.SELECTED_COLLECTION_PATH, this.getBindingInfo().getBindingPath());
554            action.addActionParameter(UifParameters.SELECTED_COLLECTION_ID, this.getId());
555        }
556    }
557
558    /**
559     * Gets the label for the collection in a human-friendly format.
560     *
561     * @return a human-friendly collection label
562     */
563    protected String getCollectionLabel() {
564        String collectionLabel = this.getHeaderText();
565
566        if (StringUtils.isBlank(collectionLabel)) {
567            String propertyName = this.getPropertyName();
568            collectionLabel = KRADServiceLocatorWeb.getUifDefaultingService().deriveHumanFriendlyNameFromPropertyName(
569                    propertyName);
570        }
571
572        return collectionLabel;
573    }
574
575    /**
576     * Gets a comma-separated list of the data field labels that are keyed a duplicates.
577     *
578     * @param duplicateLinePropertyNames the property names to check for duplicates
579     * @return a comma-separated list of labels
580     */
581    protected String getDuplicateLineLabelString(List<String> duplicateLinePropertyNames) {
582        List<String> duplicateLineLabels = new ArrayList<String>();
583
584        List<DataField> fields = new ArrayList<DataField>();
585
586        for (Component addLineItem : getAddLineItems()) {
587            if (addLineItem instanceof DataField) {
588                fields.add((DataField) addLineItem);
589            } else if (addLineItem instanceof FieldGroup) {
590                Group group = ((FieldGroup) addLineItem).getGroup();
591                List<DataField> nestedAddLineItems = ViewLifecycleUtils.getElementsOfTypeDeep(group, DataField.class);
592                fields.addAll(nestedAddLineItems);
593            }
594        }
595
596        for (DataField field : fields) {
597            if (duplicateLinePropertyNames.contains(field.getPropertyName())) {
598                String label = field.getLabel();
599                String shortLabel = field.getShortLabel();
600                duplicateLineLabels.add(StringUtils.isNotBlank(label) ? label : shortLabel);
601            }
602        }
603
604        return StringUtils.join(duplicateLineLabels, ", ");
605    }
606
607    /**
608     * New collection lines are handled in the framework by maintaining a map on
609     * the form. The map contains as a key the collection name, and as value an
610     * instance of the collection type. An entry is created here for the
611     * collection represented by the <code>CollectionGroup</code> if an instance
612     * is not available (clearExistingLine will force a new instance). The given
613     * model must be a subclass of <code>UifFormBase</code> in order to find the
614     * Map.
615     *
616     * @param model Model instance that contains the new collection lines Map
617     * @param clearExistingLine boolean that indicates whether the line should be set to a
618     * new instance if it already exists
619     */
620    @Override
621    public void initializeNewCollectionLine(View view, Object model, CollectionGroup collectionGroup,
622            boolean clearExistingLine) {
623        getCollectionGroupBuilder().initializeNewCollectionLine(view, model, collectionGroup, clearExistingLine);
624    }
625
626    /**
627     * Do not process remote field holders for collections. Collection items will be processed as
628     * the lines are built.
629     *
630     * {@inheritDoc}
631     */
632    @Override
633    public boolean isProcessRemoteFieldHolders() {
634        return false;
635    }
636
637    /**
638     * {@inheritDoc}
639     */
640    @Override
641    @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
642    @BeanTagAttribute
643    public List<? extends Component> getItems() {
644        return super.getItems();
645    }
646
647    /**
648     * {@inheritDoc}
649     */
650    @Override
651    @BeanTagAttribute
652    public Class<?> getCollectionObjectClass() {
653        return this.collectionObjectClass;
654    }
655
656    /**
657     * {@inheritDoc}
658     */
659    @Override
660    public void setCollectionObjectClass(Class<?> collectionObjectClass) {
661        this.collectionObjectClass = collectionObjectClass;
662    }
663
664    /**
665     * {@inheritDoc}
666     */
667    @Override
668    @BeanTagAttribute
669    public String getPropertyName() {
670        return this.propertyName;
671    }
672
673    /**
674     * {@inheritDoc}
675     */
676    @Override
677    public void setPropertyName(String propertyName) {
678        this.propertyName = propertyName;
679    }
680
681    /**
682     * {@inheritDoc}
683     */
684    @Override
685    @BeanTagAttribute
686    public BindingInfo getBindingInfo() {
687        return this.bindingInfo;
688    }
689
690    /**
691     * {@inheritDoc}
692     */
693    @Override
694    public void setBindingInfo(BindingInfo bindingInfo) {
695        this.bindingInfo = bindingInfo;
696    }
697
698    /**
699     * {@inheritDoc}
700     */
701    @Override
702    @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
703    @BeanTagAttribute
704    public List<? extends Component> getLineActions() {
705        return this.lineActions;
706    }
707
708    /**
709     * {@inheritDoc}
710     */
711    @Override
712    public void setLineActions(List<? extends Component> lineActions) {
713        this.lineActions = lineActions;
714    }
715
716    /**
717     * {@inheritDoc}
718     */
719    @Override
720    @BeanTagAttribute
721    public String getAddLineEnterKeyAction() {
722        return this.addLineEnterKeyAction;
723    }
724
725    /**
726     * {@inheritDoc}
727     */
728    @Override
729    public void setAddLineEnterKeyAction(String addLineEnterKeyAction) {
730        this.addLineEnterKeyAction = addLineEnterKeyAction;
731    }
732
733    /**
734     * {@inheritDoc}
735     */
736    @Override
737    @BeanTagAttribute
738    public String getLineEnterKeyAction() {
739        return this.lineEnterKeyAction;
740    }
741
742    /**
743     * {@inheritDoc}
744     */
745    @Override
746    public void setLineEnterKeyAction(String lineEnterKeyAction) {
747        this.lineEnterKeyAction = lineEnterKeyAction;
748    }
749
750    /**
751     * {@inheritDoc}
752     */
753    @Override
754    @BeanTagAttribute
755    public boolean isRenderLineActions() {
756        return this.renderLineActions;
757    }
758
759    /**
760     * {@inheritDoc}
761     */
762    @Override
763    public void setRenderLineActions(boolean renderLineActions) {
764        this.renderLineActions = renderLineActions;
765    }
766
767    /**
768     * {@inheritDoc}
769     */
770    @Override
771    @BeanTagAttribute
772    public boolean isRenderAddLine() {
773        if (this.useServerPaging && this.renderAddLine) {
774            return this.displayStart == 0 ? true : false;
775        }
776        return this.renderAddLine;
777    }
778
779    /**
780     * {@inheritDoc}
781     */
782    @Override
783    public void setRenderAddLine(boolean renderAddLine) {
784        this.renderAddLine = renderAddLine;
785    }
786
787    /**
788     * {@inheritDoc}
789     */
790    @Override
791    @BeanTagAttribute
792    public String getAddLabel() {
793        if (getAddLineLabel() != null) {
794            return getAddLineLabel().getMessageText();
795        }
796
797        return null;
798    }
799
800    /**
801     * {@inheritDoc}
802     */
803    @Override
804    public void setAddLabel(String addLabelText) {
805        if (getAddLineLabel() != null) {
806            getAddLineLabel().setMessageText(addLabelText);
807        }
808    }
809
810    /**
811     * {@inheritDoc}
812     */
813    @Override
814    @BeanTagAttribute
815    public Message getAddLineLabel() {
816        return this.addLineLabel;
817    }
818
819    /**
820     * {@inheritDoc}
821     */
822    @Override
823    public void setAddLineLabel(Message addLineLabel) {
824        this.addLineLabel = addLineLabel;
825    }
826
827    /**
828     * {@inheritDoc}
829     */
830    @Override
831    @BeanTagAttribute
832    public String getAddLinePropertyName() {
833        return this.addLinePropertyName;
834    }
835
836    /**
837     * {@inheritDoc}
838     */
839    @Override
840    public void setAddLinePropertyName(String addLinePropertyName) {
841        this.addLinePropertyName = addLinePropertyName;
842    }
843
844    /**
845     * {@inheritDoc}
846     */
847    @Override
848    @BeanTagAttribute
849    public BindingInfo getAddLineBindingInfo() {
850        return this.addLineBindingInfo;
851    }
852
853    /**
854     * {@inheritDoc}
855     */
856    @Override
857    public void setAddLineBindingInfo(BindingInfo addLineBindingInfo) {
858        this.addLineBindingInfo = addLineBindingInfo;
859    }
860
861    /**
862     * {@inheritDoc}
863     */
864    @Override
865    @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
866    @BeanTagAttribute
867    public List<? extends Component> getAddLineItems() {
868        return this.addLineItems;
869    }
870
871    /**
872     * {@inheritDoc}
873     */
874    @Override
875    public void setAddLineItems(List<? extends Component> addLineItems) {
876        this.addLineItems = addLineItems;
877    }
878
879    /**
880     * {@inheritDoc}
881     */
882    @Override
883    @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
884    @BeanTagAttribute
885    public List<? extends Component> getAddLineActions() {
886        return this.addLineActions;
887    }
888
889    /**
890     * {@inheritDoc}
891     */
892    @Override
893    public void setAddLineActions(List<? extends Component> addLineActions) {
894        this.addLineActions = addLineActions;
895    }
896
897    /**
898     * {@inheritDoc}
899     */
900    @Override
901    @BeanTagAttribute
902    public boolean isIncludeLineSelectionField() {
903        return includeLineSelectionField;
904    }
905
906    /**
907     * {@inheritDoc}
908     */
909    @Override
910    public void setIncludeLineSelectionField(boolean includeLineSelectionField) {
911        this.includeLineSelectionField = includeLineSelectionField;
912    }
913
914    /**
915     * {@inheritDoc}
916     */
917    @Override
918    @BeanTagAttribute
919    public String getLineSelectPropertyName() {
920        return lineSelectPropertyName;
921    }
922
923    /**
924     * {@inheritDoc}
925     */
926    @Override
927    public void setLineSelectPropertyName(String lineSelectPropertyName) {
928        this.lineSelectPropertyName = lineSelectPropertyName;
929    }
930
931    /**
932     * {@inheritDoc}
933     */
934    @Override
935    @BeanTagAttribute(type = BeanTagAttribute.AttributeType.BYTYPE)
936    public QuickFinder getCollectionLookup() {
937        return collectionLookup;
938    }
939
940    /**
941     * {@inheritDoc}
942     */
943    @Override
944    public void setCollectionLookup(QuickFinder collectionLookup) {
945        this.collectionLookup = collectionLookup;
946    }
947
948    /**
949     * {@inheritDoc}
950     */
951    @Override
952    @BeanTagAttribute
953    public boolean isShowInactiveLines() {
954        return showInactiveLines;
955    }
956
957    /**
958     * {@inheritDoc}
959     */
960    @Override
961    public void setShowInactiveLines(boolean showInactiveLines) {
962        this.showInactiveLines = showInactiveLines;
963    }
964
965    /**
966     * {@inheritDoc}
967     */
968    @Override
969    @BeanTagAttribute
970    public CollectionFilter getActiveCollectionFilter() {
971        return activeCollectionFilter;
972    }
973
974    /**
975     * {@inheritDoc}
976     */
977    @Override
978    public void setActiveCollectionFilter(CollectionFilter activeCollectionFilter) {
979        this.activeCollectionFilter = activeCollectionFilter;
980    }
981
982    /**
983     * {@inheritDoc}
984     */
985    @Override
986    @BeanTagAttribute
987    public List<CollectionFilter> getFilters() {
988        return filters;
989    }
990
991    /**
992     * {@inheritDoc}
993     */
994    @Override
995    public void setFilters(List<CollectionFilter> filters) {
996        this.filters = filters;
997    }
998
999    /**
1000     * {@inheritDoc}
1001     */
1002    @Override
1003    @BeanTagAttribute
1004    public List<String> getDuplicateLinePropertyNames() {
1005        return this.duplicateLinePropertyNames;
1006    }
1007
1008    /**
1009     * {@inheritDoc}
1010     */
1011    public void setDuplicateLinePropertyNames(List<String> duplicateLinePropertyNames) {
1012        this.duplicateLinePropertyNames = duplicateLinePropertyNames;
1013    }
1014
1015    /**
1016     * {@inheritDoc}
1017     */
1018    @Override
1019    public List<BindingInfo> getUnauthorizedLineBindingInfos() {
1020        return this.unauthorizedLineBindingInfos;
1021    }
1022
1023    /**
1024     * {@inheritDoc}
1025     */
1026    @Override
1027    public void setUnauthorizedLineBindingInfos(List<BindingInfo> unauthorizedLineBindingInfos) {
1028        this.unauthorizedLineBindingInfos = unauthorizedLineBindingInfos;
1029    }
1030
1031    /**
1032     * List of <code>CollectionGroup</code> instances that are sub-collections
1033     * of the collection represented by this collection group
1034     *
1035     * @return sub collections
1036     */
1037    @Override
1038    @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
1039    @BeanTagAttribute
1040    public List<CollectionGroup> getSubCollections() {
1041        return this.subCollections;
1042    }
1043
1044    /**
1045     * Setter for the sub collection list
1046     */
1047    @Override
1048    public void setSubCollections(List<CollectionGroup> subCollections) {
1049        this.subCollections = subCollections;
1050    }
1051
1052    /**
1053     * {@inheritDoc}
1054     */
1055    @Override
1056    public CollectionGroupSecurity getCollectionGroupSecurity() {
1057        return (CollectionGroupSecurity) super.getComponentSecurity();
1058    }
1059
1060    /**
1061     * {@inheritDoc}
1062     */
1063    @Override
1064    public void setComponentSecurity(ComponentSecurity componentSecurity) {
1065        if ((componentSecurity != null) && !(componentSecurity instanceof CollectionGroupSecurity)) {
1066            throw new RiceRuntimeException(
1067                    "Component security for CollectionGroup should be instance of CollectionGroupSecurity");
1068        }
1069
1070        super.setComponentSecurity(componentSecurity);
1071    }
1072
1073    /**
1074     * {@inheritDoc}
1075     */
1076    @Override
1077    protected void initializeComponentSecurity() {
1078        if (getComponentSecurity() == null) {
1079            setComponentSecurity(KRADUtils.createNewObjectFromClass(CollectionGroupSecurity.class));
1080        }
1081    }
1082
1083    /**
1084     * {@inheritDoc}
1085     */
1086    @Override
1087    @BeanTagAttribute
1088    public boolean isEditLineAuthz() {
1089        initializeComponentSecurity();
1090
1091        return getCollectionGroupSecurity().isEditLineAuthz();
1092    }
1093
1094    /**
1095     * {@inheritDoc}
1096     */
1097    @Override
1098    public void setEditLineAuthz(boolean editLineAuthz) {
1099        initializeComponentSecurity();
1100
1101        getCollectionGroupSecurity().setEditLineAuthz(editLineAuthz);
1102    }
1103
1104    /**
1105     * {@inheritDoc}
1106     */
1107    @Override
1108    @BeanTagAttribute
1109    public boolean isViewLineAuthz() {
1110        initializeComponentSecurity();
1111
1112        return getCollectionGroupSecurity().isViewLineAuthz();
1113    }
1114
1115    /**
1116     * {@inheritDoc}
1117     */
1118    @Override
1119    public void setViewLineAuthz(boolean viewLineAuthz) {
1120        initializeComponentSecurity();
1121
1122        getCollectionGroupSecurity().setViewLineAuthz(viewLineAuthz);
1123    }
1124
1125    /**
1126     * {@inheritDoc}
1127     */
1128    @Override
1129    @BeanTagAttribute
1130    public CollectionGroupBuilder getCollectionGroupBuilder() {
1131        if (this.collectionGroupBuilder == null) {
1132            this.collectionGroupBuilder = new CollectionGroupBuilder();
1133        }
1134        return this.collectionGroupBuilder;
1135    }
1136
1137    /**
1138     * {@inheritDoc}
1139     */
1140    @Override
1141    public void setCollectionGroupBuilder(CollectionGroupBuilder collectionGroupBuilder) {
1142        this.collectionGroupBuilder = collectionGroupBuilder;
1143    }
1144
1145    /**
1146     * {@inheritDoc}
1147     */
1148    @Override
1149    @BeanTagAttribute
1150    public boolean isRenderInactiveToggleButton() {
1151        return renderInactiveToggleButton;
1152    }
1153
1154    /**
1155     * {@inheritDoc}
1156     */
1157    @Override
1158    public void setRenderInactiveToggleButton(boolean renderInactiveToggleButton) {
1159        this.renderInactiveToggleButton = renderInactiveToggleButton;
1160    }
1161
1162    /**
1163     * {@inheritDoc}
1164     */
1165    @Override
1166    @BeanTagAttribute
1167    public int getDisplayCollectionSize() {
1168        return this.displayCollectionSize;
1169    }
1170
1171    /**
1172     * {@inheritDoc}
1173     */
1174    @Override
1175    public void setDisplayCollectionSize(int displayCollectionSize) {
1176        this.displayCollectionSize = displayCollectionSize;
1177    }
1178
1179    /**
1180     * {@inheritDoc}
1181     */
1182    @Override
1183    @BeanTagAttribute
1184    public boolean isHighlightNewItems() {
1185        return highlightNewItems;
1186    }
1187
1188    /**
1189     * {@inheritDoc}
1190     */
1191    @Override
1192    public void setHighlightNewItems(boolean highlightNewItems) {
1193        this.highlightNewItems = highlightNewItems;
1194    }
1195
1196    /**
1197     * {@inheritDoc}
1198     */
1199    @Override
1200    @BeanTagAttribute
1201    public String getNewItemsCssClass() {
1202        return newItemsCssClass;
1203    }
1204
1205    /**
1206     * {@inheritDoc}
1207     */
1208    @Override
1209    public void setNewItemsCssClass(String newItemsCssClass) {
1210        this.newItemsCssClass = newItemsCssClass;
1211    }
1212
1213    /**
1214     * {@inheritDoc}
1215     */
1216    @Override
1217    @BeanTagAttribute
1218    public String getAddItemCssClass() {
1219        return addItemCssClass;
1220    }
1221
1222    /**
1223     * {@inheritDoc}
1224     */
1225    @Override
1226    public void setAddItemCssClass(String addItemCssClass) {
1227        this.addItemCssClass = addItemCssClass;
1228    }
1229
1230    /**
1231     * {@inheritDoc}
1232     */
1233    @Override
1234    @BeanTagAttribute
1235    public boolean isHighlightAddItem() {
1236        return highlightAddItem;
1237    }
1238
1239    /**
1240     * {@inheritDoc}
1241     */
1242    @Override
1243    public void setHighlightAddItem(boolean highlightAddItem) {
1244        this.highlightAddItem = highlightAddItem;
1245    }
1246
1247    /**
1248     * {@inheritDoc}
1249     */
1250    @Override
1251    @BeanTagAttribute
1252    public boolean isRenderAddBlankLineButton() {
1253        return renderAddBlankLineButton;
1254    }
1255
1256    /**
1257     * {@inheritDoc}
1258     */
1259    @Override
1260    public void setRenderAddBlankLineButton(boolean renderAddBlankLineButton) {
1261        this.renderAddBlankLineButton = renderAddBlankLineButton;
1262    }
1263
1264    /**
1265     * {@inheritDoc}
1266     */
1267    @Override
1268    @BeanTagAttribute
1269    public Action getAddBlankLineAction() {
1270        return addBlankLineAction;
1271    }
1272
1273    /**
1274     * {@inheritDoc}
1275     */
1276    @Override
1277    public void setAddBlankLineAction(Action addBlankLineAction) {
1278        this.addBlankLineAction = addBlankLineAction;
1279    }
1280
1281    /**
1282     * {@inheritDoc}
1283     */
1284    @Override
1285    @BeanTagAttribute
1286    public String getAddLinePlacement() {
1287        return addLinePlacement;
1288    }
1289
1290    /**
1291     * {@inheritDoc}
1292     */
1293    @Override
1294    public void setAddLinePlacement(String addLinePlacement) {
1295        this.addLinePlacement = addLinePlacement;
1296    }
1297
1298    /**
1299     * {@inheritDoc}
1300     */
1301    @Override
1302    @BeanTagAttribute
1303    public boolean isRenderSaveLineActions() {
1304        return renderSaveLineActions;
1305    }
1306
1307    /**
1308     * {@inheritDoc}
1309     */
1310    @Override
1311    public void setRenderSaveLineActions(boolean renderSaveLineActions) {
1312        this.renderSaveLineActions = renderSaveLineActions;
1313    }
1314
1315    /**
1316     * {@inheritDoc}
1317     */
1318    @Override
1319    @BeanTagAttribute
1320    public boolean isAddWithDialog() {
1321        return addWithDialog;
1322    }
1323
1324    /**
1325     * {@inheritDoc}
1326     */
1327    @Override
1328    public void setAddWithDialog(boolean addWithDialog) {
1329        this.addWithDialog = addWithDialog;
1330    }
1331
1332    /**
1333     * {@inheritDoc}
1334     */
1335    @Override
1336    @BeanTagAttribute
1337    public Action getAddWithDialogAction() {
1338        return addWithDialogAction;
1339    }
1340
1341    /**
1342     * {@inheritDoc}
1343     */
1344    @Override
1345    public void setAddWithDialogAction(Action addWithDialogAction) {
1346        this.addWithDialogAction = addWithDialogAction;
1347    }
1348
1349    /**
1350     * {@inheritDoc}
1351     */
1352    @Override
1353    @BeanTagAttribute
1354    public DialogGroup getAddLineDialog() {
1355        return addLineDialog;
1356    }
1357
1358    /**
1359     * {@inheritDoc}
1360     */
1361    @Override
1362    public void setAddLineDialog(DialogGroup addLineDialog) {
1363        this.addLineDialog = addLineDialog;
1364    }
1365
1366    /**
1367     * {@inheritDoc}
1368     */
1369    @Override
1370    @BeanTagAttribute
1371    public boolean isUseServerPaging() {
1372        return useServerPaging;
1373    }
1374
1375    /**
1376     * {@inheritDoc}
1377     */
1378    @Override
1379    public void setUseServerPaging(boolean useServerPaging) {
1380        this.useServerPaging = useServerPaging;
1381    }
1382
1383    /**
1384     * {@inheritDoc}
1385     */
1386    @Override
1387    public int getPageSize() {
1388        return pageSize;
1389    }
1390
1391    /**
1392     * {@inheritDoc}
1393     */
1394    @Override
1395    public void setPageSize(int pageSize) {
1396        this.pageSize = pageSize;
1397    }
1398
1399    /**
1400     * {@inheritDoc}
1401     */
1402    @Override
1403    public int getDisplayStart() {
1404        return displayStart;
1405    }
1406
1407    /**
1408     * {@inheritDoc}
1409     */
1410    @Override
1411    public void setDisplayStart(int displayStart) {
1412        this.displayStart = displayStart;
1413    }
1414
1415    /**
1416     * {@inheritDoc}
1417     */
1418    @Override
1419    public int getDisplayLength() {
1420        return displayLength;
1421    }
1422
1423    /**
1424     * {@inheritDoc}
1425     */
1426    @Override
1427    public void setDisplayLength(int displayLength) {
1428        this.displayLength = displayLength;
1429    }
1430
1431    /**
1432     * {@inheritDoc}
1433     */
1434    @Override
1435    public int getFilteredCollectionSize() {
1436        return filteredCollectionSize;
1437    }
1438
1439    /**
1440     * {@inheritDoc}
1441     */
1442    @Override
1443    public void setFilteredCollectionSize(int filteredCollectionSize) {
1444        this.filteredCollectionSize = filteredCollectionSize;
1445    }
1446
1447    public int getTotalCollectionSize() {
1448        return totalCollectionSize;
1449    }
1450
1451    public void setTotalCollectionSize(int totalCollectionSize) {
1452        this.totalCollectionSize = totalCollectionSize;
1453    }
1454
1455    /**
1456     * @return list of total columns
1457     */
1458    @BeanTagAttribute
1459    protected List<String> getTotalColumns() {
1460        return totalColumns;
1461    }
1462
1463    /**
1464     * Setter for the total columns
1465     */
1466    protected void setTotalColumns(List<String> totalColumns) {
1467        this.totalColumns = totalColumns;
1468    }
1469
1470    /**
1471     * {@inheritDoc}
1472     */
1473    @Override
1474    public void completeValidation(ValidationTrace tracer) {
1475        tracer.addBean(this);
1476
1477        // Checking if collectionObjectClass is set
1478        if (getCollectionObjectClass() == null) {
1479            if (Validator.checkExpressions(this, UifConstants.PostMetadata.COLL_OBJECT_CLASS)) {
1480                String currentValues[] = {"collectionObjectClass = " + getCollectionObjectClass()};
1481                tracer.createWarning("CollectionObjectClass is not set (disregard if part of an abstract)",
1482                        currentValues);
1483            }
1484        }
1485
1486        super.completeValidation(tracer.getCopy());
1487    }
1488
1489    /**
1490     * {@inheritDoc}
1491     */
1492    @Override
1493    @BeanTagAttribute
1494    public boolean isEditWithDialog() {
1495        return editWithDialog;
1496    }
1497
1498    /**
1499     * {@inheritDoc}
1500     */
1501    @Override
1502    public void setEditWithDialog(boolean editWithDialog) {
1503        this.editWithDialog = editWithDialog;
1504    }
1505
1506    /**
1507     * {@inheritDoc}
1508     */
1509    @Override
1510    @BeanTagAttribute
1511    public boolean isCustomEditLineDialog() {
1512        return customEditLineDialog;
1513    }
1514
1515    /**
1516     * {@inheritDoc}
1517     */
1518    @Override
1519    public void setCustomEditLineDialog(boolean customEditLineDialog) {
1520        this.customEditLineDialog = customEditLineDialog;
1521    }
1522
1523    /**
1524     * {@inheritDoc}
1525     */
1526    @Override
1527    @BeanTagAttribute
1528    public DialogGroup getEditLineDialogPrototype() {
1529        return editLineDialogPrototype;
1530    }
1531
1532    /**
1533     * {@inheritDoc}
1534     */
1535    @Override
1536    public void setEditLineDialogPrototype(DialogGroup editLineDialogPrototype) {
1537        this.editLineDialogPrototype = editLineDialogPrototype;
1538    }
1539
1540    /**
1541     * {@inheritDoc}
1542     */
1543    @Override
1544    @BeanTagAttribute
1545    public Action getEditWithDialogActionPrototype() {
1546        return editWithDialogActionPrototype;
1547    }
1548
1549    /**
1550     * {@inheritDoc}
1551     */
1552    @Override
1553    public void setEditWithDialogActionPrototype(Action editWithDialogActionPrototype) {
1554        this.editWithDialogActionPrototype = editWithDialogActionPrototype;
1555    }
1556
1557    /**
1558     * {@inheritDoc}
1559     */
1560    @Override
1561    @BeanTagAttribute
1562    public Action getEditInDialogSaveActionPrototype() {
1563        return editInDialogSaveActionPrototype;
1564    }
1565
1566    /**
1567     * {@inheritDoc}
1568     */
1569    @Override
1570    public void setEditInDialogSaveActionPrototype(Action editInDialogSaveActionPrototype) {
1571        this.editInDialogSaveActionPrototype = editInDialogSaveActionPrototype;
1572    }
1573
1574    /**
1575     * {@inheritDoc}
1576     */
1577    public List<DialogGroup> getLineDialogs() {
1578        return lineDialogs;
1579    }
1580
1581    /**
1582     * {@inheritDoc}
1583     */
1584    public void setLineDialogs(List<DialogGroup> dialogGroups) {
1585        this.lineDialogs = dialogGroups;
1586    }
1587}