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.portlet.layoutsadmin.util;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.json.JSONArray;
019    import com.liferay.portal.kernel.json.JSONFactoryUtil;
020    import com.liferay.portal.kernel.json.JSONObject;
021    import com.liferay.portal.kernel.staging.LayoutStagingUtil;
022    import com.liferay.portal.kernel.staging.StagingUtil;
023    import com.liferay.portal.kernel.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.ParamUtil;
025    import com.liferay.portal.kernel.util.StringBundler;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.WebKeys;
028    import com.liferay.portal.model.Layout;
029    import com.liferay.portal.model.LayoutBranch;
030    import com.liferay.portal.model.LayoutConstants;
031    import com.liferay.portal.model.LayoutRevision;
032    import com.liferay.portal.model.LayoutSetBranch;
033    import com.liferay.portal.model.User;
034    import com.liferay.portal.model.impl.VirtualLayout;
035    import com.liferay.portal.security.permission.ActionKeys;
036    import com.liferay.portal.service.LayoutLocalServiceUtil;
037    import com.liferay.portal.service.LayoutServiceUtil;
038    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
039    import com.liferay.portal.service.permission.GroupPermissionUtil;
040    import com.liferay.portal.service.permission.LayoutPermissionUtil;
041    import com.liferay.portal.theme.ThemeDisplay;
042    import com.liferay.portal.util.PortalUtil;
043    import com.liferay.portal.util.PropsValues;
044    import com.liferay.portal.util.SessionClicks;
045    import com.liferay.portlet.sites.util.SitesUtil;
046    
047    import java.util.ArrayList;
048    import java.util.Collections;
049    import java.util.Iterator;
050    import java.util.List;
051    
052    import javax.servlet.http.HttpServletRequest;
053    import javax.servlet.http.HttpSession;
054    
055    /**
056     * @author Brian Wing Shun Chan
057     * @author Eduardo Lundgren
058     * @author Bruno Basto
059     * @author Marcellus Tavares
060     * @author Zsolt Szab??
061     * @author Tibor Lipusz
062     */
063    public class LayoutsTreeUtil {
064    
065            public static String getLayoutsJSON(
066                            HttpServletRequest request, long groupId, boolean privateLayout,
067                            long parentLayoutId, boolean incomplete, String treeId)
068                    throws Exception {
069    
070                    return getLayoutsJSON(
071                            request, groupId, privateLayout, parentLayoutId, null, incomplete,
072                            treeId);
073            }
074    
075            public static String getLayoutsJSON(
076                            HttpServletRequest request, long groupId, boolean privateLayout,
077                            long parentLayoutId, long[] expandedLayoutIds, boolean incomplete,
078                            String treeId)
079                    throws Exception {
080    
081                    LayoutTreeNodes layoutTreeNodes = _getLayoutTreeNodes(
082                            request, groupId, privateLayout, parentLayoutId, incomplete,
083                            expandedLayoutIds, treeId);
084    
085                    return _toJSON(request, groupId, layoutTreeNodes);
086            }
087    
088            public static String getLayoutsJSON(
089                            HttpServletRequest request, long groupId, String treeId)
090                    throws Exception {
091    
092                    LayoutTreeNodes layoutTreeNodes = new LayoutTreeNodes();
093    
094                    layoutTreeNodes.addAll(
095                            _getLayoutTreeNodes(
096                                    request, groupId, true,
097                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, false, null, treeId));
098                    layoutTreeNodes.addAll(
099                            _getLayoutTreeNodes(
100                                    request, groupId, false,
101                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, false, null, treeId));
102    
103                    return _toJSON(request, groupId, layoutTreeNodes);
104            }
105    
106            private static List<Layout> _getAncestorLayouts(HttpServletRequest request)
107                    throws Exception {
108    
109                    long selPlid = ParamUtil.getLong(request, "selPlid");
110    
111                    if (selPlid == 0) {
112                            return Collections.emptyList();
113                    }
114    
115                    List<Layout> ancestorLayouts = LayoutServiceUtil.getAncestorLayouts(
116                            selPlid);
117    
118                    Layout layout = LayoutLocalServiceUtil.getLayout(selPlid);
119    
120                    ancestorLayouts.add(layout);
121    
122                    return ancestorLayouts;
123            }
124    
125            private static LayoutTreeNodes _getLayoutTreeNodes(
126                            HttpServletRequest request, long groupId, boolean privateLayout,
127                            long parentLayoutId, boolean incomplete, long[] expandedLayoutIds,
128                            String treeId)
129                    throws Exception {
130    
131                    List<LayoutTreeNode> layoutTreeNodes = new ArrayList<LayoutTreeNode>();
132    
133                    List<Layout> ancestorLayouts = _getAncestorLayouts(request);
134    
135                    List<Layout> layouts = LayoutServiceUtil.getLayouts(
136                            groupId, privateLayout, parentLayoutId, incomplete,
137                            QueryUtil.ALL_POS, QueryUtil.ALL_POS);
138    
139                    for (Layout layout :
140                                    _paginateLayouts(
141                                            request, groupId, privateLayout, parentLayoutId, layouts,
142                                            treeId)) {
143    
144                            LayoutTreeNode layoutTreeNode = new LayoutTreeNode(layout);
145    
146                            LayoutTreeNodes childLayoutTreeNodes = null;
147    
148                            if (_isExpandableLayout(
149                                            request, ancestorLayouts, expandedLayoutIds, layout)) {
150    
151                                    if (layout instanceof VirtualLayout) {
152                                            VirtualLayout virtualLayout = (VirtualLayout)layout;
153    
154                                            childLayoutTreeNodes = _getLayoutTreeNodes(
155                                                    request, virtualLayout.getSourceGroupId(),
156                                                    virtualLayout.isPrivateLayout(),
157                                                    virtualLayout.getLayoutId(), incomplete,
158                                                    expandedLayoutIds, treeId);
159                                    }
160                                    else {
161                                            childLayoutTreeNodes = _getLayoutTreeNodes(
162                                                    request, groupId, layout.isPrivateLayout(),
163                                                    layout.getLayoutId(), incomplete, expandedLayoutIds,
164                                                    treeId);
165                                    }
166                            }
167                            else {
168                                    int childLayoutsCount = LayoutServiceUtil.getLayoutsCount(
169                                            groupId, privateLayout, layout.getLayoutId());
170    
171                                    childLayoutTreeNodes = new LayoutTreeNodes(
172                                            new ArrayList<LayoutTreeNode>(), childLayoutsCount);
173                            }
174    
175                            layoutTreeNode.setChildLayoutTreeNodes(childLayoutTreeNodes);
176    
177                            layoutTreeNodes.add(layoutTreeNode);
178                    }
179    
180                    return new LayoutTreeNodes(layoutTreeNodes, layouts.size());
181            }
182    
183            private static int _getLoadedLayoutsCount(
184                            HttpSession session, long groupId, boolean privateLayout,
185                            long layoutId, String treeId)
186                    throws Exception {
187    
188                    StringBundler sb = new StringBundler(7);
189    
190                    sb.append(treeId);
191                    sb.append(StringPool.COLON);
192                    sb.append(groupId);
193                    sb.append(StringPool.COLON);
194                    sb.append(privateLayout);
195                    sb.append(StringPool.COLON);
196                    sb.append("Pagination");
197    
198                    String paginationJSON = SessionClicks.get(
199                            session, sb.toString(), JSONFactoryUtil.getNullJSON());
200    
201                    JSONObject paginationJSONObject = JSONFactoryUtil.createJSONObject(
202                            paginationJSON);
203    
204                    return paginationJSONObject.getInt(String.valueOf(layoutId), 0);
205            }
206    
207            private static boolean _isExpandableLayout(
208                    HttpServletRequest request, List<Layout> ancestorLayouts,
209                    long[] expandedLayoutIds, Layout layout) {
210    
211                    boolean expandParentLayouts = ParamUtil.getBoolean(
212                            request, "expandParentLayouts");
213    
214                    if (expandParentLayouts || ancestorLayouts.contains(layout) ||
215                            ArrayUtil.contains(expandedLayoutIds, layout.getLayoutId())) {
216    
217                            return true;
218                    }
219    
220                    return false;
221            }
222    
223            private static boolean _isPaginationEnabled(HttpServletRequest request) {
224                    boolean paginate = ParamUtil.getBoolean(request, "paginate", true);
225    
226                    if (paginate &&
227                            (PropsValues.LAYOUT_MANAGE_PAGES_INITIAL_CHILDREN > -1)) {
228    
229                            return true;
230                    }
231    
232                    return false;
233            }
234    
235            private static List<Layout> _paginateLayouts(
236                            HttpServletRequest request, long groupId, boolean privateLayout,
237                            long parentLayoutId, List<Layout> layouts, String treeId)
238                    throws Exception {
239    
240                    if (!_isPaginationEnabled(request)) {
241                            return layouts;
242                    }
243    
244                    HttpSession session = request.getSession();
245    
246                    int loadedLayoutsCount = _getLoadedLayoutsCount(
247                            session, groupId, privateLayout, parentLayoutId, treeId);
248    
249                    int start = ParamUtil.getInteger(request, "start");
250    
251                    start = Math.max(0, Math.min(start, layouts.size()));
252    
253                    int end = ParamUtil.getInteger(
254                            request, "end",
255                            start + PropsValues.LAYOUT_MANAGE_PAGES_INITIAL_CHILDREN);
256    
257                    if (loadedLayoutsCount > end) {
258                            end = loadedLayoutsCount;
259                    }
260    
261                    end = Math.max(start, Math.min(end, layouts.size()));
262    
263                    return layouts.subList(start, end);
264            }
265    
266            private static String _toJSON(
267                            HttpServletRequest request, long groupId,
268                            LayoutTreeNodes layoutTreeNodes)
269                    throws Exception {
270    
271                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
272                            WebKeys.THEME_DISPLAY);
273    
274                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
275    
276                    boolean hasManageLayoutsPermission = GroupPermissionUtil.contains(
277                            themeDisplay.getPermissionChecker(), groupId,
278                            ActionKeys.MANAGE_LAYOUTS);
279    
280                    for (LayoutTreeNode layoutTreeNode : layoutTreeNodes) {
281                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
282    
283                            String childrenJSON = _toJSON(
284                                    request, groupId, layoutTreeNode.getChildLayoutTreeNodes());
285    
286                            jsonObject.put(
287                                    "children", JSONFactoryUtil.createJSONObject(childrenJSON));
288    
289                            Layout layout = layoutTreeNode.getLayout();
290    
291                            jsonObject.put("contentDisplayPage", layout.isContentDisplayPage());
292                            jsonObject.put("friendlyURL", layout.getFriendlyURL());
293    
294                            if (layout instanceof VirtualLayout) {
295                                    VirtualLayout virtualLayout = (VirtualLayout)layout;
296    
297                                    jsonObject.put("groupId", virtualLayout.getSourceGroupId());
298                            }
299                            else {
300                                    jsonObject.put("groupId", layout.getGroupId());
301                            }
302    
303                            jsonObject.put("hasChildren", layout.hasChildren());
304                            jsonObject.put("layoutId", layout.getLayoutId());
305                            jsonObject.put("name", layout.getName(themeDisplay.getLocale()));
306                            jsonObject.put("parentable", PortalUtil.isLayoutParentable(layout));
307                            jsonObject.put("parentLayoutId", layout.getParentLayoutId());
308                            jsonObject.put("plid", layout.getPlid());
309                            jsonObject.put("priority", layout.getPriority());
310                            jsonObject.put("privateLayout", layout.isPrivateLayout());
311                            jsonObject.put(
312                                    "sortable",
313                                            hasManageLayoutsPermission &&
314                                            SitesUtil.isLayoutSortable(layout));
315                            jsonObject.put("type", layout.getType());
316                            jsonObject.put(
317                                    "updateable",
318                                    LayoutPermissionUtil.contains(
319                                            themeDisplay.getPermissionChecker(), layout,
320                                            ActionKeys.UPDATE));
321                            jsonObject.put("uuid", layout.getUuid());
322    
323                            LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
324                                    layout);
325    
326                            if (layoutRevision != null) {
327                                    User user = themeDisplay.getUser();
328    
329                                    long recentLayoutSetBranchId =
330                                            StagingUtil.getRecentLayoutSetBranchId(
331                                                    user, layout.getLayoutSet().getLayoutSetId());
332    
333                                    if (StagingUtil.isIncomplete(layout, recentLayoutSetBranchId)) {
334                                            jsonObject.put("incomplete", true);
335                                    }
336    
337                                    long layoutSetBranchId = layoutRevision.getLayoutSetBranchId();
338    
339                                    LayoutSetBranch layoutSetBranch =
340                                            LayoutSetBranchLocalServiceUtil.getLayoutSetBranch(
341                                                    layoutSetBranchId);
342    
343                                    LayoutBranch layoutBranch = layoutRevision.getLayoutBranch();
344    
345                                    if (!layoutBranch.isMaster()) {
346                                            jsonObject.put(
347                                                    "layoutBranchId", layoutBranch.getLayoutBranchId());
348                                            jsonObject.put("layoutBranchName", layoutBranch.getName());
349                                    }
350    
351                                    if (layoutRevision.isHead()) {
352                                            jsonObject.put("layoutRevisionHead", true);
353                                    }
354    
355                                    jsonObject.put(
356                                            "layoutRevisionId", layoutRevision.getLayoutRevisionId());
357                                    jsonObject.put("layoutSetBranchId", layoutSetBranchId);
358                                    jsonObject.put(
359                                            "layoutSetBranchName", layoutSetBranch.getName());
360                            }
361    
362                            jsonArray.put(jsonObject);
363                    }
364    
365                    JSONObject responseJSONObject = JSONFactoryUtil.createJSONObject();
366    
367                    responseJSONObject.put("layouts", jsonArray);
368                    responseJSONObject.put("total", layoutTreeNodes.getTotal());
369    
370                    return responseJSONObject.toString();
371            }
372    
373            private static class LayoutTreeNode {
374    
375                    public LayoutTreeNode(Layout layout) {
376                            _layout = layout;
377                    }
378    
379                    public Layout getLayout() {
380                            return _layout;
381                    }
382    
383                    public LayoutTreeNodes getChildLayoutTreeNodes() {
384                            return _childLayoutTreeNodes;
385                    }
386    
387                    public void setChildLayoutTreeNodes(
388                            LayoutTreeNodes childLayoutTreeNodes) {
389    
390                            _childLayoutTreeNodes = childLayoutTreeNodes;
391                    }
392    
393                    private LayoutTreeNodes _childLayoutTreeNodes = new LayoutTreeNodes();
394                    private Layout _layout;
395    
396            }
397    
398            private static class LayoutTreeNodes implements Iterable<LayoutTreeNode> {
399    
400                    public LayoutTreeNodes() {
401                    }
402    
403                    public LayoutTreeNodes(
404                            List<LayoutTreeNode> layoutTreeNodesList, int total) {
405    
406                            _layoutTreeNodesList = layoutTreeNodesList;
407                            _total = total;
408                    }
409    
410                    public void addAll(LayoutTreeNodes layoutTreeNodes) {
411                            _layoutTreeNodesList.addAll(
412                                    layoutTreeNodes.getLayoutTreeNodesList());
413    
414                            _total += layoutTreeNodes.getTotal();
415                    }
416    
417                    public int getTotal() {
418                            return _total;
419                    }
420    
421                    public List<LayoutTreeNode> getLayoutTreeNodesList() {
422                            return _layoutTreeNodesList;
423                    }
424    
425                    @Override
426                    public Iterator<LayoutTreeNode> iterator() {
427                            return _layoutTreeNodesList.iterator();
428                    }
429    
430                    private List<LayoutTreeNode> _layoutTreeNodesList =
431                            new ArrayList<LayoutTreeNode>();
432                    private int _total;
433    
434            }
435    
436    }