1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
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
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
279
280 public void addActionListener(ActionListener listener) {
281 addFacesListener(listener);
282 }
283
284
285
286
287 public ActionListener[] getActionListeners() {
288 return (ActionListener[]) getFacesListeners(ActionListener.class);
289 }
290
291
292
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 }