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.component.Attributes;
23  import org.apache.myfaces.tobago.component.UITab;
24  import org.apache.myfaces.tobago.component.Visual;
25  import org.apache.myfaces.tobago.event.TabChangeEvent;
26  import org.apache.myfaces.tobago.event.TabChangeListener;
27  import org.apache.myfaces.tobago.event.TabChangeSource2;
28  import org.apache.myfaces.tobago.model.SwitchType;
29  import org.apache.myfaces.tobago.util.FacesELUtils;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  import javax.el.MethodExpression;
34  import javax.el.ValueExpression;
35  import javax.faces.component.ActionSource2;
36  import javax.faces.component.UIComponent;
37  import javax.faces.component.behavior.ClientBehaviorHolder;
38  import javax.faces.context.FacesContext;
39  import javax.faces.event.AbortProcessingException;
40  import javax.faces.event.ActionListener;
41  import javax.faces.event.FacesEvent;
42  import javax.faces.event.PhaseId;
43  import java.io.IOException;
44  import java.util.ArrayList;
45  import java.util.List;
46  
47  /**
48   * {@link org.apache.myfaces.tobago.internal.taglib.component.TabGroupTagDeclaration}
49   */
50  public abstract class AbstractUITabGroup extends AbstractUIPanelBase
51      implements TabChangeSource2, ActionSource2, ClientBehaviorHolder, 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             }
121           }
122           index++;
123         }
124       }
125 //      final AbstractUIPanelBase renderedTab = getRenderedTab();
126 //      renderedTab.processDecodes(context);
127       for (final UIComponent facet : getFacets().values()) {
128         facet.processDecodes(context);
129       }
130       try {
131         decode(context);
132       } catch (final RuntimeException e) {
133         context.renderResponse();
134         throw e;
135       }
136     } else {
137       super.processDecodes(context);
138     }
139   }
140 
141   @Override
142   public void processValidators(final FacesContext context) {
143     if (!(getSwitchType() == SwitchType.client)) {
144       if (!isRendered()) {
145         return;
146       }
147       final AbstractUITab renderedTab = getRenderedTab();
148       renderedTab.processValidators(context);
149       for (final UIComponent facet : getFacets().values()) {
150         facet.processValidators(context);
151       }
152     } else {
153       super.processValidators(context);
154     }
155   }
156 
157   @Override
158   public void processUpdates(final FacesContext context) {
159     if (!(getSwitchType() == SwitchType.client)) {
160       if (!isRendered()) {
161         return;
162       }
163       final AbstractUITab renderedTab = getRenderedTab();
164       renderedTab.processUpdates(context);
165       for (final UIComponent facet : getFacets().values()) {
166         facet.processUpdates(context);
167       }
168 
169     } else {
170       super.processUpdates(context);
171     }
172   }
173 
174   @Override
175   public void broadcast(final FacesEvent facesEvent) throws AbortProcessingException {
176     super.broadcast(facesEvent);
177     if (facesEvent instanceof TabChangeEvent && facesEvent.getComponent() == this) {
178       final TabChangeEvent event = (TabChangeEvent) facesEvent;
179 
180       final MethodExpression methodExpression = getTabChangeListenerExpression();
181       if (methodExpression != null) {
182         FacesELUtils.invokeMethodExpression(FacesContext.getCurrentInstance(), methodExpression, facesEvent);
183       }
184 
185 // switched off, because this is already called in super.broadcast()
186 //      final ActionListener[] actionListeners = getActionListeners();
187 //      for (ActionListener listener : actionListeners) {
188 //        listener.processAction(event);
189 //      }
190 
191       // XXX is this needed?
192       if (!(getSwitchType() == SwitchType.client)) {
193         final ActionListener defaultActionListener = getFacesContext().getApplication().getActionListener();
194         if (defaultActionListener != null) {
195           defaultActionListener.processAction(event);
196         }
197       }
198       final Integer index = event.getNewTabIndex();
199       final ValueExpression expression = getValueExpression(Attributes.selectedIndex.getName());
200       if (expression != null) {
201         expression.setValue(getFacesContext().getELContext(), index);
202       } else {
203         setSelectedIndex(index);
204       }
205     }
206   }
207 
208   @Override
209   public void addTabChangeListener(final TabChangeListener listener) {
210     if (LOG.isWarnEnabled() && getSwitchType() == SwitchType.client) {
211       LOG.warn("Adding TabChangeListener to client side TabGroup!");
212     }
213     addFacesListener(listener);
214   }
215 
216   @Override
217   public void removeTabChangeListener(final TabChangeListener listener) {
218     removeFacesListener(listener);
219   }
220 
221   @Override
222   public TabChangeListener[] getTabChangeListeners() {
223     return (TabChangeListener[]) getFacesListeners(TabChangeListener.class);
224   }
225 
226   public abstract Integer getRenderedIndex();
227 
228   public abstract void setRenderedIndex(Integer index);
229 
230   public abstract Integer getSelectedIndex();
231 
232   public abstract void setSelectedIndex(Integer index);
233 
234   public abstract SwitchType getSwitchType();
235 
236   private AbstractUITab getTab(final int index) {
237     int i = 0;
238     for (final UIComponent component : getChildren()) {
239       if (component instanceof AbstractUITab) {
240         if (i == index) {
241           return (AbstractUITab) component;
242         }
243         i++;
244       } else {
245         LOG.error("Invalid component in UITabGroup: " + component);
246       }
247     }
248     LOG.error("Found no component with index: " + index + " childCount: " + getChildCount());
249     return null;
250   }
251 
252   private AbstractUITab getRenderedTab() {
253     return getTab(getRenderedIndex());
254   }
255 
256 
257   /**
258    * @since 1.5.0
259    */
260   @Override
261   public void addActionListener(final ActionListener listener) {
262     addFacesListener(listener);
263   }
264 
265   /**
266    * @since 1.5.0
267    */
268   @Override
269   public ActionListener[] getActionListeners() {
270     return (ActionListener[]) getFacesListeners(ActionListener.class);
271   }
272 
273   /**
274    * @since 1.5.0
275    */
276   @Override
277   public void removeActionListener(final ActionListener listener) {
278     removeFacesListener(listener);
279   }
280 }