001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.taglib.ui;
016    
017    import com.liferay.portal.kernel.language.LanguageUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.servlet.taglib.ui.BreadcrumbEntry;
021    import com.liferay.portal.kernel.util.ArrayUtil;
022    import com.liferay.portal.kernel.util.CookieKeys;
023    import com.liferay.portal.kernel.util.GetterUtil;
024    import com.liferay.portal.kernel.util.HtmlUtil;
025    import com.liferay.portal.kernel.util.HttpUtil;
026    import com.liferay.portal.kernel.util.PropsKeys;
027    import com.liferay.portal.kernel.util.PropsUtil;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.UnicodeProperties;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.kernel.util.WebKeys;
034    import com.liferay.portal.model.Account;
035    import com.liferay.portal.model.Group;
036    import com.liferay.portal.model.GroupConstants;
037    import com.liferay.portal.model.Layout;
038    import com.liferay.portal.model.LayoutConstants;
039    import com.liferay.portal.model.LayoutSet;
040    import com.liferay.portal.model.Organization;
041    import com.liferay.portal.model.User;
042    import com.liferay.portal.service.GroupLocalServiceUtil;
043    import com.liferay.portal.service.LayoutLocalServiceUtil;
044    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
045    import com.liferay.portal.service.OrganizationLocalServiceUtil;
046    import com.liferay.portal.service.UserLocalServiceUtil;
047    import com.liferay.portal.theme.PortletDisplay;
048    import com.liferay.portal.theme.ThemeDisplay;
049    import com.liferay.portal.util.PortalUtil;
050    import com.liferay.taglib.aui.AUIUtil;
051    import com.liferay.taglib.util.IncludeTag;
052    
053    import java.util.List;
054    import java.util.Map;
055    
056    import javax.portlet.PortletURL;
057    
058    import javax.servlet.http.HttpServletRequest;
059    import javax.servlet.http.HttpSession;
060    
061    /**
062     * @author Brian Wing Shun Chan
063     */
064    public class BreadcrumbTag extends IncludeTag {
065    
066            public void setDisplayStyle(String displayStyle) {
067                    _displayStyle = displayStyle;
068            }
069    
070            public void setPortletURL(PortletURL portletURL) {
071                    _portletURL = portletURL;
072            }
073    
074            public void setSelLayout(Layout selLayout) {
075                    _selLayout = selLayout;
076            }
077    
078            public void setSelLayoutParam(String selLayoutParam) {
079                    _selLayoutParam = selLayoutParam;
080            }
081    
082            public void setShowCurrentGroup(boolean showCurrentGroup) {
083                    _showCurrentGroup = showCurrentGroup;
084            }
085    
086            public void setShowCurrentPortlet(boolean showCurrentPortlet) {
087                    _showCurrentPortlet = showCurrentPortlet;
088            }
089    
090            public void setShowGuestGroup(boolean showGuestGroup) {
091                    _showGuestGroup = showGuestGroup;
092            }
093    
094            public void setShowLayout(boolean showLayout) {
095                    _showLayout = showLayout;
096            }
097    
098            public void setShowParentGroups(boolean showParentGroups) {
099                    _showParentGroups = showParentGroups;
100            }
101    
102            public void setShowPortletBreadcrumb(boolean showPortletBreadcrumb) {
103                    _showPortletBreadcrumb = showPortletBreadcrumb;
104            }
105    
106            protected void buildGroupsBreadcrumb(
107                            LayoutSet layoutSet, PortletURL portletURL,
108                            ThemeDisplay themeDisplay, boolean includeParentGroups,
109                            StringBundler sb)
110                    throws Exception {
111    
112                    Group group = layoutSet.getGroup();
113    
114                    if (group.isControlPanel()) {
115                            return;
116                    }
117    
118                    if (includeParentGroups) {
119                            LayoutSet parentLayoutSet = getParentLayoutSet(layoutSet);
120    
121                            if (parentLayoutSet != null) {
122                                    buildGroupsBreadcrumb(
123                                            parentLayoutSet, portletURL, themeDisplay, true, sb);
124                            }
125                    }
126    
127                    int layoutsPageCount = 0;
128    
129                    if (layoutSet.isPrivateLayout()) {
130                            layoutsPageCount = group.getPrivateLayoutsPageCount();
131                    }
132                    else {
133                            layoutsPageCount = group.getPublicLayoutsPageCount();
134                    }
135    
136                    if ((layoutsPageCount > 0) && !group.isGuest()) {
137                            String layoutSetFriendlyURL = PortalUtil.getLayoutSetFriendlyURL(
138                                    layoutSet, themeDisplay);
139    
140                            if (themeDisplay.isAddSessionIdToURL()) {
141                                    layoutSetFriendlyURL = PortalUtil.getURLWithSessionId(
142                                            layoutSetFriendlyURL, themeDisplay.getSessionId());
143                            }
144    
145                            sb.append("<li><a href=\"");
146                            sb.append(layoutSetFriendlyURL);
147                            sb.append("\">");
148                            sb.append(HtmlUtil.escape(group.getDescriptiveName()));
149                            sb.append("</a><span class=\"divider\">/</span></li>");
150                    }
151            }
152    
153            protected void buildGuestGroupBreadcrumb(
154                            ThemeDisplay themeDisplay, StringBundler sb)
155                    throws Exception {
156    
157                    Group group = GroupLocalServiceUtil.getGroup(
158                            themeDisplay.getCompanyId(), GroupConstants.GUEST);
159    
160                    if (group.getPublicLayoutsPageCount() == 0) {
161                            return;
162                    }
163    
164                    sb.append("<li><a href=\"");
165    
166                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
167                            group.getGroupId(), false);
168    
169                    String layoutSetFriendlyURL = PortalUtil.getLayoutSetFriendlyURL(
170                            layoutSet, themeDisplay);
171    
172                    if (themeDisplay.isAddSessionIdToURL()) {
173                            layoutSetFriendlyURL = PortalUtil.getURLWithSessionId(
174                                    layoutSetFriendlyURL, themeDisplay.getSessionId());
175                    }
176    
177                    sb.append(layoutSetFriendlyURL);
178    
179                    sb.append("\">");
180    
181                    Account account = themeDisplay.getAccount();
182    
183                    sb.append(HtmlUtil.escape(account.getName()));
184    
185                    sb.append("</a><span class=\"divider\">/</span></li>");
186            }
187    
188            protected void buildLayoutBreadcrumb(
189                            Layout selLayout, String selLayoutParam, boolean selectedLayout,
190                            PortletURL portletURL, ThemeDisplay themeDisplay, StringBundler sb)
191                    throws Exception {
192    
193                    if (selLayout.getParentLayoutId() !=
194                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
195    
196                            Layout parentLayout = LayoutLocalServiceUtil.getParentLayout(
197                                    selLayout);
198    
199                            buildLayoutBreadcrumb(
200                                    parentLayout, selLayoutParam, false, portletURL, themeDisplay,
201                                    sb);
202                    }
203    
204                    sb.append("<li><a href=\"");
205    
206                    String layoutURL = getBreadcrumbLayoutURL(
207                            selLayout, selLayoutParam, portletURL, themeDisplay);
208    
209                    if (themeDisplay.isAddSessionIdToURL()) {
210                            layoutURL = PortalUtil.getURLWithSessionId(
211                                    layoutURL, themeDisplay.getSessionId());
212                    }
213    
214                    if (selLayout.isTypeControlPanel()) {
215                            layoutURL = HttpUtil.removeParameter(
216                                    layoutURL, "controlPanelCategory");
217                    }
218    
219                    sb.append(layoutURL);
220    
221                    sb.append("\" ");
222    
223                    String layoutName = selLayout.getName(themeDisplay.getLocale());
224    
225                    if (selLayout.isTypeControlPanel()) {
226                            sb.append("target=\"_top\"");
227    
228                            if (layoutName.equals(LayoutConstants.NAME_CONTROL_PANEL_DEFAULT)) {
229                                    layoutName = LanguageUtil.get(
230                                            themeDisplay.getLocale(), "control-panel");
231                            }
232                    }
233                    else {
234                            String target = PortalUtil.getLayoutTarget(selLayout);
235    
236                            sb.append(target);
237                    }
238    
239                    sb.append(StringPool.GREATER_THAN);
240                    sb.append(HtmlUtil.escape(layoutName));
241                    sb.append("</a><span class=\"divider\">/</span></li>");
242            }
243    
244            protected void buildPortletBreadcrumb(
245                            HttpServletRequest request, boolean showCurrentGroup,
246                            boolean showCurrentPortlet, ThemeDisplay themeDisplay,
247                            StringBundler sb)
248                    throws Exception {
249    
250                    List<BreadcrumbEntry> breadcrumbEntries =
251                            PortalUtil.getPortletBreadcrumbs(request);
252    
253                    if (breadcrumbEntries == null) {
254                            return;
255                    }
256    
257                    for (int i = 0; i < breadcrumbEntries.size(); i++) {
258                            BreadcrumbEntry breadcrumbEntry = breadcrumbEntries.get(i);
259    
260                            Map<String, Object> data = breadcrumbEntry.getData();
261    
262                            String breadcrumbTitle = breadcrumbEntry.getTitle();
263                            String breadcrumbURL = breadcrumbEntry.getURL();
264    
265                            if (!showCurrentGroup) {
266                                    String siteGroupName = themeDisplay.getSiteGroupName();
267    
268                                    if (siteGroupName.equals(breadcrumbTitle)) {
269                                            continue;
270                                    }
271                            }
272    
273                            if (!showCurrentPortlet) {
274                                    PortletDisplay portletDisplay =
275                                            themeDisplay.getPortletDisplay();
276    
277                                    String portletTitle = PortalUtil.getPortletTitle(
278                                            portletDisplay.getId(), themeDisplay.getUser());
279    
280                                    if (portletTitle.equals(breadcrumbTitle)) {
281                                            continue;
282                                    }
283                            }
284    
285                            if (!CookieKeys.hasSessionId(request) &&
286                                    Validator.isNotNull(breadcrumbURL)) {
287    
288                                    HttpSession session = request.getSession();
289    
290                                    breadcrumbURL = PortalUtil.getURLWithSessionId(
291                                            breadcrumbURL, session.getId());
292                            }
293    
294                            sb.append("<li>");
295    
296                            if (i < (breadcrumbEntries.size() - 1)) {
297                                    if (Validator.isNotNull(breadcrumbURL)) {
298                                            sb.append("<a href=\"");
299                                            sb.append(HtmlUtil.escape(breadcrumbURL));
300                                            sb.append("\"");
301                                            sb.append(AUIUtil.buildData(data));
302                                            sb.append(">");
303                                    }
304    
305                                    sb.append(HtmlUtil.escape(breadcrumbTitle));
306    
307                                    if (Validator.isNotNull(breadcrumbURL)) {
308                                            sb.append("</a>");
309                                    }
310    
311                                    sb.append("<span class=\"divider\">/</span>");
312                            }
313                            else {
314                                    sb.append(HtmlUtil.escape(breadcrumbTitle));
315                            }
316    
317                            sb.append("</li>");
318                    }
319            }
320    
321            @Override
322            protected void cleanUp() {
323                    _displayStyle = _DISPLAY_STYLE;
324                    _portletURL = null;
325                    _selLayout = null;
326                    _selLayoutParam = null;
327                    _showCurrentGroup = true;
328                    _showCurrentPortlet = true;
329                    _showGuestGroup = _SHOW_GUEST_GROUP;
330                    _showLayout = true;
331                    _showParentGroups = null;
332                    _showPortletBreadcrumb = true;
333            }
334    
335            protected String getBreadcrumbLayoutURL(
336                            Layout selLayout, String selLayoutParam, PortletURL portletURL,
337                            ThemeDisplay themeDisplay)
338                    throws Exception {
339    
340                    if (portletURL == null) {
341                            return PortalUtil.getLayoutFullURL(selLayout, themeDisplay);
342                    }
343    
344                    portletURL.setParameter(
345                            selLayoutParam, String.valueOf(selLayout.getPlid()));
346    
347                    if (selLayout.isTypeControlPanel()) {
348                            if (themeDisplay.getDoAsGroupId() > 0) {
349                                    portletURL.setParameter(
350                                            "doAsGroupId",
351                                            String.valueOf(themeDisplay.getDoAsGroupId()));
352                            }
353    
354                            if (themeDisplay.getRefererPlid() != LayoutConstants.DEFAULT_PLID) {
355                                    portletURL.setParameter(
356                                            "refererPlid",
357                                            String.valueOf(themeDisplay.getRefererPlid()));
358                            }
359                    }
360    
361                    return portletURL.toString();
362            }
363    
364            protected String getBreadcrumbString(HttpServletRequest request) {
365                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
366                            WebKeys.THEME_DISPLAY);
367    
368                    StringBundler sb = new StringBundler();
369    
370                    try {
371                            if (Validator.isNull(_selLayout)) {
372                                    setSelLayout(themeDisplay.getLayout());
373                            }
374    
375                            Group group = _selLayout.getGroup();
376    
377                            if (_showGuestGroup) {
378                                    buildGuestGroupBreadcrumb(themeDisplay, sb);
379                            }
380    
381                            if (_showParentGroups) {
382                                    LayoutSet parentLayoutSet = getParentLayoutSet(
383                                            _selLayout.getLayoutSet());
384    
385                                    if (parentLayoutSet != null) {
386                                            buildGroupsBreadcrumb(
387                                                    parentLayoutSet, _portletURL, themeDisplay, true, sb);
388                                    }
389                            }
390    
391                            if (_showCurrentGroup) {
392                                    buildGroupsBreadcrumb(
393                                            _selLayout.getLayoutSet(), _portletURL, themeDisplay, false,
394                                            sb);
395                            }
396    
397                            if (_showLayout && !group.isLayoutPrototype()) {
398                                    buildLayoutBreadcrumb(
399                                            _selLayout, _selLayoutParam, true, _portletURL,
400                                            themeDisplay, sb);
401                            }
402    
403                            if (_showPortletBreadcrumb) {
404                                    buildPortletBreadcrumb(
405                                            request, _showCurrentGroup, _showCurrentPortlet,
406                                            themeDisplay, sb);
407                            }
408                    }
409                    catch (Exception e) {
410                            _log.error(e, e);
411                    }
412    
413                    String breadcrumbString = sb.toString();
414    
415                    if (Validator.isNull(breadcrumbString)) {
416                            return StringPool.BLANK;
417                    }
418    
419                    String breadcrumbTruncateClass = StringPool.BLANK;
420    
421                    String[] breadcrumbArray = breadcrumbString.split("<li", -1);
422    
423                    boolean breadcrumbTruncate = false;
424    
425                    if (breadcrumbArray.length > 3) {
426                            breadcrumbTruncate = true;
427                    }
428    
429                    if (breadcrumbTruncate) {
430                            breadcrumbTruncateClass = " breadcrumb-truncate";
431                    }
432    
433                    int x = breadcrumbString.indexOf("<li") + 3;
434                    int y = breadcrumbString.lastIndexOf("<li") + 3;
435    
436                    if (x == y) {
437                            breadcrumbString = StringUtil.insert(
438                                    breadcrumbString,
439                                    " class=\"active only" + breadcrumbTruncateClass + "\"", x);
440                    }
441                    else {
442                            breadcrumbString = StringUtil.insert(
443                                    breadcrumbString,
444                                    " class=\"active last" + breadcrumbTruncateClass + "\"", y);
445    
446                            breadcrumbString = StringUtil.insert(
447                                    breadcrumbString,
448                                    " class=\"first" + breadcrumbTruncateClass + "\"", x);
449                    }
450    
451                    if (breadcrumbTruncate) {
452                            y = breadcrumbString.lastIndexOf("<li");
453    
454                            int z = breadcrumbString.lastIndexOf("<li", y - 1) + 3;
455    
456                            breadcrumbString = StringUtil.insert(
457                                    breadcrumbString,
458                                    " class=\"current-parent" + breadcrumbTruncateClass + "\"", z);
459                    }
460    
461                    return breadcrumbString;
462            }
463    
464            @Override
465            protected String getPage() {
466                    return _PAGE;
467            }
468    
469            protected LayoutSet getParentLayoutSet(LayoutSet layoutSet)
470                    throws Exception {
471    
472                    Group group = layoutSet.getGroup();
473    
474                    if (group.isSite()) {
475                            Group parentGroup = group.getParentGroup();
476    
477                            if (parentGroup != null) {
478                                    return LayoutSetLocalServiceUtil.getLayoutSet(
479                                            parentGroup.getGroupId(), layoutSet.isPrivateLayout());
480                            }
481                    }
482                    else if (group.isUser()) {
483                            User user = UserLocalServiceUtil.getUser(group.getClassPK());
484    
485                            List<Organization> organizations =
486                                    OrganizationLocalServiceUtil.getUserOrganizations(
487                                            user.getUserId());
488    
489                            if (!organizations.isEmpty()) {
490                                    Organization organization = organizations.get(0);
491    
492                                    Group parentGroup = organization.getGroup();
493    
494                                    return LayoutSetLocalServiceUtil.getLayoutSet(
495                                            parentGroup.getGroupId(), layoutSet.isPrivateLayout());
496                            }
497                    }
498    
499                    return null;
500            }
501    
502            protected void initShowParentGroups(HttpServletRequest request) {
503                    if (_showParentGroups != null) {
504                            return;
505                    }
506    
507                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
508                            WebKeys.THEME_DISPLAY);
509    
510                    try {
511                            if (Validator.isNull(_selLayout)) {
512                                    setSelLayout(themeDisplay.getLayout());
513                            }
514    
515                            Group group = _selLayout.getGroup();
516    
517                            UnicodeProperties typeSettingsProperties =
518                                    group.getTypeSettingsProperties();
519    
520                            _showParentGroups = GetterUtil.getBoolean(
521                                    typeSettingsProperties.getProperty(
522                                            "breadcrumbShowParentGroups"),
523                                    _SHOW_PARENT_GROUPS);
524                    }
525                    catch (Exception e) {
526                            _log.error(e, e);
527                    }
528            }
529    
530            @Override
531            protected void setAttributes(HttpServletRequest request) {
532                    initShowParentGroups(request);
533    
534                    request.setAttribute(
535                            "liferay-ui:breadcrumb:breadcrumbString",
536                            getBreadcrumbString(request));
537    
538                    String displayStyle = _displayStyle;
539    
540                    if (!ArrayUtil.contains(_DISPLAY_STYLE_OPTIONS, displayStyle)) {
541                            displayStyle = _DISPLAY_STYLE_OPTIONS[0];
542                    }
543    
544                    request.setAttribute(
545                            "liferay-ui:breadcrumb:displayStyle", displayStyle);
546                    request.setAttribute("liferay-ui:breadcrumb:portletURL", _portletURL);
547                    request.setAttribute("liferay-ui:breadcrumb:selLayout", _selLayout);
548                    request.setAttribute(
549                            "liferay-ui:breadcrumb:selLayoutParam", _selLayoutParam);
550                    request.setAttribute(
551                            "liferay-ui:breadcrumb:showCurrentGroup",
552                            String.valueOf(_showCurrentGroup));
553                    request.setAttribute(
554                            "liferay-ui:breadcrumb:showCurrentPortlet",
555                            String.valueOf(_showCurrentPortlet));
556                    request.setAttribute(
557                            "liferay-ui:breadcrumb:showGuestGroup",
558                            String.valueOf(_showGuestGroup));
559                    request.setAttribute(
560                            "liferay-ui:breadcrumb:showLayout", String.valueOf(_showLayout));
561                    request.setAttribute(
562                            "liferay-ui:breadcrumb:showParentGroups",
563                            String.valueOf(_showParentGroups));
564                    request.setAttribute(
565                            "liferay-ui:breadcrumb:showPortletBreadcrumb",
566                            String.valueOf(_showPortletBreadcrumb));
567            }
568    
569            private static final String _DISPLAY_STYLE = GetterUtil.getString(
570                    PropsUtil.get(PropsKeys.BREADCRUMB_DISPLAY_STYLE_DEFAULT));
571    
572            private static final String[] _DISPLAY_STYLE_OPTIONS = PropsUtil.getArray(
573                    PropsKeys.BREADCRUMB_DISPLAY_STYLE_OPTIONS);
574    
575            private static final String _PAGE = "/html/taglib/ui/breadcrumb/page.jsp";
576    
577            private static final boolean _SHOW_GUEST_GROUP = GetterUtil.getBoolean(
578                    PropsUtil.get(PropsKeys.BREADCRUMB_SHOW_GUEST_GROUP));
579    
580            private static final boolean _SHOW_PARENT_GROUPS = GetterUtil.getBoolean(
581                    PropsUtil.get(PropsKeys.BREADCRUMB_SHOW_PARENT_GROUPS));
582    
583            private static Log _log = LogFactoryUtil.getLog(BreadcrumbTag.class);
584    
585            private String _displayStyle = _DISPLAY_STYLE;
586            private PortletURL _portletURL;
587            private Layout _selLayout;
588            private String _selLayoutParam;
589            private boolean _showCurrentGroup = true;
590            private boolean _showCurrentPortlet = true;
591            private boolean _showGuestGroup = _SHOW_GUEST_GROUP;
592            private boolean _showLayout = true;
593            private Boolean _showParentGroups = null;
594            private boolean _showPortletBreadcrumb = true;
595    
596    }