View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.tabbedpane;
20  
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import javax.faces.component.UIComponent;
25  import javax.faces.component.UIForm;
26  import javax.faces.component.UINamingContainer;
27  import javax.faces.component.html.HtmlPanelGroup;
28  import javax.faces.context.FacesContext;
29  import javax.faces.el.EvaluationException;
30  import javax.faces.el.MethodBinding;
31  import javax.faces.event.AbortProcessingException;
32  import javax.faces.event.FacesEvent;
33  import javax.faces.event.PhaseId;
34  
35  import org.apache.myfaces.component.AlignProperty;
36  import org.apache.myfaces.component.DataProperties;
37  import org.apache.myfaces.component.EventAware;
38  import org.apache.myfaces.component.PanelProperties;
39  import org.apache.myfaces.component.UniversalProperties;
40  import org.apache.myfaces.component.UserRoleAware;
41  
42  /**
43   * TODO: Document this component.
44   * 
45   * Unless otherwise specified, all attributes accept static values or EL expressions.
46   * 
47   * @JSFComponent
48   *   name = "t:panelTabbedPane"
49   *   class = "org.apache.myfaces.custom.tabbedpane.HtmlPanelTabbedPane"
50   *   tagClass = "org.apache.myfaces.custom.tabbedpane.HtmlPanelTabbedPaneTag"
51   *   tagHandler = "org.apache.myfaces.custom.tabbedpane.HtmlPanelTabbedPaneTagHandler"
52   * 
53   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
54   * @version $Revision: 745263 $ $Date: 2009-02-17 16:51:58 -0500 (Tue, 17 Feb 2009) $
55   */
56  public abstract class AbstractHtmlPanelTabbedPane
57          extends HtmlPanelGroup
58          implements UniversalProperties, EventAware, PanelProperties,
59          AlignProperty, DataProperties, UserRoleAware
60          
61  {
62      //private static final Log log = LogFactory.getLog(HtmlPanelTabbedPane.class);
63  
64      public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlPanelTabbedPane";
65      public static final String COMPONENT_FAMILY = "javax.faces.Panel";
66      private static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.TabbedPane";
67      private static final int DEFAULT_SELECTEDINDEX = 0;
68      private static final boolean DEFAULT_SERVER_SIDE_TAB_SWITCH = false;
69  
70      private MethodBinding _tabChangeListener = null;
71      private static final int DEFAULT_BORDER = Integer.MIN_VALUE;
72  
73      public void decode(FacesContext context)
74      {
75          super.decode(context);    //To change body of overridden methods use File | Settings | File Templates.
76      }
77  
78      public void processDecodes(javax.faces.context.FacesContext context)
79     {
80         if (context == null) throw new NullPointerException("context");
81         decode(context);
82  
83         int tabIdx = 0;
84         int selectedIndex = getSelectedIndex();
85  
86         Iterator it = getFacetsAndChildren();
87  
88         while (it.hasNext())
89         {
90             UIComponent childOrFacet = getUIComponent((UIComponent) it.next());
91             if (childOrFacet instanceof HtmlPanelTab) {
92                 if (isClientSide() || selectedIndex == tabIdx) {
93                     childOrFacet.processDecodes(context);
94                 }
95                 tabIdx++;
96             } else {
97                 childOrFacet.processDecodes(context);
98             }
99         }
100    }
101 
102     public void processValidators(FacesContext context)
103     {
104         if (context == null) throw new NullPointerException("context");
105         if (!isRendered()) return;
106 
107         int tabIdx = 0;
108         int selectedIndex = getSelectedIndex();
109 
110         Iterator it = getFacetsAndChildren();
111 
112         while (it.hasNext())
113         {
114             UIComponent childOrFacet = getUIComponent((UIComponent) it.next());
115             if (childOrFacet instanceof HtmlPanelTab) {
116                 if (isClientSide() || selectedIndex == tabIdx) {
117                     childOrFacet.processValidators(context);
118                 }
119                 tabIdx++;
120             } else {
121                 childOrFacet.processValidators(context);
122             }
123         }
124     }
125 
126     public void processUpdates(FacesContext context)
127     {
128         if (context == null) throw new NullPointerException("context");
129         if (!isRendered()) return;
130 
131         int tabIdx = 0;
132         int selectedIndex = getSelectedIndex();
133 
134         Iterator it = getFacetsAndChildren();
135 
136         while (it.hasNext())
137         {
138             UIComponent childOrFacet = getUIComponent((UIComponent) it.next());
139             if (childOrFacet instanceof HtmlPanelTab) {
140                 if (isClientSide() || selectedIndex == tabIdx) {
141                     childOrFacet.processUpdates(context);
142                 }
143                 tabIdx++;
144             } else {
145                 childOrFacet.processUpdates(context);
146             }
147         }
148     }
149 
150     private UIComponent getUIComponent(UIComponent uiComponent)
151     {
152         /*todo: checking for UIForm is not enough - Trinidad form, etc.*/
153         if (uiComponent instanceof UINamingContainer || uiComponent instanceof UIForm)
154         {
155             List children = uiComponent.getChildren();
156             for (int i = 0, len = children.size(); i < len; i++)
157             {
158                 uiComponent = getUIComponent((UIComponent)children.get(i));
159             }
160         }
161         return uiComponent;
162     }
163 
164     public void addTabChangeListener(TabChangeListener listener)
165     {
166         addFacesListener(listener);
167     }
168 
169     public void removeTabChangeListener(TabChangeListener listener)
170     {
171         removeFacesListener(listener);
172     }
173 
174     /**
175      * TODO: This should be something like this:
176      * 
177      * JSFProperty
178      *   returnSignature = "void"
179      *   methodSignature = "org.apache.myfaces.custom.tabbedpane.TabChangeEvent"
180      * 
181      * And be added on tld. But you can do the same with TabChangeListenerTag. 
182      * 
183      * @return
184      */
185     public MethodBinding getTabChangeListener()
186     {
187         return _tabChangeListener;
188     }
189 
190     public void setTabChangeListener(MethodBinding tabChangeListener)
191     {
192         _tabChangeListener = tabChangeListener;
193     }
194     
195     public Object saveState(FacesContext context)
196     {
197         Object values[] = new Object[2];
198         values[0] = super.saveState(context);
199         values[1] = saveAttachedState(context, _tabChangeListener);
200         return values;
201     }
202 
203     public void restoreState(FacesContext context, Object state)
204     {
205         Object values[] = (Object[])state;
206         super.restoreState(context, values[0]);
207         _tabChangeListener = (MethodBinding)restoreAttachedState(context, values[1]);
208     }    
209 
210     public void broadcast(FacesEvent event) throws AbortProcessingException
211     {
212         if (event instanceof TabChangeEvent)
213         {
214             TabChangeEvent tabChangeEvent = (TabChangeEvent)event;
215             if (tabChangeEvent.getComponent() == this)
216             {
217                 setSelectedIndex(tabChangeEvent.getNewTabIndex());
218                 getFacesContext().renderResponse();
219             }
220         }
221         super.broadcast(event);
222 
223         MethodBinding tabChangeListenerBinding = getTabChangeListener();
224         if (tabChangeListenerBinding != null)
225         {
226             try
227             {
228                 tabChangeListenerBinding.invoke(getFacesContext(), new Object[]{event});
229             }
230             catch (EvaluationException e)
231             {
232                 Throwable cause = e.getCause();
233                 if (cause != null && cause instanceof AbortProcessingException)
234                 {
235                     throw (AbortProcessingException)cause;
236                 }
237                 else
238                 {
239                     throw e;
240                 }
241             }
242         }
243     }
244     
245     /**
246      * Write out information about the toggling mode - the component might
247      * be toggled server side or client side.
248      */
249     public boolean isClientSide()
250     {
251         return !isServerSideTabSwitch(); 
252     }
253 
254     /**
255      * @JSFProperty
256      *   tagExcluded = "true"
257      */
258     public abstract String getActiveTabVar();
259     
260     /**
261      * Boolean Variable that is set in request scope when 
262      * rendering a panelTab. True means that the currently 
263      * rendered panelTab is active.
264      * 
265      * @JSFProperty
266      */
267     public abstract Boolean getActivePanelTabVar();
268 
269     /**
270      * Index of tab that is selected by default.
271      * 
272      * @JSFProperty
273      *   defaultValue = "0"
274      */
275     public abstract int getSelectedIndex();
276     
277     public abstract void setSelectedIndex(int selectedIndex);
278 
279     /**
280      * Style class of the active tab cell.
281      * 
282      * @JSFProperty
283      */
284     public abstract String getActiveTabStyleClass();
285 
286     /**
287      * Style class of the inactive tab cells.
288      * 
289      * @JSFProperty
290      */
291     public abstract String getInactiveTabStyleClass();
292 
293     /**
294      * Style class of the active tab sub cell.
295      * 
296      * @JSFProperty
297      */
298     public abstract String getActiveSubStyleClass();
299 
300     /**
301      * Style class of the inactive tab sub cells.
302      * 
303      * @JSFProperty
304      */
305     public abstract String getInactiveSubStyleClass();
306 
307     /**
308      * Style class of the active tab content cell.
309      * 
310      * @JSFProperty
311      */
312     public abstract String getTabContentStyleClass();
313 
314     /**
315      * Style class of the disabled tab cells.
316      * 
317      * @JSFProperty
318      */
319     public abstract String getDisabledTabStyleClass();
320 
321     /**
322      * Toggle client-side/server-side tab switches.
323      * 
324      * @JSFProperty
325      *   defaultValue = "false"
326      */
327     public abstract boolean isServerSideTabSwitch();
328     
329     public boolean getServerSideTabSwitch()
330     {
331         return isServerSideTabSwitch();
332     }
333 
334     /**
335      * Define if the process validation and update model phases
336      * should be executed before change between tabs, when
337      * serverSideTabSwitch = true (if is false, the switch
338      * is done by other way so this property does not have any
339      * effect).
340      * 
341      * Note that if this property is set as false, only a tab 
342      * change is done if all input fields inside the form are valid 
343      * (including input components outside this panel). 
344      * 
345      * By default is true, so both phases are not executed.
346      * 
347      * @JSFProperty
348      *   defaultValue = "true"
349      */    
350     public abstract boolean isImmediateTabChange();
351     
352     public void queueEvent(FacesEvent event)
353     {
354         if (event != null && event instanceof TabChangeEvent)
355         {
356             if (isImmediateTabChange())
357             {
358                 event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
359             }
360             else
361             {
362                 event.setPhaseId(PhaseId.INVOKE_APPLICATION);
363             }
364         }
365         super.queueEvent(event);
366     }
367 }