View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.element;
17  
18  import java.io.Serializable;
19  import java.util.List;
20  import java.util.Map;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.kuali.rice.krad.datadictionary.Copyable;
24  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
25  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
26  import org.kuali.rice.krad.uif.container.Container;
27  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
28  import org.kuali.rice.krad.uif.util.ComponentUtils;
29  import org.kuali.rice.krad.uif.util.ContextUtils;
30  import org.kuali.rice.krad.uif.view.View;
31  import org.kuali.rice.krad.util.KRADUtils;
32  import org.kuali.rice.krad.web.form.HistoryFlow;
33  import org.kuali.rice.krad.web.form.UifFormBase;
34  
35  /**
36   * BreadcrumbOptions represents the options for the current view breadcrumbs that are displayed.
37   *
38   * <p>
39   * This class allows
40   * for complete override of all breadcrumbs, and ability to add breadcrumbs before the view and page breadcrumb items.
41   * Important note: breadcrumbOptions for preViewBreadcrumbs, prePageBreadcrumbs, and
42   * breadcrumbOverrides are inherited from the View if not explicitly set from the PageGroup level's breadcrumbOptions
43   * (if they contain a value at the view level and the property is null at the page level - default behavior).
44   * Explicitly providing an empty list or setting these properties at the PageGroup level will
45   * override this inheritance.
46   * </p>
47   */
48  @BeanTag(name = "breadcrumbOptions", parent = "Uif-BreadcrumbOptions")
49  public class BreadcrumbOptions implements Serializable, Copyable {
50      private static final long serialVersionUID = -6705552809624394000L;
51  
52      //custom breadcrumbs
53      private List<BreadcrumbItem> homewardPathBreadcrumbs;
54      private List<BreadcrumbItem> preViewBreadcrumbs;
55      private List<BreadcrumbItem> prePageBreadcrumbs;
56      private List<BreadcrumbItem> breadcrumbOverrides;
57  
58      /**
59       * Sets up the history and breadcrumb configuration for this View.  Should be called from performInitialization.
60       *
61       * @param model the model
62       */
63      public void setupBreadcrumbs(Object model) {
64          View view = ViewLifecycle.getView();
65          
66          if (model != null && model instanceof UifFormBase) {
67              UifFormBase form = (UifFormBase) model;
68  
69              //flow is being tracked if there is a flowKey or the breadcrumbs widget is forcing it
70              boolean usingFlow = StringUtils.isNotBlank(form.getFlowKey()) || (view.getBreadcrumbs() != null && view
71                      .getBreadcrumbs().isUsePathBasedBreadcrumbs());
72  
73              //if using flow setup a new HistoryFlow for this view and set into the HistoryManager
74              if (usingFlow && form.getHistoryManager() != null) {
75  
76                  //use original request form key if present to match history flows stored in map (incase key changed)
77                  String formKey = form.getRequestedFormKey();
78                  if (StringUtils.isBlank(formKey)) {
79                      formKey = form.getFormKey();
80                      form.setRequestedFormKey(formKey);
81                  }
82  
83                  //get the historyFlow for this view
84                  HistoryFlow historyFlow = form.getHistoryManager().process(form.getFlowKey(), formKey,
85                          form.getRequestUrl());
86                  if (historyFlow != null) {
87                      form.setHistoryFlow(historyFlow);
88                      form.setFlowKey(historyFlow.getFlowKey());
89                  }
90              }
91  
92              view.getBreadcrumbs().setUsePathBasedBreadcrumbs(usingFlow);
93  
94              //get the pastItems from the flow and set them so they can be picked up by the Breadcrumbs widget
95              if (view.getBreadcrumbs() != null
96                      && view.getBreadcrumbs().isUsePathBasedBreadcrumbs()
97                      && form.getHistoryFlow() != null
98                      && form.getHistoryFlow().getPastItems() != null) {
99                  List<BreadcrumbItem> pastItems = form.getHistoryFlow().getPastItems();
100                 ComponentUtils.clearAndAssignIds(pastItems);
101                 view.setPathBasedBreadcrumbs(pastItems);
102             }
103         }
104     }
105 
106     /**
107      * Finalize the setup of the BreadcrumbOptions and the BreadcrumbItem for the View.  To be called from the
108      * performFinalize method.
109      *
110      * @param model the model
111      * @param parent parent container
112      * @param breadcrumbItem breadcrumb item to finalize
113      */
114     public void finalizeBreadcrumbs(Object model, Container parent, BreadcrumbItem breadcrumbItem) {
115         View view = ViewLifecycle.getView();
116         
117         //set breadcrumbItem label same as the header, if not set
118         if (StringUtils.isBlank(breadcrumbItem.getLabel()) && view.getHeader() != null && !StringUtils.isBlank(
119                 view.getHeader().getHeaderText()) && model instanceof UifFormBase) {
120             breadcrumbItem.setLabel(KRADUtils.generateUniqueViewTitle((UifFormBase) model, view));
121         }
122 
123         //if label still blank, don't render
124         if (StringUtils.isBlank(breadcrumbItem.getLabel())) {
125             breadcrumbItem.setRender(false);
126         }
127 
128         // set breadcrumb url attributes
129         finalizeBreadcrumbsUrl(model, parent, breadcrumbItem);
130 
131         //explicitly set the page to default for the view breadcrumb when not using path based (path based will pick
132         //up the breadcrumb pageId from the form data automatically)
133         if (breadcrumbItem.getUrl().getPageId() == null && !view.getBreadcrumbs().isUsePathBasedBreadcrumbs()) {
134             //set breadcrumb to default to the default page if an explicit page id for view breadcrumb is not set
135             if (view.getEntryPageId() != null) {
136                 breadcrumbItem.getUrl().setPageId(view.getEntryPageId());
137             } else if (view.isSinglePageView() && view.getPage() != null) {
138                 //single page
139                 breadcrumbItem.getUrl().setPageId(view.getPage().getId());
140             } else if (!view.getItems().isEmpty() && view.getItems().get(0) != null) {
141                 //multi page
142                 breadcrumbItem.getUrl().setPageId(view.getItems().get(0).getId());
143             }
144         }
145 
146         //add to breadcrumbItem to current items if it is set to use in path based
147         if (model instanceof UifFormBase && ((UifFormBase) model).getHistoryFlow() != null) {
148             // clean the breadcrumb item since it will be stored in session
149             ContextUtils.cleanContextDeep(view.getBreadcrumbItem());
150 
151             ((UifFormBase) model).getHistoryFlow().setCurrentViewItem(view.getBreadcrumbItem());
152         }
153     }
154 
155     /**
156      * Finalize the setup of url for the BreadcrumbItem.
157      *
158      * @param model the model
159      * @param parent the parent
160      * @param breadcrumbItem the breadcrumb item
161      */
162     protected void finalizeBreadcrumbsUrl(Object model, Container parent, BreadcrumbItem breadcrumbItem) {
163         //special breadcrumb request param handling
164         if (breadcrumbItem.getUrl().getControllerMapping() == null
165                 && breadcrumbItem.getUrl().getViewId() == null
166                 && model instanceof UifFormBase
167                 && breadcrumbItem.getUrl().getRequestParameters() == null
168                 && ((UifFormBase) model).getInitialRequestParameters() != null) {
169             //add the current request parameters if controllerMapping, viewId, and requestParams are null
170             //(this means that no explicit breadcrumbItem customization was set)
171             Map<String, String[]> requestParameters = ((UifFormBase) model).getInitialRequestParameters();
172 
173             //remove ajax properties because breadcrumb should always be a full view request
174             requestParameters.remove("ajaxReturnType");
175             requestParameters.remove("ajaxRequest");
176 
177             //remove pageId so we can use special handling
178             requestParameters.remove("pageId");
179 
180             breadcrumbItem.getUrl().setRequestParameters(KRADUtils.translateRequestParameterMap(requestParameters));
181         }
182 
183         //form key handling
184         if (breadcrumbItem.getUrl().getFormKey() == null
185                 && model instanceof UifFormBase
186                 && ((UifFormBase) model).getFormKey() != null) {
187             breadcrumbItem.getUrl().setFormKey(((UifFormBase) model).getFormKey());
188         }
189 
190         //automatically set breadcrumbItem UifUrl properties if not set
191         if (breadcrumbItem.getUrl().getControllerMapping() == null && model instanceof UifFormBase) {
192             breadcrumbItem.getUrl().setControllerMapping(((UifFormBase) model).getControllerMapping());
193         }
194 
195         if (breadcrumbItem.getUrl().getViewId() == null) {
196             breadcrumbItem.getUrl().setViewId(ViewLifecycle.getView().getId());
197         }
198     }
199 
200     /**
201      * The homewardPathBreadcrumbs represent the path to "Home" location, these appear before anything else - including
202      * parentLocation/path based breadcrumbs.
203      *
204      * @return the homewardPathBreadcrumbs to render
205      */
206     @BeanTagAttribute(name = "homewardPathBreadcrumbs", type = BeanTagAttribute.AttributeType.LISTBEAN)
207     public List<BreadcrumbItem> getHomewardPathBreadcrumbs() {
208         return homewardPathBreadcrumbs;
209     }
210 
211     /**
212      * Set the homewardPathBreadcrumbs
213      *
214      * @param homewardPathBreadcrumbs
215      */
216     public void setHomewardPathBreadcrumbs(List<BreadcrumbItem> homewardPathBreadcrumbs) {
217         this.homewardPathBreadcrumbs = homewardPathBreadcrumbs;
218     }
219 
220     /**
221      * The preViewBreadcrumbs list represents BreadcrumbItems that will be shown before the View's BreadcrumbItem,
222      * but after any parent location breadcrumbs/path based breadcrumbs (if in use)
223      *
224      * @return the preViewBreadcrumbs to render
225      */
226     @BeanTagAttribute(name = "preViewBreadcrumbs", type = BeanTagAttribute.AttributeType.LISTBEAN)
227     public List<BreadcrumbItem> getPreViewBreadcrumbs() {
228         return preViewBreadcrumbs;
229     }
230 
231     /**
232      * Set the preViewBreadcrumbs
233      *
234      * @param preViewBreadcrumbs
235      */
236     public void setPreViewBreadcrumbs(List<BreadcrumbItem> preViewBreadcrumbs) {
237         this.preViewBreadcrumbs = preViewBreadcrumbs;
238     }
239 
240     /**
241      * The prePageBreadcrumbs list represents BreadcrumbItems that will be shown before the PageGroup's BreadcrumbItem,
242      * but after the View's BreadcrumbItem.
243      *
244      * @return the preViewBreadcrumbs to render
245      */
246     @BeanTagAttribute(name = "prePageBreadcrumbs", type = BeanTagAttribute.AttributeType.LISTBEAN)
247     public List<BreadcrumbItem> getPrePageBreadcrumbs() {
248         return prePageBreadcrumbs;
249     }
250 
251     /**
252      * Set the prePageBreadcrumbs
253      *
254      * @param prePageBreadcrumbs
255      */
256     public void setPrePageBreadcrumbs(List<BreadcrumbItem> prePageBreadcrumbs) {
257         this.prePageBreadcrumbs = prePageBreadcrumbs;
258     }
259 
260     /**
261      * The breadcrumbOverrides are a complete override for all breadcrumbs shown expect for parent location/path
262      * breadcrumbs.
263      *
264      * <p>
265      * The BreadcrumbItems set in this list will be used instead of any View, PageGroup, preViewBreadcrumbs, or
266      * prePageBreadcrumbs BreadcrumbItems already set.  Each item can be customized fully.  If
267      * parent location/path breadcrumbs should also not be shown, set renderParentLocations to false.
268      * All other render options set in BreadcrumbOptions will be ignored/not apply as a result of setting this override
269      * list.
270      * </p>
271      *
272      * @return the breadcrumbOverride list
273      */
274     @BeanTagAttribute(name = "breadcrumbOverrides", type = BeanTagAttribute.AttributeType.LISTBEAN)
275     public List<BreadcrumbItem> getBreadcrumbOverrides() {
276         return breadcrumbOverrides;
277     }
278 
279     /**
280      * Set the breadcrumbOverrides list
281      *
282      * @param breadcrumbOverrides
283      */
284     public void setBreadcrumbOverrides(List<BreadcrumbItem> breadcrumbOverrides) {
285         this.breadcrumbOverrides = breadcrumbOverrides;
286     }
287 
288     /**
289      * @see Copyable#clone()
290      */
291     @Override
292     public BreadcrumbOptions clone() throws CloneNotSupportedException {
293         return (BreadcrumbOptions) super.clone();
294     }
295 
296 }