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