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  
20  package org.apache.myfaces.tobago.internal.component;
21  
22  import org.apache.myfaces.tobago.compat.FacesUtilsEL;
23  import org.apache.myfaces.tobago.component.Attributes;
24  import org.apache.myfaces.tobago.component.Facets;
25  import org.apache.myfaces.tobago.component.OnComponentPopulated;
26  import org.apache.myfaces.tobago.component.SupportsRenderedPartially;
27  import org.apache.myfaces.tobago.component.UITab;
28  import org.apache.myfaces.tobago.component.Visual;
29  import org.apache.myfaces.tobago.event.TabChangeEvent;
30  import org.apache.myfaces.tobago.event.TabChangeListener;
31  import org.apache.myfaces.tobago.event.TabChangeSource2;
32  import org.apache.myfaces.tobago.model.SwitchType;
33  import org.apache.myfaces.tobago.util.ComponentUtils;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  import javax.el.MethodExpression;
38  import javax.el.ValueExpression;
39  import javax.faces.component.ActionSource2;
40  import javax.faces.component.UIComponent;
41  import javax.faces.context.FacesContext;
42  import javax.faces.event.AbortProcessingException;
43  import javax.faces.event.ActionListener;
44  import javax.faces.event.FacesEvent;
45  import javax.faces.event.PhaseId;
46  import java.io.IOException;
47  import java.util.ArrayList;
48  import java.util.List;
49  
50  public abstract class AbstractUITabGroup extends AbstractUIPanel
51      implements TabChangeSource2, ActionSource2, OnComponentPopulated, SupportsRenderedPartially, Visual {
52  
53    private static final Logger LOG = LoggerFactory.getLogger(AbstractUITabGroup.class);
54  
55    @Override
56    public void encodeChildren(final FacesContext facesContext) throws IOException {
57    }
58  
59    @Override
60    public void encodeEnd(final FacesContext facesContext) throws IOException {
61      super.encodeEnd(facesContext);
62      setRenderedIndex(getSelectedIndex());
63    }
64  
65  
66    @Override
67    public boolean getRendersChildren() {
68      return true;
69    }
70  
71    @Override
72    public void queueEvent(final FacesEvent event) {
73      if (this == event.getSource()) {
74        if (isImmediate() || getSwitchType() == SwitchType.client) {
75          // if switch type client event is always immediate
76          event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
77        } else {
78          event.setPhaseId(PhaseId.INVOKE_APPLICATION);
79        }
80      }
81      super.queueEvent(event);
82    }
83  
84    public AbstractUITab[] getTabs() {
85      final List<AbstractUITab> tabs = new ArrayList<AbstractUITab>();
86      for (final UIComponent kid : getChildren()) {
87        if (kid instanceof AbstractUITab) {
88          //if (kid.isRendered()) {
89          tabs.add((AbstractUITab) kid);
90          //}
91        } else {
92          LOG.error("Invalid component in UITabGroup: " + kid);
93        }
94      }
95      return tabs.toArray(new AbstractUITab[tabs.size()]);
96    }
97  
98    public AbstractUITab getActiveTab() {
99      return getTab(getSelectedIndex());
100   }
101 
102 
103   @Override
104   public void processDecodes(final FacesContext context) {
105     if (!(getSwitchType() == SwitchType.client)) {
106 
107       if (context == null) {
108         throw new NullPointerException("context");
109       }
110       if (!isRendered()) {
111         return;
112       }
113       int index = 0;
114       for (final UIComponent child : getChildren()) {
115         if (child instanceof UITab) {
116           final UITab tab = (UITab) child;
117           if (tab.isRendered()) {
118             if (getRenderedIndex() == index) {
119               tab.processDecodes(context);
120             } else {
121               UIComponent facet = ComponentUtils.getFacet(tab, Facets.toolBar);
122               if (facet != null) {
123                 facet.processDecodes(context);
124               }
125             }
126           }
127           index++;
128         }
129       }
130 //      final AbstractUIPanelBase renderedTab = getRenderedTab();
131 //      renderedTab.processDecodes(context);
132       for (final UIComponent facet : getFacets().values()) {
133         facet.processDecodes(context);
134       }
135       try {
136         decode(context);
137       } catch (final RuntimeException e) {
138         context.renderResponse();
139         throw e;
140       }
141     } else {
142       super.processDecodes(context);
143     }
144   }
145 
146   @Override
147   public void processValidators(final FacesContext context) {
148     if (!(getSwitchType() == SwitchType.client)) {
149       if (context == null) {
150         throw new NullPointerException("context");
151       }
152       if (!isRendered()) {
153         return;
154       }
155       final AbstractUITab renderedTab = getRenderedTab();
156       renderedTab.processValidators(context);
157       for (final UIComponent facet : getFacets().values()) {
158         facet.processValidators(context);
159       }
160     } else {
161       super.processValidators(context);
162     }
163   }
164 
165   @Override
166   public void processUpdates(final FacesContext context) {
167     if (!(getSwitchType() == SwitchType.client)) {
168       if (context == null) {
169         throw new NullPointerException("context");
170       }
171       if (!isRendered()) {
172         return;
173       }
174       final AbstractUITab renderedTab = getRenderedTab();
175       renderedTab.processUpdates(context);
176       for (final UIComponent facet : getFacets().values()) {
177         facet.processUpdates(context);
178       }
179 
180     } else {
181       super.processUpdates(context);
182     }
183   }
184 
185   @Override
186   public void broadcast(final FacesEvent facesEvent) throws AbortProcessingException {
187     super.broadcast(facesEvent);
188     if (facesEvent instanceof TabChangeEvent && facesEvent.getComponent() == this) {
189       final TabChangeEvent event = (TabChangeEvent) facesEvent;
190 
191       final MethodExpression methodExpression = getTabChangeListenerExpression();
192       if (methodExpression != null) {
193         FacesUtilsEL.invokeMethodExpression(FacesContext.getCurrentInstance(), methodExpression, facesEvent);
194       }
195 
196 // switched off, because this is already called in super.broadcast()
197 //      final ActionListener[] actionListeners = getActionListeners();
198 //      for (ActionListener listener : actionListeners) {
199 //        listener.processAction(event);
200 //      }
201 
202       // XXX is this needed?
203       if (!(getSwitchType() == SwitchType.client)) {
204         final ActionListener defaultActionListener = getFacesContext().getApplication().getActionListener();
205         if (defaultActionListener != null) {
206           defaultActionListener.processAction(event);
207         }
208       }
209       final Integer index = event.getNewTabIndex();
210       final ValueExpression expression = getValueExpression(Attributes.selectedIndex.getName());
211       if (expression != null) {
212         expression.setValue(getFacesContext().getELContext(), index);
213       } else {
214         setSelectedIndex(index);
215       }
216     }
217   }
218 
219   @Override
220   public void addTabChangeListener(final TabChangeListener listener) {
221     if (LOG.isWarnEnabled() && getSwitchType() == SwitchType.client) {
222       LOG.warn("Adding TabChangeListener to client side TabGroup!");
223     }
224     addFacesListener(listener);
225   }
226 
227   @Override
228   public void removeTabChangeListener(final TabChangeListener listener) {
229     removeFacesListener(listener);
230   }
231 
232   @Override
233   public TabChangeListener[] getTabChangeListeners() {
234     return (TabChangeListener[]) getFacesListeners(TabChangeListener.class);
235   }
236 
237   public abstract Integer getRenderedIndex();
238 
239   public abstract void setRenderedIndex(Integer index);
240 
241   public abstract Integer getSelectedIndex();
242 
243   public abstract void setSelectedIndex(Integer index);
244 
245   public abstract SwitchType getSwitchType();
246 
247   private AbstractUITab getTab(final int index) {
248     int i = 0;
249     for (final UIComponent component : getChildren()) {
250       if (component instanceof AbstractUITab) {
251         if (i == index) {
252           return (AbstractUITab) component;
253         }
254         i++;
255       } else {
256         LOG.error("Invalid component in UITabGroup: " + component);
257       }
258     }
259     LOG.error("Found no component with index: " + index + " childCount: " + getChildCount());
260     return null;
261   }
262 
263   private AbstractUITab getRenderedTab() {
264     return getTab(getRenderedIndex());
265   }
266 
267 
268   /**
269    * @since 1.5.0
270    */
271   @Override
272   public void addActionListener(final ActionListener listener) {
273     addFacesListener(listener);
274   }
275 
276   /**
277    * @since 1.5.0
278    */
279   @Override
280   public ActionListener[] getActionListeners() {
281     return (ActionListener[]) getFacesListeners(ActionListener.class);
282   }
283 
284   /**
285    * @since 1.5.0
286    */
287   @Override
288   public void removeActionListener(final ActionListener listener) {
289     removeFacesListener(listener);
290   }
291 
292   @Override
293   public void onComponentPopulated(final FacesContext facesContext, final UIComponent parent) {
294     super.onComponentPopulated(facesContext, parent);
295   }
296 }