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