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