View Javadoc

1   // WARNING: This file was automatically generated. Do not edit it directly,
2   //          or you will lose your changes.
3   
4   /*
5    * Licensed to the Apache Software Foundation (ASF) under one
6    * or more contributor license agreements.  See the NOTICE file
7    * distributed with this work for additional information
8    * regarding copyright ownership.  The ASF licenses this file
9    * to you under the Apache License, Version 2.0 (the
10   * "License"); you may not use this file except in compliance
11   * with the License.  You may obtain a copy of the License at
12   *
13   *   http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing,
16   * software distributed under the License is distributed on an
17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   * KIND, either express or implied.  See the License for the
19   * specific language governing permissions and limitations
20   * under the License.
21  */
22  package org.apache.myfaces.trinidad.component;
23  
24  import java.io.IOException;
25  import java.util.Iterator;
26  import java.util.Map;
27  import javax.el.MethodExpression;
28  import javax.faces.component.UIComponent;
29  import javax.faces.component.visit.VisitCallback;
30  import javax.faces.component.visit.VisitContext;
31  import javax.faces.component.visit.VisitHint;
32  import javax.faces.context.FacesContext;
33  import javax.faces.event.AbortProcessingException;
34  import javax.faces.event.FacesEvent;
35  import javax.faces.event.PhaseId;
36  import org.apache.myfaces.trinidad.bean.FacesBean;
37  import org.apache.myfaces.trinidad.bean.PropertyKey;
38  import org.apache.myfaces.trinidad.event.RowDisclosureListener;
39  import org.apache.myfaces.trinidad.model.CollectionModel;
40  import org.apache.myfaces.trinidad.model.RowKeySet;
41  import org.apache.myfaces.trinidad.model.RowKeySetTreeImpl;
42  import org.apache.myfaces.trinidad.model.TreeModel;
43  import org.apache.myfaces.trinidad.util.ComponentUtils;
44  
45  /**
46   *
47   * <html:p>
48   *           A Page component uses a MenuModel and a stamp to render navigation items.
49   *           </html:p>
50   *
51   * <h4>Events:</h4>
52   * <table border="1" width="100%" cellpadding="3" summary="">
53   * <tr bgcolor="#CCCCFF" class="TableHeadingColor">
54   * <th align="left">Type</th>
55   * <th align="left">Phases</th>
56   * <th align="left">Description</th>
57   * </tr>
58   * <tr class="TableRowColor">
59   * <td valign="top"><code>org.apache.myfaces.trinidad.event.RowDisclosureEvent</code></td>
60   * <td valign="top" nowrap>Apply<br>Request<br>Values<br>Invoke<br>Application</td>
61   * <td valign="top">The expansion event is generated for a table when the detail facet of a row is expanded or collapsed. For tree or a treeTable, the expansion
62                         event is generated when tree nodes are expanded or collapsed.</td>
63   * </tr>
64   * <tr class="TableRowColor">
65   * <td valign="top"><code>org.apache.myfaces.trinidad.event.AttributeChangeEvent</code></td>
66   * <td valign="top" nowrap>Invoke<br>Application<br>Apply<br>Request<br>Values</td>
67   * <td valign="top">Event delivered to describe an attribute change.  Attribute change events are not delivered for any programmatic change to a property.  They are only delivered when a renderer changes a property without the application's specific request.  An example of an attribute change event might include the width of a column that supported client-side resizing.</td>
68   * </tr>
69   * </table>
70   */
71  public class UIXPage extends UIXNavigationHierarchy
72  {
73    static public final FacesBean.Type TYPE = new FacesBean.Type(
74      UIXNavigationHierarchy.TYPE);
75    static public final PropertyKey ROW_DISCLOSURE_LISTENER_KEY =
76      TYPE.registerKey("rowDisclosureListener", MethodExpression.class);
77    static public final PropertyKey DISCLOSED_ROW_KEYS_KEY =
78      TYPE.registerKey("disclosedRowKeys", RowKeySet.class, null, 0, PropertyKey.Mutable.OFTEN);
79    static public final PropertyKey VALUE_KEY =
80      TYPE.registerKey("value", Object.class, null, 0, PropertyKey.Mutable.SOMETIMES);
81    static public final PropertyKey VAR_STATUS_KEY =
82      TYPE.registerKey("varStatus", String.class, PropertyKey.CAP_NOT_BOUND);
83    static public final PropertyKey IMMEDIATE_KEY =
84      TYPE.registerKey("immediate", Boolean.class, Boolean.FALSE);
85    static public final String NODE_STAMP_FACET = "nodeStamp";
86  
87    static public final String COMPONENT_FAMILY =
88      "org.apache.myfaces.trinidad.Page";
89    static public final String COMPONENT_TYPE =
90      "org.apache.myfaces.trinidad.Page";
91  
92    /**
93     * Construct an instance of the UIXPage.
94     */
95    public UIXPage()
96    {
97      super("org.apache.myfaces.trinidad.BasePage");
98    }
99    
100   /**
101    * Sets the phaseID of UI events depending on the "immediate" property.
102    */
103   @Override
104   public void queueEvent(FacesEvent event)
105   {
106     TableUtils.__handleQueueEvent(this, event);
107     super.queueEvent(event);
108   }
109 
110   /**
111    * Delivers an event.
112    * @param event
113    * @throws javax.faces.event.AbortProcessingException
114    */
115   @Override
116   public void broadcast(FacesEvent event) throws AbortProcessingException
117   {
118     HierarchyUtils.__handleBroadcast(this,
119                                       event,
120                                       getDisclosedRowKeys(),
121                                       getRowDisclosureListener());
122     super.broadcast(event);
123   }
124 
125   @Override
126  public CollectionModel createCollectionModel(CollectionModel current, Object value)
127   {
128     TreeModel model = (TreeModel)super.createCollectionModel(current, value);
129     RowKeySet treeState = getDisclosedRowKeys();
130     treeState.setCollectionModel(model);
131     return model;
132   }
133 
134   @Override
135   @SuppressWarnings("unchecked")
136   protected void processFacetsAndChildren(
137     FacesContext context,
138     PhaseId phaseId)
139   {
140     Object oldPath = getRowKey();
141     setRowKey(null);
142 
143     HierarchyUtils.__iterateOverTree(context,
144                                       phaseId,
145                                       this,
146                                       getDisclosedRowKeys(),
147                                       false);
148 
149     setRowKey(oldPath);
150 
151     // process the children
152     TableUtils.__processChildren(context, this, phaseId);
153 
154     Map<String, UIComponent> facets = getFacets();
155     Iterator<String> facetKeys = facets.keySet().iterator();
156 
157     while(facetKeys.hasNext())
158     {
159       String facetKey = facetKeys.next();
160       if (!"nodeStamp".equals(facetKey))
161       {
162         processComponent(context, facets.get(facetKey), phaseId);
163       }
164     }
165   }
166   
167   @Override
168   protected boolean visitChildren(
169     VisitContext  visitContext,
170     VisitCallback callback)
171   {
172     if (ComponentUtils.isSkipIterationVisit(visitContext))
173     {
174       return visitChildrenWithoutIterating(visitContext, callback);
175     }
176     else
177     {
178       return _visitChildrenIterating(visitContext, callback);
179     }
180   }
181   
182   private boolean _visitChildrenIterating(
183     VisitContext  visitContext,
184     VisitCallback callback)
185   {
186     boolean done = visitData(visitContext, callback);
187     
188     if (!done)
189     {
190       // process the children
191       int childCount = getChildCount();
192       if (childCount > 0)
193       {
194         for (UIComponent child : getChildren())
195         {
196           done = UIXComponent.visitTree(visitContext, child, callback);
197           
198           if (done)
199             break;
200         }
201       }
202       
203       // process the non-stamp facet children
204       if (!done)
205       {
206         // Visit the facets except for the node stamp
207         int facetCount = getFacetCount();
208         
209         if (facetCount > 0)
210         {
211           UIComponent nodeStamp = getNodeStamp();
212           
213           // if our only facet is the node stamp, we don't need to do this
214           if ((facetCount > 1) || (nodeStamp == null))
215           {
216             for (UIComponent facet : getFacets().values())
217             {
218               // ignore the nodeStamp facet, since it is stamped
219               if (facet != nodeStamp)
220               {
221                 if (UIXComponent.visitTree(visitContext, facet, callback))
222                 {
223                   done = true;
224                   break;
225                 }
226               }
227             }
228           }
229         }        
230       }
231     }
232     
233     return done;    
234   }
235   
236   @Override
237   protected boolean visitData(
238     VisitContext  visitContext,
239     VisitCallback callback)
240   {
241     Object oldPath = getRowKey();
242 
243     // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
244     // pass in null, indicating that all row keys should be visited
245     RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
246                                    ? getDisclosedRowKeys()
247                                    : null;
248 
249     setRowKey(null);
250 
251     boolean done;
252     
253     try
254     {
255       done = visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
256     }
257     finally
258     {
259       setRowKey(oldPath);
260     }
261     
262     return done;
263   }
264 
265   @Override
266   void __encodeBegin(FacesContext context) throws IOException
267   {
268     HierarchyUtils.__handleEncodeBegin(this, getDisclosedRowKeys());
269     super.__encodeBegin(context);
270   }
271 
272   @Override
273   void __init()
274   {
275     super.__init();
276     if (getDisclosedRowKeys() == null)
277       setDisclosedRowKeys(new RowKeySetTreeImpl());
278   }
279 
280   @Override
281   protected FacesBean createFacesBean(String rendererType)
282   {
283     return new RowKeyFacesBeanWrapper(super.createFacesBean(rendererType));
284   }
285 
286   private class RowKeyFacesBeanWrapper
287     extends FacesBeanWrapper
288   {
289     private boolean _retrievingDisclosedRows = false;
290 
291     RowKeyFacesBeanWrapper(FacesBean bean)
292     {
293       super(bean);
294     }
295 
296     @Override
297     public Object getProperty(PropertyKey key)
298     {
299       Object value = super.getProperty(key);
300 
301       if (key == DISCLOSED_ROW_KEYS_KEY && !_retrievingDisclosedRows && value instanceof RowKeySet)
302       {
303         // Ensure that when we are retrieving and setting the collection model, this property
304         // is not asked for which would create an infinite loop
305         _retrievingDisclosedRows = true;
306 
307         try
308         {
309           RowKeySet rowKeys = (RowKeySet) value;
310           // row key sets need the most recent collection model, but there is no one common entry
311           // point to set this on the set besides when code asks for the value from the bean
312           __flushCachedModel();  //insist that we populate with the very lastest instance of the collection model
313           rowKeys.setCollectionModel(getCollectionModel());
314         }
315         finally
316         {
317           _retrievingDisclosedRows = false;
318         }
319       }
320 
321       return value;
322     }
323 
324     @Override
325     public Object saveState(FacesContext context)
326     {
327       RowKeySet rowKeys = (RowKeySet)super.getProperty(DISCLOSED_ROW_KEYS_KEY);
328       if (rowKeys != null)
329       {
330         // make sure the set does not pin the model in memory
331         rowKeys.setCollectionModel(null);
332       }
333       return super.saveState(context);
334     }
335   }
336 
337   /**
338    * the component to use to stamp each element in the
339    *               menu. A CommandNavigationItem is expected.
340    */
341   final public UIComponent getNodeStamp()
342   {
343     return getFacet(NODE_STAMP_FACET);
344   }
345 
346   /**
347    * the component to use to stamp each element in the
348    *               menu. A CommandNavigationItem is expected.
349    */
350   @SuppressWarnings("unchecked")
351   final public void setNodeStamp(UIComponent nodeStampFacet)
352   {
353     getFacets().put(NODE_STAMP_FACET, nodeStampFacet);
354   }
355 
356   /**
357    * Gets a method reference to an ExpansionListener
358    *
359    * @return  the new rowDisclosureListener value
360    */
361   final public MethodExpression getRowDisclosureListener()
362   {
363     return (MethodExpression)getProperty(ROW_DISCLOSURE_LISTENER_KEY);
364   }
365 
366   /**
367    * Sets a method reference to an ExpansionListener
368    * 
369    * @param rowDisclosureListener  the new rowDisclosureListener value
370    */
371   final public void setRowDisclosureListener(MethodExpression rowDisclosureListener)
372   {
373     setProperty(ROW_DISCLOSURE_LISTENER_KEY, (rowDisclosureListener));
374   }
375 
376   /**
377    * Gets the set of disclosed rows for this component.
378    * Each entry in the set is a rowKey.
379    *
380    * @return  the new disclosedRowKeys value
381    */
382   final public RowKeySet getDisclosedRowKeys()
383   {
384     return (RowKeySet)getProperty(DISCLOSED_ROW_KEYS_KEY);
385   }
386 
387   /**
388    * Sets the set of disclosed rows for this component.
389    * Each entry in the set is a rowKey.
390    * 
391    * @param disclosedRowKeys  the new disclosedRowKeys value
392    */
393   final public void setDisclosedRowKeys(RowKeySet disclosedRowKeys)
394   {
395     setProperty(DISCLOSED_ROW_KEYS_KEY, (disclosedRowKeys));
396   }
397 
398   /**
399    * Gets the hierarchy of menu data - must be of type 
400    *             org.apache.myfaces.trinidad.model.MenuModel
401    *
402    * @return  the new value value
403    */
404   final public Object getValue()
405   {
406     return getProperty(VALUE_KEY);
407   }
408 
409   /**
410    * Sets the hierarchy of menu data - must be of type 
411    *             org.apache.myfaces.trinidad.model.MenuModel
412    * 
413    * @param value  the new value value
414    */
415   final public void setValue(Object value)
416   {
417     setProperty(VALUE_KEY, (value));
418   }
419 
420   /**
421    * Gets <html>
422    *  Name of the EL variable used to reference the varStatus information.
423    *           Once this component has completed rendering, this variable is
424    *           removed (or reverted back to its previous value).
425    *           The VarStatus provides contextual information about the state of the
426    *           component to EL expressions. For components that iterate, varStatus
427    *           also provides loop counter information.  Please see the this 
428    *           component's documentation for the specific properties on the varStatus.
429    *           The common properties on varStatus include:<ul><li>"model" - returns the CollectionModel for this component</li><li>"index" - returns the zero based row index</li></ul></html>
430    *
431    * @return  the new varStatus value
432    */
433   final public String getVarStatus()
434   {
435     return ComponentUtils.resolveString(getProperty(VAR_STATUS_KEY));
436   }
437 
438   /**
439    * Sets <html>
440    *  Name of the EL variable used to reference the varStatus information.
441    *           Once this component has completed rendering, this variable is
442    *           removed (or reverted back to its previous value).
443    *           The VarStatus provides contextual information about the state of the
444    *           component to EL expressions. For components that iterate, varStatus
445    *           also provides loop counter information.  Please see the this 
446    *           component's documentation for the specific properties on the varStatus.
447    *           The common properties on varStatus include:<ul><li>"model" - returns the CollectionModel for this component</li><li>"index" - returns the zero based row index</li></ul></html>
448    * 
449    * @param varStatus  the new varStatus value
450    */
451   final public void setVarStatus(String varStatus)
452   {
453     setProperty(VAR_STATUS_KEY, (varStatus));
454   }
455 
456   /**
457    * Gets whether data validation 
458    *           should be skipped when row disclosure
459    *           events are generated by this component.
460    * 
461    *           When immediate is false (the default), events will
462    *           be delivered during the Invoke Application phase, which
463    *           will trigger validation.  When set to true,  events
464    *           will be executed during the Apply Request Values phase.
465    *
466    * @return  the new immediate value
467    */
468   final public boolean isImmediate()
469   {
470     return ComponentUtils.resolveBoolean(getProperty(IMMEDIATE_KEY), false);
471   }
472 
473   /**
474    * Sets whether data validation 
475    *           should be skipped when row disclosure
476    *           events are generated by this component.
477    * 
478    *           When immediate is false (the default), events will
479    *           be delivered during the Invoke Application phase, which
480    *           will trigger validation.  When set to true,  events
481    *           will be executed during the Apply Request Values phase.
482    * 
483    * @param immediate  the new immediate value
484    */
485   final public void setImmediate(boolean immediate)
486   {
487     setProperty(IMMEDIATE_KEY, immediate ? Boolean.TRUE : Boolean.FALSE);
488   }
489 
490   /**
491    * Adds a rowDisclosure listener.
492    *
493    * @param listener  the rowDisclosure listener to add
494    */
495   final public void addRowDisclosureListener(
496     RowDisclosureListener listener)
497   {
498     addFacesListener(listener);
499   }
500 
501   /**
502    * Removes a rowDisclosure listener.
503    *
504    * @param listener  the rowDisclosure listener to remove
505    */
506   final public void removeRowDisclosureListener(
507     RowDisclosureListener listener)
508   {
509     removeFacesListener(listener);
510   }
511 
512   /**
513    * Returns an array of attached rowDisclosure listeners.
514    *
515    * @return  an array of attached rowDisclosure listeners.
516    */
517   final public RowDisclosureListener[] getRowDisclosureListeners()
518   {
519     return (RowDisclosureListener[])getFacesListeners(RowDisclosureListener.class);
520   }
521 
522   @Override
523   public String getFamily()
524   {
525     return COMPONENT_FAMILY;
526   }
527 
528   @Override
529   protected FacesBean.Type getBeanType()
530   {
531     return TYPE;
532   }
533 
534   /**
535    * Construct an instance of the UIXPage.
536    */
537   protected UIXPage(
538     String rendererType
539     )
540   {
541     super(rendererType);
542   }
543 
544   static
545   {
546     TYPE.lockAndRegister("org.apache.myfaces.trinidad.Page","org.apache.myfaces.trinidad.BasePage");
547   }
548 }