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.TabChangeSource;
28  import org.apache.myfaces.tobago.event.TobagoActionSource;
29  import org.apache.myfaces.tobago.model.SwitchType;
30  import org.apache.myfaces.tobago.util.FacesELUtils;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import javax.el.MethodExpression;
35  import javax.el.ValueExpression;
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 TabChangeSource, TobagoActionSource, 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<>();
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 = getTab(getRenderedIndex());
148       if (renderedTab != null) {
149         renderedTab.processValidators(context);
150       }
151       for (final UIComponent facet : getFacets().values()) {
152         facet.processValidators(context);
153       }
154     } else {
155       super.processValidators(context);
156     }
157   }
158 
159   @Override
160   public void processUpdates(final FacesContext context) {
161     if (!(getSwitchType() == SwitchType.client)) {
162       if (!isRendered()) {
163         return;
164       }
165       final AbstractUITab renderedTab = getTab(getRenderedIndex());
166       if (renderedTab != null) {
167         renderedTab.processUpdates(context);
168       }
169       for (final UIComponent facet : getFacets().values()) {
170         facet.processUpdates(context);
171       }
172 
173     } else {
174       super.processUpdates(context);
175     }
176   }
177 
178   @Override
179   public void broadcast(final FacesEvent facesEvent) throws AbortProcessingException {
180     super.broadcast(facesEvent);
181     if (facesEvent instanceof TabChangeEvent && facesEvent.getComponent() == this) {
182       final TabChangeEvent event = (TabChangeEvent) facesEvent;
183 
184       final MethodExpression methodExpression = getTabChangeListenerExpression();
185       if (methodExpression != null) {
186         FacesELUtils.invokeMethodExpression(FacesContext.getCurrentInstance(), methodExpression, facesEvent);
187       }
188 
189 // switched off, because this is already called in super.broadcast()
190 //      final ActionListener[] actionListeners = getActionListeners();
191 //      for (ActionListener listener : actionListeners) {
192 //        listener.processAction(event);
193 //      }
194 
195       // XXX is this needed?
196       if (!(getSwitchType() == SwitchType.client)) {
197         final ActionListener defaultActionListener = getFacesContext().getApplication().getActionListener();
198         if (defaultActionListener != null) {
199           defaultActionListener.processAction(event);
200         }
201       }
202       final Integer index = event.getNewTabIndex();
203       final ValueExpression expression = getValueExpression(Attributes.selectedIndex.getName());
204       if (expression != null) {
205         expression.setValue(getFacesContext().getELContext(), index);
206       } else {
207         setSelectedIndex(index);
208       }
209     }
210   }
211 
212   @Override
213   public void addTabChangeListener(final TabChangeListener listener) {
214     if (LOG.isWarnEnabled() && getSwitchType() == SwitchType.client) {
215       LOG.warn("Adding TabChangeListener to client side TabGroup!");
216     }
217     addFacesListener(listener);
218   }
219 
220   @Override
221   public void removeTabChangeListener(final TabChangeListener listener) {
222     removeFacesListener(listener);
223   }
224 
225   @Override
226   public TabChangeListener[] getTabChangeListeners() {
227     return (TabChangeListener[]) getFacesListeners(TabChangeListener.class);
228   }
229 
230   public abstract Integer getRenderedIndex();
231 
232   public abstract void setRenderedIndex(Integer index);
233 
234   public abstract Integer getSelectedIndex();
235 
236   public abstract void setSelectedIndex(Integer index);
237 
238   public abstract SwitchType getSwitchType();
239 
240   private AbstractUITab getTab(final int index) {
241     int i = 0;
242     for (final UIComponent component : getChildren()) {
243       if (component instanceof AbstractUITab) {
244         if (i == index) {
245           return (AbstractUITab) component;
246         }
247         i++;
248       } else {
249         LOG.error("Invalid component in UITabGroup: " + component);
250       }
251     }
252     LOG.error("Found no component with index: " + index + " childCount: " + getChildCount());
253     return null;
254   }
255 
256   /**
257    * @since 1.5.0
258    */
259   @Override
260   public void addActionListener(final ActionListener listener) {
261     addFacesListener(listener);
262   }
263 
264   /**
265    * @since 1.5.0
266    */
267   @Override
268   public ActionListener[] getActionListeners() {
269     return (ActionListener[]) getFacesListeners(ActionListener.class);
270   }
271 
272   /**
273    * @since 1.5.0
274    */
275   @Override
276   public void removeActionListener(final ActionListener listener) {
277     removeFacesListener(listener);
278   }
279 }