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  package org.apache.myfaces.custom.navmenu;
20  
21  import java.util.Iterator;
22  import java.util.StringTokenizer;
23  
24  import javax.el.MethodExpression;
25  import javax.faces.component.ActionSource;
26  import javax.faces.component.UIComponent;
27  import javax.faces.component.UISelectItem;
28  import javax.faces.context.FacesContext;
29  import javax.faces.el.EvaluationException;
30  import javax.faces.el.MethodBinding;
31  import javax.faces.event.AbortProcessingException;
32  import javax.faces.event.ActionEvent;
33  import javax.faces.event.ActionListener;
34  import javax.faces.event.FacesEvent;
35  
36  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
37  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
38  import org.apache.myfaces.component.MethodBindingToMethodExpression;
39  import org.apache.myfaces.component.MethodExpressionToMethodBinding;
40  import org.apache.myfaces.component.UserRoleAware;
41  import org.apache.myfaces.component.UserRoleUtils;
42  import org.apache.myfaces.custom.navmenu.htmlnavmenu.HtmlCommandNavigationItem;
43  import org.apache.myfaces.custom.navmenu.htmlnavmenu.HtmlPanelNavigationMenu;
44  
45  /**
46   * A menu item. Used by navigationMenu, jscookMenu. 
47   * 
48   * Unless otherwise specified, all attributes accept static values or EL expressions.
49   * 
50   * @since 1.1.7
51   * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
52   * @version $Revision: 719425 $ $Date: 2008-11-20 18:41:15 -0500 (Thu, 20 Nov 2008) $
53   */
54  @JSFComponent(
55          name = "t:navigationMenuItem",
56          bodyContent = "JSP",
57          clazz = "org.apache.myfaces.custom.navmenu.UINavigationMenuItem",
58          tagClass = "org.apache.myfaces.custom.navmenu.HtmlNavigationMenuItemTag")
59  public abstract class AbstractUINavigationMenuItem extends UISelectItem implements
60      UserRoleAware, ActionSource {
61      private static final boolean DEFAULT_IMMEDIATE = true;
62  
63      public static final String COMPONENT_TYPE = "org.apache.myfaces.NavigationMenuItem";
64      public static final String COMPONENT_FAMILY = "javax.faces.SelectItem";
65  
66      public AbstractUINavigationMenuItem() {
67          super();
68      }
69  
70      public String getFamily() {
71          return COMPONENT_FAMILY;
72      }
73  
74      /**
75       *  
76       */
77      @JSFProperty
78      public abstract String getIcon();
79  
80      /**
81       * 
82       */
83      @JSFProperty(defaultValue="false")
84      public abstract boolean isSplit();
85  
86      /**
87       * 
88       */
89      @JSFProperty(defaultValue="false",tagExcluded=true)
90      public abstract boolean isOpen();
91      
92      public abstract void setOpen(boolean open);
93  
94      public abstract void setActive(boolean active);
95  
96      /**
97       * 
98       */
99      @JSFProperty(defaultValue="false",tagExcluded=true)
100     public abstract boolean isActive();
101 
102     /**
103      * 
104      */
105     @JSFProperty(defaultValue="true",tagExcluded=true)
106     public abstract boolean isImmediate();
107 
108     /**
109      * 
110      */
111     @JSFProperty(tagExcluded=true)
112     public abstract String getExternalLink();
113 
114     // Action Source    
115     /**
116      * Specifies the action to take when this command is invoked.
117      *
118      * If the value is an expression, it is expected to be a method 
119      * binding EL expression that identifies an action method. An action method
120      * accepts no parameters and has a String return value, called the action
121      * outcome, that identifies the next view displayed. The phase that this
122      * event is fired in can be controlled via the immediate attribute.
123      *
124      * If the value is a string literal, it is treated as a navigation outcome
125      * for the current view.  This is functionally equivalent to a reference to
126      * an action method that returns the string literal.
127      * 
128      */
129     @JSFProperty(
130             stateHolder = true,
131             literalOnly = true,
132             returnSignature = "java.lang.Object",
133             jspName = "action")
134     public abstract MethodExpression getActionExpression();
135     
136     /**
137      * @deprecated Use getActionExpression() instead.
138      */
139     public MethodBinding getAction()
140     {
141         MethodExpression actionExpression = getActionExpression();
142         if (actionExpression instanceof MethodBindingToMethodExpression) {
143             return ((MethodBindingToMethodExpression)actionExpression).getMethodBinding();
144         }
145         if(actionExpression != null)
146         {
147             return new MethodExpressionToMethodBinding(actionExpression);
148         }
149         return null;
150     }
151     
152     public abstract void setActionExpression(MethodExpression actionExpression);
153     
154     /**
155      * @deprecated Use setActionExpression instead.
156      */
157     public void setAction(MethodBinding action)
158     {
159         if(action != null)
160         {
161             setActionExpression(new MethodBindingToMethodExpression(action));
162         } 
163         else
164         {
165             setActionExpression(null);
166         }
167     }
168     
169     
170     public abstract void setActionListener(MethodBinding actionListener);
171 
172     /**
173      * A method binding EL expression that identifies an action listener method
174      * to be invoked if this component is activated by the user. An action
175      * listener method accepts a parameter of type javax.faces.event.ActionEvent
176      * and returns void. The phase that this event is fired in can be controlled
177      * via the immediate attribute.
178      *  
179      */
180     @JSFProperty(
181          stateHolder = true,
182          literalOnly = true,
183          returnSignature="void",
184          methodSignature="javax.faces.event.ActionEvent")
185     public abstract MethodBinding getActionListener();
186 
187     public void addActionListener(ActionListener listener) {
188         addFacesListener(listener);
189     }
190 
191     public ActionListener[] getActionListeners() {
192         return (ActionListener[]) getFacesListeners(ActionListener.class);
193     }
194 
195     public void removeActionListener(ActionListener listener) {
196         removeFacesListener(listener);
197     }
198 
199     // Action Source
200 
201     /**
202      * 
203      */
204     @JSFProperty
205     public abstract String getTarget();
206 
207     /**
208      * When set instead of a Hyperlink a span tag is rendered in 
209      * the corresponding Component
210      *
211      */
212     @JSFProperty(defaultValue="false") 
213     public abstract boolean isDisabled();
214 
215     /**
216      * CSS-Style Attribute to render when disabled is true
217      * 
218      */
219     @JSFProperty
220     public abstract String getDisabledStyle();
221 
222     /**
223      * @see javax.faces.component.UIComponent#broadcast(javax.faces.event.FacesEvent)
224      */
225     public void broadcast(FacesEvent event) throws AbortProcessingException {
226         super.broadcast(event);
227 
228         if (event instanceof ActionEvent) {
229             FacesContext context = getFacesContext();
230 
231             MethodBinding actionListenerBinding = getActionListener();
232             if (actionListenerBinding != null) {
233                 try {
234                     actionListenerBinding.invoke(context,
235                                                  new Object[]{event});
236                 }
237                 catch (EvaluationException e) {
238                     Throwable cause = e.getCause();
239                     if (cause != null
240                         && cause instanceof AbortProcessingException) {
241                         throw (AbortProcessingException) cause;
242                     }
243                     else {
244                         throw e;
245                     }
246                 }
247             }
248 
249             ActionListener defaultActionListener = context.getApplication()
250                 .getActionListener();
251             if (defaultActionListener != null) {
252                 defaultActionListener.processAction((ActionEvent) event);
253             }
254         }
255     }
256 
257     /**
258      * CSS-Style Class to use when disabled is true
259      * 
260      */
261     @JSFProperty
262     public abstract String getDisabledStyleClass();
263 
264     /**
265      * 
266      */
267     @JSFProperty(
268         localMethod= true,
269         tagExcluded = true) 
270     public abstract String getActiveOnViewIds();
271     
272     protected abstract String getLocalActiveOnViewIds();
273     
274     public String getActiveOnViewIdsDirectly() {
275         return getLocalActiveOnViewIds();
276     }
277 
278     /**
279      * A boolean value that indicates whether this component should be rendered.
280      * Default value: true.
281      */
282     @JSFProperty(tagExcluded=false)
283     public boolean isRendered() {
284         if (!UserRoleUtils.isVisibleOnUserRole(this))
285             return false;
286         return super.isRendered();
287     }
288 
289     public void toggleActive(FacesContext context) {
290         StringTokenizer tokenizer = new StringTokenizer(this.getActiveOnViewIdsDirectly(), ";");
291         while (tokenizer.hasMoreTokens()) {
292             String token = tokenizer.nextToken();
293             if (token.trim().equals(context.getViewRoot().getViewId())) {
294                 this.deactivateAll();
295                 this.setActive(true);
296                 openParents();
297             }
298             else {
299                 this.setActive(false);
300             }
301         }
302     }
303 
304     private void openParents() {
305         UIComponent comp = this;
306 
307         while ((comp = comp.getParent()) instanceof AbstractUINavigationMenuItem) {
308             AbstractUINavigationMenuItem parent = (AbstractUINavigationMenuItem) comp;
309             if (!parent.isOpen())
310                 parent.setOpen(true);
311             else
312                 return;
313         }
314     }
315 
316     public void deactivateAll() {
317         UIComponent parent = this.getParent();
318         while (!(parent instanceof HtmlPanelNavigationMenu) && parent != null) {
319             parent = parent.getParent();
320         }
321         if (parent == null) {
322             throw new IllegalStateException("no PanelNavigationMenu!");
323         }
324 
325         HtmlPanelNavigationMenu root = (HtmlPanelNavigationMenu) parent;
326         for (Iterator<UIComponent> it = root.getChildren().iterator(); it.hasNext();) {
327             Object o = it.next();
328             if (o instanceof AbstractUINavigationMenuItem) {
329                 AbstractUINavigationMenuItem navItem = (AbstractUINavigationMenuItem) o;
330                 navItem.setActive(false);
331                 if (navItem.getChildCount() > 0) {
332                     navItem.deactivateChildren();
333                 }
334             }
335             if (o instanceof HtmlCommandNavigationItem) {
336                 HtmlCommandNavigationItem current = (HtmlCommandNavigationItem) o;
337                 current.setActive(false);
338                 if (current.getChildCount() > 0) {
339                     current.deactivateChildren();
340                 }
341             }
342         }
343     }
344 
345     public void deactivateChildren() {
346         for (Iterator<UIComponent> it = this.getChildren().iterator(); it.hasNext();) {
347             Object o = it.next();
348             if (o instanceof AbstractUINavigationMenuItem) {
349                 AbstractUINavigationMenuItem current = (AbstractUINavigationMenuItem) o;
350                 current.setActive(false);
351                 if (current.getChildCount() > 0) {
352                     current.deactivateChildren();
353                 }
354             }
355         }
356     }
357 
358     public Boolean getActiveDirectly() {
359         return Boolean.valueOf(isActive());
360     }
361 }