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