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