KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > frontend > templateone > CmsTemplateNavigation


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src-modules/org/opencms/frontend/templateone/CmsTemplateNavigation.java,v $
3  * Date : $Date: 2006/03/27 14:52:51 $
4  * Version: $Revision: 1.31 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.frontend.templateone;
33
34 import org.opencms.file.CmsPropertyDefinition;
35 import org.opencms.file.CmsResource;
36 import org.opencms.i18n.CmsEncoder;
37 import org.opencms.i18n.CmsMessages;
38 import org.opencms.jsp.CmsJspNavElement;
39 import org.opencms.main.CmsException;
40 import org.opencms.main.CmsLog;
41 import org.opencms.main.OpenCms;
42 import org.opencms.util.CmsStringUtil;
43 import org.opencms.xml.content.CmsXmlContent;
44 import org.opencms.xml.types.I_CmsXmlContentValue;
45
46 import java.io.IOException JavaDoc;
47 import java.util.ArrayList JavaDoc;
48 import java.util.HashMap JavaDoc;
49 import java.util.Iterator JavaDoc;
50 import java.util.List JavaDoc;
51 import java.util.Locale JavaDoc;
52 import java.util.Map JavaDoc;
53
54 import javax.servlet.http.HttpServletRequest JavaDoc;
55 import javax.servlet.http.HttpServletResponse JavaDoc;
56 import javax.servlet.jsp.JspException JavaDoc;
57 import javax.servlet.jsp.JspWriter JavaDoc;
58 import javax.servlet.jsp.PageContext JavaDoc;
59
60 import org.apache.commons.logging.Log;
61
62 /**
63  * Provides methods to build the different navigations for the OpenCms template one.<p>
64  *
65  * The navigation methods are used by the included JSP elements of template one.
66  * The inclusion has to be done by passing the Map of request parameters to the included
67  * element. The following request parameters have to be added before inclusion:
68  * <ul>
69  * <li>the current locale</li>
70  * <li>the resource path to the used navigation icons</li>
71  * <li>the start folder to build the navigation from</li>
72  * <li>the head navigation start folder to build the navigation from</li>
73  * <li>the flag to determine if the head navigation menus are enabled</li>
74  * <li>the flag to determine if the left navigation follows the head navigation selection</li>
75  * </ul>
76  *
77  * Remember to set the Flex cache settings of the navigation elements to consider these
78  * request parameters.<p>
79  *
80  * @author Andreas Zahner
81  *
82  * @version $Revision: 1.31 $
83  *
84  * @since 6.0.0
85  */

86 public class CmsTemplateNavigation extends CmsTemplateBase {
87
88     /** Configuration file name for the optional manual head navigation configuration. */
89     public static final String JavaDoc FILE_CONFIG_HEADNAV = "headnav";
90
91     /** Request parameter name for the head navigation start folder. */
92     public static final String JavaDoc PARAM_HEADNAV_FOLDER = "headnavfolder";
93
94     /** Request parameter name for the head navigation flag to use images on 1st level. */
95     public static final String JavaDoc PARAM_HEADNAV_IMAGES = "headnavimages";
96
97     /** Request parameter name for the head navigation flag to mark the current top level folder. */
98     public static final String JavaDoc PARAM_HEADNAV_MARKCURRENT = "headnavmarkcurrent";
99
100     /** Request parameter name for the head navigation flag to manually configure the head navigation. */
101     public static final String JavaDoc PARAM_HEADNAV_MANUAL = "headnavmanual";
102
103     /** Request parameter name for the head navigation flag to expand the submenus on click (true) or mouseover (false). */
104     public static final String JavaDoc PARAM_HEADNAV_MENUCLICK = "headnavmenuclick";
105
106     /** Request parameter name for the head navigation sub menu depth. */
107     public static final String JavaDoc PARAM_HEADNAV_MENUDEPTH = "headnavmenudepth";
108
109     /** Request parameter name for the current locale. */
110     public static final String JavaDoc PARAM_LOCALE = "locale";
111
112     /** Request parameter name for the left navigation editable include element uri. */
113     public static final String JavaDoc PARAM_NAVLEFT_ELEMENTURI = "navleftelementuri";
114
115     /** Request parameter name for the flag if the left navigation should display only the selected resources. */
116     public static final String JavaDoc PARAM_NAVLEFT_SHOWSELECTED = "navleftselected";
117
118     /** Request parameter name for the flag if the left navigation tree should be displayed. */
119     public static final String JavaDoc PARAM_NAVLEFT_SHOWTREE = "navleftshowtree";
120
121     /** Request parameter name for the current resource path. */
122     public static final String JavaDoc PARAM_RESPATH = "respath";
123
124     /** Request parameter name for the flag if the head navigation menus should be shown. */
125     public static final String JavaDoc PARAM_SHOWMENUS = "showmenus";
126
127     /** Request parameter name for the current start folder. */
128     public static final String JavaDoc PARAM_STARTFOLDER = "startfolder";
129
130     /** Name of the property key to determine if the current element is shown in headnav. */
131     public static final String JavaDoc PROPERTY_HEADNAV_USE = "style_head_nav_showitem";
132
133     /** The log object for this class. */
134     private static final Log LOG = CmsLog.getLog(CmsTemplateBean.class);
135
136     /** Stores the global website area configuration. */
137     private CmsXmlContent m_globalConfiguration;
138
139     /** Stores the optional head navigation configuration. */
140     private CmsXmlContent m_headNavConfiguration;
141
142     /** Stores the path to the head navigation start folder. */
143     private String JavaDoc m_headNavFolder;
144
145     /** The default behaviour to include items in head navigation menu if property <code>style_head_nav_showitem</code> is not set. */
146     private boolean m_headNavItemDefaultValue;
147
148     /** Determines if the head navigation menu should be created from a manual configuration file. */
149     private boolean m_headNavManual;
150
151     /** Determines if the currently active top folder should be marked in the head navigation. */
152     private boolean m_headNavMarkCurrent;
153
154     /** Determines if the submenus are expanded on click (true) or mouseover (false). */
155     private boolean m_headNavMenuClick;
156
157     /** Stores the current locale value. */
158     private String JavaDoc m_locale;
159
160     /** The maximum depth of the sub menus in the head navigation. */
161     private int m_menuDepth;
162
163     /** Stores the localized resource Strings. */
164     private CmsMessages m_messages;
165
166     /** Stores the left navigation include element uri. */
167     private String JavaDoc m_navLeftElementUri;
168
169     /** Flag if the left navigation should display only the selected resources. */
170     private boolean m_navLeftShowSelected;
171
172     /** Flag if the left navigation tree should be displayed. */
173     private boolean m_navLeftShowTree;
174
175     /** Stores the substituted path to the modules resources. */
176     private String JavaDoc m_resPath;
177
178     /** Indicates if accessible version is shown. */
179     private boolean m_showAccessibleVersion;
180
181     /** Flag that determines if the head navigation 1st row should use images instead of text links. */
182     private boolean m_showHeadNavImages;
183
184     /** Flag to determine if the DHTML menus (2nd level) of the head navigation should be shown. */
185     private boolean m_showMenus;
186
187     /** Stores the path to the start folder for navigation and search. */
188     private String JavaDoc m_startFolder;
189
190     /**
191      * Empty constructor, required for every JavaBean.<p>
192      */

193     public CmsTemplateNavigation() {
194
195         super();
196     }
197
198     /**
199      * Constructor, with parameters.<p>
200      *
201      * Use this constructor for the template.<p>
202      *
203      * @param context the JSP page context object
204      * @param req the JSP request
205      * @param res the JSP response
206      */

207     public CmsTemplateNavigation(PageContext JavaDoc context, HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res) {
208
209         super();
210         init(context, req, res);
211     }
212
213     /**
214      * Returns the html for the bread crumb navigation above the page content.<p>
215      *
216      * The bread crumb navigation is only displayed if the folder depth of the current
217      * URI is deeper than 3 levels relative to the defined start level.<p>
218      *
219      * @param styleClass the CSS class name to use in the &lt;div&gt; and &lt;a&gt; elements
220      * @return the html for the bread crumb navigation above the page content
221      */

222     public String JavaDoc buildNavigationBreadCrumb(String JavaDoc styleClass) {
223
224         StringBuffer JavaDoc result = new StringBuffer JavaDoc(512);
225         // get start level of the displayed tree
226
int startLevel = 1;
227         if (showNavLeftSelected()) {
228             // follow selection in head navigation
229
startLevel = CmsResource.getPathLevel(getHeadNavFolder());
230         } else {
231             // create default navigation
232
startLevel = CmsResource.getPathLevel(getStartFolder());
233         }
234         // get navigation for requested uri
235
CmsJspNavElement currentPage = getNavigation().getNavigationForResource(getRequestContext().getUri());
236         // get the level of the requested uri
237
int currentLevel = currentPage.getNavTreeLevel();
238         // determine level delta
239
int deltaLevel = currentLevel - startLevel;
240
241         // check if navigation is shown
242
boolean showNavigation = deltaLevel > 3 || (deltaLevel == 3 && currentPage.isInNavigation());
243
244         if (showNavigation) {
245             // create the navigation row
246
String JavaDoc separator = "&gt;";
247             result.append("<div class=\"");
248             result.append(styleClass);
249             result.append("\">");
250             List JavaDoc navElements = getNavigation().getNavigationBreadCrumb(startLevel + 3, true);
251             for (int i = 0; i < navElements.size(); i++) {
252                 CmsJspNavElement nav = (CmsJspNavElement)navElements.get(i);
253                 result.append("<a HREF=\"");
254                 result.append(link(nav.getResourceName()));
255                 result.append("\" class=\"");
256                 result.append(styleClass);
257                 result.append("\" title=\"");
258                 result.append(nav.getNavText());
259                 result.append("\">");
260                 result.append(separator);
261                 result.append("&nbsp;");
262                 result.append(nav.getNavText());
263                 result.append("</a>\n");
264             }
265             if (currentPage.isInNavigation()) {
266                 // show current page in navigation list
267
result.append("<a HREF=\"");
268                 result.append(link(currentPage.getResourceName()));
269                 result.append("\" class=\"");
270                 result.append(styleClass);
271                 result.append("\" title=\"");
272                 result.append(currentPage.getNavText());
273                 result.append("\">");
274                 result.append(separator);
275                 result.append("&nbsp;");
276                 result.append(currentPage.getNavText());
277                 result.append("</a>\n");
278             }
279             result.append("</div>");
280
281         }
282         return result.toString();
283     }
284
285     /**
286      * Returns the html for the head navigation row.<p>
287      *
288      * This method only creates the head row part, be sure to add the
289      * dhtml menu entries by calling the method buildNavigationHeadMenus(java.lang.String).<p>
290      *
291      * @param homeLabel the label of the "home" link
292      * @param styleLink the CSS class name of the link node
293      * @param styleSeparator the CSS class name of the spearator node
294      * @return the html for the head navigation row
295      */

296     public String JavaDoc buildNavigationHead(String JavaDoc homeLabel, String JavaDoc styleLink, String JavaDoc styleSeparator) {
297
298         boolean firstItem = true;
299         StringBuffer JavaDoc result = new StringBuffer JavaDoc(1024);
300         result.append("<div class=\"");
301         result.append(styleLink);
302         result.append("\">\n");
303         result.append("\t<!-- Start Topnavigation -->\n");
304
305         boolean showHomeLink = Boolean.valueOf(getConfigurationValue("headnav.homelink/link.show", CmsStringUtil.TRUE)).booleanValue();
306         if (showHomeLink && !showHeadNavImages()) {
307             // create the "home" link at first position
308
boolean onlyIndex = Boolean.valueOf(
309                 getConfigurationValue("headnav.homelink/link.onlyindex", CmsStringUtil.FALSE)).booleanValue();
310             String JavaDoc url = getStartFolder();
311             String JavaDoc target = "_self";
312             if ((onlyIndex && isDefaultFile(getStartFolder(), getRequestContext().getUri())) || (!onlyIndex)) {
313                 // settings only valid for start page of microsite or for all subpages
314
url = getConfigurationValue("headnav.homelink/link.url", getStartFolder());
315                 homeLabel = getConfigurationValue("headnav.homelink/link.text", homeLabel);
316                 target = getConfigurationValue("headnav.homelink/link.target", "_self");
317             }
318
319             if (url.startsWith("/")) {
320                 // internal link
321
url = link(url);
322             }
323             homeLabel = homeLabel.toUpperCase();
324
325             result.append("<a class=\"");
326             result.append(styleLink);
327             result.append("\" HREF=\"");
328             result.append(url);
329             result.append("\" title=\"");
330             result.append(homeLabel);
331             result.append("\" target=\"");
332             result.append(target);
333             result.append("\">");
334             result.append(homeLabel);
335             result.append("</a>\n");
336             firstItem = false;
337         } else if (showHeadNavImages()) {
338             // create a table to allow vertical alignment of images
339
result.append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>");
340         }
341
342         int count = -1;
343         String JavaDoc showItemProperty;
344
345         // check if head navigation has to be created manually from config file
346
boolean manualHeadConfig = isHeadNavManual();
347
348         List JavaDoc navElements = new ArrayList JavaDoc();
349         if (manualHeadConfig) {
350             // manual configuration, get List of nav items from config file
351
navElements = getHeadNavItemsFromConfig(0, "0");
352         } else {
353             // automatic, get folder navigation
354
navElements = getNavigation().getNavigationForFolder(getHeadNavFolder());
355         }
356         for (int i = 0; i < navElements.size(); i++) {
357             CmsJspNavElement nav = (CmsJspNavElement)navElements.get(i);
358             String JavaDoc link = nav.getResourceName();
359             if (link.startsWith("/")) {
360                 link = link(link);
361             }
362             showItemProperty = getHeadNavItemDefaultStringValue();
363             if (getCmsObject().existsResource(nav.getResourceName())) {
364                 showItemProperty = property(
365                     PROPERTY_HEADNAV_USE,
366                     nav.getResourceName(),
367                     getHeadNavItemDefaultStringValue());
368             } else if (LOG.isWarnEnabled()) {
369                 LOG.warn(Messages.get().getBundle().key(
370                     Messages.LOG_NAVIGATION_CONFIG_ERR_2,
371                     nav.getResourceName(),
372                     getRequestContext().getUri()));
373             }
374             boolean showItem = Boolean.valueOf(showItemProperty).booleanValue();
375             if (manualHeadConfig || (nav.isFolderLink() && showItem)) {
376                 // create an entry for every folder
377
count++;
378                 String JavaDoc navText = CmsEncoder.escapeXml(nav.getNavText().toUpperCase());
379                 String JavaDoc target = nav.getInfo();
380                 if (CmsStringUtil.isEmpty(target)) {
381                     target = "_self";
382                 }
383                 if (showHeadNavImages()) {
384                     // build row with images
385
result.append("<td style= \"vertical-align: middle\">");
386                     result.append("<a");
387                     if (showMenus()) {
388                         result.append(" onmouseover=\"buttonMouseover(event, 'menu");
389                         result.append(count);
390                         result.append("');\"");
391                         if (getHeadNavMenuClick()) {
392                             // only show menus on mouse click
393
result.append(" onclick=\"return buttonClick(event, 'menu");
394                             result.append(count);
395                             result.append("');\"");
396                         }
397                     }
398                     result.append(" title=\"");
399                     result.append(navText);
400                     result.append("\" HREF=\"");
401                     result.append(link);
402                     result.append("\" target=\"");
403                     result.append(target);
404                     result.append("\">");
405                     result.append("<img SRC=\"");
406                     result.append(link(nav.getNavImage()));
407                     result.append("\" border=\"0\" alt=\"");
408                     result.append(navText);
409                     result.append("\">");
410                     result.append("</a></td>\n");
411                 } else {
412                     // build row with text links
413
if (!firstItem) {
414                         result.append("<span class=\"");
415                         result.append(styleSeparator);
416                         result.append("\">|</span>\n");
417                     }
418                     result.append("<a");
419                     if (showMenus()) {
420                         result.append(" onmouseover=\"buttonMouseover(event, 'menu");
421                         result.append(count);
422                         result.append("');\"");
423                         if (getHeadNavMenuClick()) {
424                             // only show menus on mouse click
425
result.append(" onclick=\"return buttonClick(event, 'menu");
426                             result.append(count);
427                             result.append("');\"");
428                         }
429                     }
430                     if (getHeadNavMarkCurrent() && getRequestContext().getUri().startsWith(nav.getResourceName())) {
431                         // mark currently active top folder with bold font
432
result.append(" style=\"font-weight: bold;\"");
433                     }
434                     result.append(" class=\"");
435                     result.append(styleLink);
436                     result.append("\" title=\"");
437                     result.append(navText);
438                     result.append("\" HREF=\"");
439                     result.append(link);
440                     result.append("\" target=\"");
441                     result.append(target);
442                     result.append("\">");
443                     result.append(navText);
444                     result.append("</a>\n");
445                 }
446                 firstItem = false;
447             }
448         }
449
450         if (showHeadNavImages()) {
451             // close table
452
result.append("</tr></table>");
453         }
454
455         result.append("\t<!-- End Topnavigation -->\n");
456         result.append("</div>\n");
457         return result.toString();
458     }
459
460     /**
461      * Returns the html for the head navigation menus.<p>
462      *
463      * This method only creates the menu entries, be sure to
464      * build the head row calling the menus, too.<p>
465      *
466      * @param styleClass the CSS class name of the &lt;div&gt; nodes
467      * @return the html for the head navigation menus
468      */

469     public String JavaDoc buildNavigationHeadMenus(String JavaDoc styleClass) {
470
471         boolean cacheNavEnabled = !getRequestContext().currentProject().isOnlineProject();
472         String JavaDoc cacheKey = null;
473         if (cacheNavEnabled) {
474             // create unique cache key with: site, head nav folder, area folder, menu depth, show submenus flag
475
StringBuffer JavaDoc key = new StringBuffer JavaDoc(8);
476             key.append(getRequestContext().getSiteRoot());
477             key.append("_");
478             key.append(getHeadNavFolder().hashCode());
479             key.append("_");
480             key.append(getStartFolder().hashCode());
481             key.append("_");
482             key.append(getMenuDepth());
483             key.append("_");
484             key.append(showMenus());
485             key.append("_");
486             key.append(showAccessibleVersion());
487             key.append("_");
488             key.append(getLocale());
489             if (isHeadNavManual()) {
490                 // for manual head nav configuration, append config path to cache key
491
key.append("_");
492                 key.append(getConfigPath().hashCode());
493             }
494             cacheKey = key.toString();
495             String JavaDoc cachedNav = CmsTemplateParts.getInstance().getPart(cacheKey);
496             if (CmsStringUtil.isNotEmpty(cachedNav)) {
497                 // found previously cached navigation menu structure, return it
498
return cachedNav;
499             }
500         }
501
502         StringBuffer JavaDoc result = new StringBuffer JavaDoc(4096);
503
504         if (showMenus()) {
505             // only create navigation if the template is configured to show it
506

507             // check if head navigation has to be created manually from config file
508
boolean manualHeadConfig = isHeadNavManual();
509
510             List JavaDoc navElements = new ArrayList JavaDoc();
511             if (manualHeadConfig) {
512                 // manual configuration, get List of nav items from config file
513
navElements = getHeadNavItemsFromConfig(0, "0");
514             } else {
515                 // automatic, get folder navigation
516
navElements = getNavigation().getNavigationForFolder(getHeadNavFolder());
517             }
518
519             int count = -1;
520             String JavaDoc showItemProperty;
521             for (int i = 0; i < navElements.size(); i++) {
522                 CmsJspNavElement foldernav = (CmsJspNavElement)navElements.get(i);
523                 showItemProperty = getHeadNavItemDefaultStringValue();
524                 if (getCmsObject().existsResource(foldernav.getResourceName())) {
525                     showItemProperty = property(
526                         PROPERTY_HEADNAV_USE,
527                         foldernav.getResourceName(),
528                         getHeadNavItemDefaultStringValue());
529                 } else if (LOG.isWarnEnabled()) {
530                     LOG.warn(Messages.get().getBundle().key(
531                         Messages.LOG_NAVIGATION_CONFIG_ERR_2,
532                         foldernav.getResourceName(),
533                         getRequestContext().getUri()));
534                 }
535                 boolean showItem = Boolean.valueOf(showItemProperty).booleanValue();
536                 if (manualHeadConfig || (foldernav.isFolderLink() && showItem)) {
537                     // create a menu entry for every found folder
538
count++;
539                     String JavaDoc subfolder = foldernav.getResourceName();
540
541                     List JavaDoc subNav = new ArrayList JavaDoc();
542                     String JavaDoc menuIndexes = null;
543                     if (manualHeadConfig) {
544                         menuIndexes = String.valueOf(i);
545                         subNav = getHeadNavItemsFromConfig(1, menuIndexes);
546                     } else {
547                         // get all navigation elements of the sub folder
548
subNav = getNavigation().getNavigationForFolder(subfolder);
549                     }
550                     result.append(getMenuNavigation(subNav, styleClass, "menu" + count, 1, menuIndexes));
551                 }
552             }
553
554             if (cacheNavEnabled) {
555                 // cache the generated navigation submenu output
556
CmsTemplateParts.getInstance().addPart(cacheKey, result.toString());
557             }
558         }
559         return result.toString();
560     }
561
562     /**
563      * Returns the html for the left navigation tree.<p>
564      *
565      * @return the html for the left navigation tree
566      */

567     public String JavaDoc buildNavigationLeft() {
568
569         StringBuffer JavaDoc result = new StringBuffer JavaDoc(2048);
570         if (showNavLeftTree()) {
571             // create navigation tree
572
result.append("<!-- Start navigation left -->\n");
573             if (!showAccessibleVersion()) {
574                 result.append("\t<div style=\"line-height: 1px; font-size: 1px; display: block; height: 4px;\">&nbsp;</div>\n");
575             }
576             // get start and end level of the displayed tree
577
int startLevel = 1;
578             if (showNavLeftSelected()) {
579                 // follow selection in head navigation
580
startLevel = CmsResource.getPathLevel(getHeadNavFolder());
581             } else {
582                 // create default navigation
583
startLevel = CmsResource.getPathLevel(getStartFolder());
584             }
585             int endLevel = startLevel + 2;
586
587             // get requested uri
588
String JavaDoc uri = getRequestContext().getUri();
589
590             // get the navigation tree list
591
List JavaDoc navElements = getNavigation().getNavigationTreeForFolder(
592                 getRequestContext().getUri(),
593                 startLevel,
594                 endLevel);
595             int oldLevel = -1;
596             for (int i = 0; i < navElements.size(); i++) {
597                 CmsJspNavElement nav = (CmsJspNavElement)navElements.get(i);
598                 // flag to determine if nav element is shown
599
boolean showElement = true;
600
601                 // get resource name of navelement
602
String JavaDoc resName = nav.getResourceName();
603
604                 // compute current level from 1 to 3
605
int level = nav.getNavTreeLevel() - (startLevel - 1);
606
607                 // check if current navelement is active
608
String JavaDoc styleClass = "navleft";
609                 if (uri.equals(resName) || (nav.isFolderLink() && isDefaultFile(resName, uri))) {
610                     styleClass += "active";
611                 }
612
613                 // check if current element is shown when left navigation follows head menu
614
if (showNavLeftSelected()) {
615                     if (level <= 1 && !uri.startsWith(resName)) {
616                         // do not show element, does not belong to selected area
617
showElement = false;
618                     }
619                 }
620
621                 if (showElement) {
622                     // element is shown
623
if (oldLevel != -1) {
624                         // manage level transitions
625
if (level == oldLevel) {
626                             // same level, close only previous list item
627
result.append("</li>\n");
628                         } else if (level < oldLevel) {
629                             // lower level transition, determine delta
630
int delta = oldLevel - level;
631                             boolean itemClosed = false;
632                             for (int k = 0; k < delta; k++) {
633                                 // close sub list and list item
634
if (!itemClosed) {
635                                     result.append("</li>");
636                                     itemClosed = true;
637                                 }
638                                 result.append("\n</ul></li>\n");
639                             }
640                         } else {
641                             // higher level transition, create new sub list
642
result.append("<ul class=\"navleft\">\n");
643                         }
644                     } else {
645                         // initial list creation
646
result.append("<ul class=\"navleft\">\n");
647                     }
648
649                     // create the navigation entry
650
result.append("<li class=\"");
651                     result.append(styleClass);
652                     result.append("\"><a class=\"");
653                     result.append(styleClass);
654                     result.append("\" HREF=\"");
655                     result.append(link(resName));
656                     result.append("\" title=\"");
657                     result.append(nav.getNavText());
658                     result.append("\">");
659                     result.append(nav.getNavText());
660                     result.append("</a>");
661                     // set old level for next loop
662
oldLevel = level;
663                 }
664             }
665             for (int i = 0; i < oldLevel; i++) {
666                 // close the remaining lists
667
result.append("</li></ul>\n");
668             }
669             result.append("<!-- End navigation left -->");
670         }
671         return result.toString();
672     }
673
674     /**
675      * Builds the html for the inclusion of the editable element under the left navigation tree.<p>
676      *
677      * @throws IOException if writing the output fails
678      * @throws JspException if including the element fails
679      */

680     public void buildNavLeftIncludeElement() throws IOException JavaDoc, JspException JavaDoc {
681
682         JspWriter JavaDoc out = getJspContext().getOut();
683         if (showNavLeftElement()) {
684             out.print("\t<div style=\"line-height: 1px; font-size: 1px; display: block; height: 4px;\">&nbsp;</div>\n");
685             include(getNavLeftElementUri(), "text1", true);
686         } else if (!showNavLeftTree()) {
687             // none of the left navigation elements is shown, add a non breaking space to avoid html display errors
688
out.print("&nbsp;");
689         }
690     }
691
692     /**
693      * Returns the template configuration path in the OpenCms VFS.<p>
694      *
695      * @return the template configuration path
696      */

697     public String JavaDoc getConfigPath() {
698
699         return property(CmsTemplateBean.PROPERTY_CONFIGPATH, "search", "/");
700     }
701
702     /**
703      * Returns the common configuration properties for the current web site area.<p>
704      *
705      * @return the common configuration properties
706      */

707     public CmsXmlContent getConfiguration() {
708
709         if (m_globalConfiguration == null) {
710             m_globalConfiguration = CmsTemplateBean.getConfigurationFile(getConfigPath()
711                 + CmsTemplateBean.FILE_CONFIG_COMMON, getCmsObject());
712         }
713         return m_globalConfiguration;
714     }
715
716     /**
717      * Returns the value for the specified property key name from the configuration.<p>
718      *
719      * Returns the default value argument if the property is not found.<p>
720      *
721      * @param key the property key name to look up
722      * @param defaultValue a default value
723      * @return the value for the specified property key name
724      */

725     public String JavaDoc getConfigurationValue(String JavaDoc key, String JavaDoc defaultValue) {
726
727         String JavaDoc value = null;
728         try {
729             value = getConfiguration().getStringValue(null, key, getRequestContext().getLocale());
730         } catch (Exception JavaDoc e) {
731             // log error in debug mode
732
if (LOG.isDebugEnabled()) {
733                 LOG.debug(e.getMessage(), e);
734             }
735         }
736         if (CmsStringUtil.isEmpty(value)) {
737             value = defaultValue;
738         }
739         return value;
740     }
741
742     /**
743      * Returns the path to the head navigation start folder.<p>
744      *
745      * @return the path to the head navigation start folder
746      */

747     public String JavaDoc getHeadNavFolder() {
748
749         return m_headNavFolder;
750     }
751
752     /**
753      * Creates a List of {@link org.opencms.jsp.CmsJspNavElement} objects from a manual XML content configuration file.<p>
754      *
755      * A manual configuration file can be used to build a head navigation that does not depend
756      * on the OpenCms resource structure. The menu level starts with 0 meaning the current level to create,
757      * the menuIndexes String contains at each char position numbers from 0-9 meaning the xpath index of the submenu
758      * entries in the XML content configuration file.<p>
759      *
760      * To get the first row, call this method like <code>getHeadNavItemsFromConfig(0, "0")</code> ,
761      * to get the subitems for the second entry in the second row <code>getHeadNavItemsFromConfig(1, "1")</code>.<p>
762      *
763      * @param menuLevel the menu level to get the items for, starting with 0
764      * @param menuIndexes the menu indexes of the submenus for xpath creation, starting with "0"
765      * @return a sorted list of CmsJspNavElement objects
766      */

767     public List JavaDoc getHeadNavItemsFromConfig(int menuLevel, String JavaDoc menuIndexes) {
768
769         if (m_headNavConfiguration == null) {
770             // get the XML configuration file
771
m_headNavConfiguration = CmsTemplateBean.getConfigurationFile(
772                 getConfigPath() + FILE_CONFIG_HEADNAV,
773                 getCmsObject());
774         }
775         Locale JavaDoc locale = getRequestContext().getLocale();
776         List JavaDoc navEntries = new ArrayList JavaDoc();
777         if (menuLevel == 0) {
778             // create a list with the first level items from the configuration file as CmsJspNavElements
779
navEntries = m_headNavConfiguration.getValues("link", locale);
780         } else {
781             // create the xpath to the menu items and get the list of values fot the desired menu
782
StringBuffer JavaDoc xPath = new StringBuffer JavaDoc(8);
783             xPath.append("link");
784             for (int i = 0; i < menuLevel; i++) {
785                 // get the index of the current menu entry from the indexes String
786
int menuIndex = Integer.parseInt(String.valueOf(menuIndexes.charAt(i)));
787                 xPath.append("[");
788                 xPath.append(menuIndex + 1);
789                 xPath.append("]/menu");
790
791             }
792             navEntries = m_headNavConfiguration.getValues(xPath.toString(), locale);
793         }
794         int navEntriesSize = navEntries.size();
795         List JavaDoc result = new ArrayList JavaDoc(navEntriesSize);
796         for (int i = 0; i < navEntriesSize; i++) {
797             I_CmsXmlContentValue headLink = (I_CmsXmlContentValue)navEntries.get(i);
798             // get the xpath information of the current link
799
String JavaDoc linkPath = headLink.getPath();
800             // get the link URI
801
String JavaDoc url = m_headNavConfiguration.getStringValue(getCmsObject(), linkPath + "/link.url", locale);
802             // get the link text
803
String JavaDoc text = m_headNavConfiguration.getStringValue(getCmsObject(), linkPath + "/link.text", locale);
804             // get the link target
805
String JavaDoc target = m_headNavConfiguration.getStringValue(getCmsObject(), linkPath + "/link.target", locale);
806             if (CmsStringUtil.isEmpty(target)) {
807                 target = "_self";
808             }
809             // create property Map to pass to the new CmsJspNavElement
810
Map JavaDoc properties = new HashMap JavaDoc(3);
811             properties.put(CmsPropertyDefinition.PROPERTY_NAVTEXT, text);
812             properties.put(CmsPropertyDefinition.PROPERTY_NAVINFO, target);
813             if (showHeadNavImages() && menuLevel == 0) {
814                 // put head navigation image info to Map
815
String JavaDoc image = m_headNavConfiguration.getStringValue(getCmsObject(), linkPath + "/link.image", locale);
816                 if (CmsStringUtil.isEmpty(image)) {
817                     image = "";
818                 }
819                 properties.put(CmsPropertyDefinition.PROPERTY_NAVIMAGE, image);
820             }
821             CmsJspNavElement nav = new CmsJspNavElement(url, properties, 1);
822             result.add(nav);
823         }
824         return result;
825
826     }
827
828     /**
829      * Returns if the currently active top level folder should be marked in the head navigation.<p>
830      *
831      * @return true if the currently active top level folder should be marked in the head navigation, otherwise false
832      */

833     public boolean getHeadNavMarkCurrent() {
834
835         return m_headNavMarkCurrent;
836     }
837
838     /**
839      * Returns if the submenus are expanded on click (true) or mouseover (false).<p>
840      *
841      * @return true if the submenus are expanded on click, otherwise false
842      */

843     public boolean getHeadNavMenuClick() {
844
845         return m_headNavMenuClick;
846     }
847
848     /**
849      * Returns the currently active locale.<p>
850      *
851      * @return the locale
852      */

853     public String JavaDoc getLocale() {
854
855         return m_locale;
856     }
857
858     /**
859      * Returns the maximum depth of the head navigation sub menu structure.<p>
860      *
861      * @return the maximum depth of the head navigation sub menu structure
862      */

863     public int getMenuDepth() {
864
865         return m_menuDepth;
866     }
867
868     /**
869      * This method builds a complete menu navigation with entries of all branches
870      * from the specified folder.<p>
871      *
872      * @param curNav the List of current navigation elements
873      * @param styleClass the CSS class name of the &lt;div&gt; nodes
874      * @param prefix the prefix to generate the unique menu node id.
875      * @param currentDepth the depth of the current submenu
876      * @param menuIndexes String representing the menu indexes in the manual XML configuration, if null, no manual configuration is used
877      * @return the HTML to generate menu entries
878      */

879     public StringBuffer JavaDoc getMenuNavigation(
880         List JavaDoc curNav,
881         String JavaDoc styleClass,
882         String JavaDoc prefix,
883         int currentDepth,
884         String JavaDoc menuIndexes) {
885
886         StringBuffer JavaDoc result = new StringBuffer JavaDoc(64);
887         String JavaDoc showItemProperty;
888
889         int navSize = curNav.size();
890         if (navSize > 0) {
891             // at least one navigation entry present, create menu
892
Map JavaDoc subNav = new HashMap JavaDoc();
893             Map JavaDoc subIndex = new HashMap JavaDoc();
894             boolean entryPresent = false;
895             boolean manualConfig = CmsStringUtil.isNotEmpty(menuIndexes);
896             // loop through all nav entries
897
for (int i = 0; i < navSize; i++) {
898                 CmsJspNavElement ne = (CmsJspNavElement)curNav.get(i);
899                 String JavaDoc resName = ne.getResourceName();
900                 String JavaDoc link = resName;
901                 if (link.startsWith("/")) {
902                     link = link(link);
903                 }
904                 showItemProperty = getHeadNavItemDefaultStringValue();
905                 if (getCmsObject().existsResource(resName)) {
906                     showItemProperty = property(PROPERTY_HEADNAV_USE, resName, getHeadNavItemDefaultStringValue());
907                 } else if (LOG.isWarnEnabled()) {
908                     LOG.warn(Messages.get().getBundle().key(
909                         Messages.LOG_NAVIGATION_CONFIG_ERR_2,
910                         resName,
911                         getRequestContext().getUri()));
912                 }
913                 boolean showEntry = manualConfig || Boolean.valueOf(showItemProperty).booleanValue();
914                 if (showEntry) {
915                     entryPresent = true;
916                     List JavaDoc navEntries = new ArrayList JavaDoc();
917                     // check if is depth smaller than maximum depth -> if so, get the navigation from this folder as well
918
if (currentDepth < getMenuDepth()) {
919                         if (manualConfig) {
920                             // manual configuration, get nav entries from XML configuration file
921
navEntries = getHeadNavItemsFromConfig(currentDepth + 1, menuIndexes + String.valueOf(i));
922                         } else if (ne.isFolderLink()) {
923                             // entry is folder, get sub navigation
924
navEntries = getNavigation().getNavigationForFolder(resName);
925                         }
926
927                     }
928
929                     String JavaDoc target = ne.getInfo();
930                     if (CmsStringUtil.isEmpty(target)) {
931                         target = "_self";
932                     }
933                     result.append(" <a class=\"mI\" HREF=\"");
934                     result.append(link);
935                     result.append("\"");
936                     result.append("\" target=\"");
937                     result.append(target);
938                     result.append("\"");
939                     if ((ne.isFolderLink() && hasSubMenuEntries(navEntries)) || (manualConfig && navEntries.size() > 0)) {
940                         // sub menu(s) present, create special entry
941
result.append(" onmouseover=\"menuItemMouseover(event, '");
942                         result.append(prefix);
943                         result.append("_");
944                         result.append(resName.hashCode());
945                         result.append("');\">");
946                         result.append("<span class=\"mIText\">");
947                         result.append(ne.getNavText());
948                         result.append("</span><span class=\"mIArrow\">&#9654;</span></a>");
949                         // add current entry to temporary Map to create the sub menus
950
subNav.put(resName, navEntries);
951                         if (manualConfig) {
952                             // for manual configuration, additional information for the xpath is needed for the sub menus
953
subIndex.put(resName, menuIndexes + String.valueOf(i));
954                         }
955                     } else {
956                         // no sub menu present, create common menu entry
957
result.append(">");
958                         result.append(ne.getNavText());
959                         result.append("</a>");
960                     }
961                 }
962             }
963             result.append("</div>\n");
964
965             StringBuffer JavaDoc openTag = new StringBuffer JavaDoc(8);
966             if ("menu0".equals(prefix) && showAccessibleVersion()) {
967                 // create div that is displayed for accessible version
968
CmsMessages messages = new CmsMessages(CmsTemplateBean.MESSAGE_BUNDLE, getRequestContext().getLocale());
969                 openTag.append("<div style=\"visibility: hidden; display:none;\">");
970                 openTag.append("<h3>").append(messages.key("headline.accessible.nav.headline")).append("</h3>");
971                 openTag.append("<p>").append(messages.key("headline.accessible.nav.text")).append("</p>");
972                 openTag.append("</div>");
973             }
974             if (entryPresent) {
975                 openTag.append("<div class=\"");
976                 openTag.append(styleClass);
977                 openTag.append("\" id=\"");
978                 openTag.append(prefix);
979                 openTag.append("\" onmouseover=\"menuMouseover(event);\">");
980             } else {
981                 openTag.append("<div style=\"visibility: hidden;\" id=\"");
982                 openTag.append(prefix);
983                 openTag.append("\">");
984             }
985             result.insert(0, openTag);
986
987             // add the sub menus recursively from temporary Map
988
Iterator JavaDoc i = subNav.keySet().iterator();
989             while (i.hasNext()) {
990                 String JavaDoc resName = (String JavaDoc)i.next();
991                 List JavaDoc navEntries = (List JavaDoc)subNav.get(resName);
992                 String JavaDoc newIndex = menuIndexes;
993                 if (manualConfig) {
994                     // get the xpath information to build the submenus from the XML configuration
995
newIndex = (String JavaDoc)subIndex.get(resName);
996                 }
997                 result.append(getMenuNavigation(
998                     navEntries,
999                     styleClass,
1000                    prefix + "_" + resName.hashCode(),
1001                    currentDepth + 1,
1002                    newIndex));
1003            }
1004        }
1005        return result;
1006    }
1007
1008    /**
1009     * Returns the URI of the page element to include on the left navigation.<p>
1010     *
1011     * @return the URI of the page element to include on the left navigation
1012     */

1013    public String JavaDoc getNavLeftElementUri() {
1014
1015        return m_navLeftElementUri;
1016    }
1017
1018    /**
1019     * Returns the substituted path to the modules resource folder.<p>
1020     *
1021     * @return the substituted path to the modules resource folder
1022     */

1023    public String JavaDoc getResourcePath() {
1024
1025        return m_resPath;
1026    }
1027
1028    /**
1029     * Returns the start folder for navigation and search results.<p>
1030     *
1031     * @return the start folder for navigation and search results
1032     */

1033    public String JavaDoc getStartFolder() {
1034
1035        return m_startFolder;
1036    }
1037
1038    /**
1039     * Initialize this bean with the current page context, request and response.<p>
1040     *
1041     * It is required to call one of the init() methods before you can use the
1042     * instance of this bean.
1043     *
1044     * @param context the JSP page context object
1045     * @param req the JSP request
1046     * @param res the JSP response
1047     */

1048    public void init(PageContext JavaDoc context, HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res) {
1049
1050        // call initialization of super class
1051
super.init(context, req, res);
1052        // initialize members from request
1053
m_locale = req.getParameter(PARAM_LOCALE);
1054        if (m_locale == null) {
1055            m_locale = property(CmsPropertyDefinition.PROPERTY_LOCALE, "search", "en").toLowerCase();
1056        }
1057        m_showAccessibleVersion = Boolean.valueOf(req.getParameter(CmsTemplateBean.PARAM_ACCESSIBLE)).booleanValue();
1058        m_headNavFolder = req.getParameter(PARAM_HEADNAV_FOLDER);
1059        m_showHeadNavImages = Boolean.valueOf(req.getParameter(PARAM_HEADNAV_IMAGES)).booleanValue();
1060        m_headNavItemDefaultValue = true;
1061        m_headNavManual = Boolean.valueOf(req.getParameter(PARAM_HEADNAV_MANUAL)).booleanValue();
1062        m_headNavMarkCurrent = Boolean.valueOf(req.getParameter(PARAM_HEADNAV_MARKCURRENT)).booleanValue();
1063        m_headNavMenuClick = Boolean.valueOf(req.getParameter(PARAM_HEADNAV_MENUCLICK)).booleanValue();
1064        try {
1065            m_menuDepth = Integer.parseInt(req.getParameter(PARAM_HEADNAV_MENUDEPTH));
1066        } catch (Exception JavaDoc e) {
1067            m_menuDepth = 2;
1068        }
1069        m_navLeftElementUri = req.getParameter(PARAM_NAVLEFT_ELEMENTURI);
1070        m_navLeftShowSelected = Boolean.valueOf(req.getParameter(PARAM_NAVLEFT_SHOWSELECTED)).booleanValue();
1071        m_navLeftShowTree = Boolean.valueOf(req.getParameter(PARAM_NAVLEFT_SHOWTREE)).booleanValue();
1072        m_resPath = req.getParameter(PARAM_RESPATH);
1073        m_startFolder = req.getParameter(PARAM_STARTFOLDER);
1074        m_showMenus = Boolean.valueOf(req.getParameter(PARAM_SHOWMENUS)).booleanValue();
1075    }
1076
1077    /**
1078     * Gets the localized resource string for a given message key.<p>
1079     *
1080     * If the key was not found in the bundle, the return value is
1081     * <code>"??? " + keyName + " ???"</code>. This will also be returned
1082     * if the bundle was not properly initialized first.
1083     *
1084     * @param keyName the key for the desired string
1085     * @return the resource string for the given key
1086     */

1087    public String JavaDoc key(String JavaDoc keyName) {
1088
1089        return messages().key(keyName);
1090    }
1091
1092    /**
1093     * Returns the initialized CmsMessages object to use on the JSP template.<p>
1094     *
1095     * @return the initialized CmsMessages object
1096     */

1097    public CmsMessages messages() {
1098
1099        if (m_messages == null) {
1100            m_messages = getMessages(CmsTemplateBean.MESSAGE_BUNDLE, getLocale());
1101        }
1102        return m_messages;
1103    }
1104
1105    /**
1106     * Sets the default value of the property <code>style_head_nav_showitem</code> in case the property is not set.<p>
1107     *
1108     * @param defaultValue if true, all resources without property value are included in head menu, if false, vice versa
1109     */

1110    public void setHeadNavItemDefaultValue(boolean defaultValue) {
1111
1112        m_headNavItemDefaultValue = defaultValue;
1113    }
1114
1115    /**
1116     * Returns if the accessible version of the page should be shown.<p>
1117     *
1118     * @return true if the accessible version should be shown, otherwise false
1119     */

1120    public boolean showAccessibleVersion() {
1121
1122        return m_showAccessibleVersion;
1123    }
1124
1125    /**
1126     * Returns if the head navigation should use images for the 1st navigation level.<p>
1127     *
1128     * @return true if the head navigation should use images for the 1st navigation level, otherwise false
1129     */

1130    public boolean showHeadNavImages() {
1131
1132        return m_showHeadNavImages;
1133    }
1134
1135    /**
1136     * Returns if the second level navigation menus of the head navigation should be shown.<p>
1137     *
1138     * @return true if the second level navigation menus of the head navigation should be shown
1139     */

1140    public boolean showMenus() {
1141
1142        return m_showMenus;
1143    }
1144
1145    /**
1146     * Returns true if the left navigation include element should be shown.<p>
1147     *
1148     * @return true if the left navigation include element should be shown
1149     */

1150    public boolean showNavLeftElement() {
1151
1152        return (getNavLeftElementUri() != null && !CmsTemplateBean.PROPERTY_VALUE_NONE.equals(getNavLeftElementUri()));
1153    }
1154
1155    /**
1156     * Returns true if the left navigation follows the selection in the head navigation menu.<p>
1157     *
1158     * @return true if the left navigation follows the selection in the head navigation menu
1159     */

1160    public boolean showNavLeftSelected() {
1161
1162        return m_navLeftShowSelected;
1163    }
1164
1165    /**
1166     * Returns true if the left navigation tree should be displayed.<p>
1167     *
1168     * @return true if the left navigation tree should be displayed
1169     */

1170    public boolean showNavLeftTree() {
1171
1172        return m_navLeftShowTree;
1173    }
1174
1175    /**
1176     * Returns the String representation of the default value for the property <code>style_head_nav_showitem</code>.<p>
1177     *
1178     * @return the String representation of the default value for the property <code>style_head_nav_showitem</code>
1179     */

1180    private String JavaDoc getHeadNavItemDefaultStringValue() {
1181
1182        return "" + m_headNavItemDefaultValue;
1183    }
1184
1185    /**
1186     * Checks if a list of navigation entries contains at least one element which is shown in the head navigation.<p>
1187     *
1188     * @param navEntries the navigation elements to check
1189     * @return true if at least one element of the list should be shown in the head navigation
1190     */

1191    private boolean hasSubMenuEntries(List JavaDoc navEntries) {
1192
1193        for (int i = navEntries.size() - 1; i >= 0; i--) {
1194            CmsJspNavElement nav = (CmsJspNavElement)navEntries.get(i);
1195            String JavaDoc showItemProperty = getHeadNavItemDefaultStringValue();
1196            if (getCmsObject().existsResource(nav.getResourceName())) {
1197                showItemProperty = property(
1198                    PROPERTY_HEADNAV_USE,
1199                    nav.getResourceName(),
1200                    getHeadNavItemDefaultStringValue());
1201            } else if (LOG.isWarnEnabled()) {
1202                LOG.warn(Messages.get().getBundle().key(
1203                    Messages.LOG_NAVIGATION_CONFIG_ERR_2,
1204                    nav.getResourceName(),
1205                    getRequestContext().getUri()));
1206            }
1207            if (Boolean.valueOf(showItemProperty).booleanValue()) {
1208                return true;
1209            }
1210        }
1211        return false;
1212    }
1213
1214    /**
1215     * Determines if the current folder link in the left navigation is the same as the requested uri.<p>
1216     *
1217     * Used to determine if a folder link is marked as "active".<p>
1218     *
1219     * @param navPath the complete path of the current navigation element
1220     * @param fileUri the requested uri
1221     * @return true if the folder link is the same as the requested uri, otherwise false
1222     */

1223    private boolean isDefaultFile(String JavaDoc navPath, String JavaDoc fileUri) {
1224
1225        String JavaDoc folderName = CmsResource.getFolderPath(fileUri);
1226        if (navPath.equals(folderName)) {
1227            String JavaDoc fileName = CmsResource.getName(fileUri);
1228            try {
1229                // check if the "default-file" property was used on the folder
1230
String JavaDoc defaultFileName = getCmsObject().readPropertyObject(
1231                    folderName,
1232                    CmsPropertyDefinition.PROPERTY_DEFAULT_FILE,
1233                    false).getValue();
1234                if (defaultFileName != null && fileName.equals(defaultFileName)) {
1235                    // property was set and the requested file name matches the default file name
1236
return true;
1237                }
1238            } catch (CmsException e) {
1239                // ignore exception, reading property failed
1240
}
1241            List JavaDoc defaultFileNames = OpenCms.getDefaultFiles();
1242            for (int i = 0; i < defaultFileNames.size(); i++) {
1243                String JavaDoc currFileName = (String JavaDoc)defaultFileNames.get(i);
1244                if (fileName.equals(currFileName)) {
1245                    return true;
1246                }
1247            }
1248        }
1249
1250        // current uri does not match
1251
return false;
1252    }
1253
1254    /**
1255     * Returns true if the head navigation is built manually using a XML content configuration file, otherwise false.<p>
1256     *
1257     * @return true if the head navigation is built manually using a XML content configuration file, otherwise false
1258     */

1259    private boolean isHeadNavManual() {
1260
1261        return m_headNavManual;
1262    }
1263}
Popular Tags