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