001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.exception.SystemException;
019    import com.liferay.portal.kernel.json.JSONArray;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.json.JSONObject;
022    import com.liferay.portal.kernel.staging.LayoutStagingUtil;
023    import com.liferay.portal.kernel.staging.StagingUtil;
024    import com.liferay.portal.kernel.util.ArrayUtil;
025    import com.liferay.portal.kernel.util.ParamUtil;
026    import com.liferay.portal.kernel.util.StringBundler;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.WebKeys;
029    import com.liferay.portal.model.Layout;
030    import com.liferay.portal.model.LayoutBranch;
031    import com.liferay.portal.model.LayoutConstants;
032    import com.liferay.portal.model.LayoutRevision;
033    import com.liferay.portal.model.LayoutSetBranch;
034    import com.liferay.portal.model.User;
035    import com.liferay.portal.model.impl.VirtualLayout;
036    import com.liferay.portal.security.permission.ActionKeys;
037    import com.liferay.portal.service.LayoutLocalServiceUtil;
038    import com.liferay.portal.service.LayoutServiceUtil;
039    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
040    import com.liferay.portal.service.permission.GroupPermissionUtil;
041    import com.liferay.portal.service.permission.LayoutPermissionUtil;
042    import com.liferay.portal.theme.ThemeDisplay;
043    import com.liferay.portal.util.PortalUtil;
044    import com.liferay.portal.util.PropsValues;
045    import com.liferay.portal.util.SessionClicks;
046    import com.liferay.portlet.sites.util.SitesUtil;
047    
048    import java.util.ArrayList;
049    import java.util.Collections;
050    import java.util.Iterator;
051    import java.util.List;
052    import java.util.Locale;
053    
054    import javax.servlet.http.HttpServletRequest;
055    import javax.servlet.http.HttpSession;
056    
057    /**
058     * @author Brian Wing Shun Chan
059     * @author Eduardo Lundgren
060     * @author Bruno Basto
061     * @author Marcellus Tavares
062     * @author Zsolt Szab??
063     * @author Tibor Lipusz
064     */
065    public class LayoutsTreeUtil {
066    
067            public static String getLayoutsJSON(
068                            HttpServletRequest request, long groupId, boolean privateLayout,
069                            long parentLayoutId, boolean incomplete, String treeId)
070                    throws Exception {
071    
072                    return getLayoutsJSON(
073                            request, groupId, privateLayout, parentLayoutId, null, incomplete,
074                            treeId);
075            }
076    
077            public static String getLayoutsJSON(
078                            HttpServletRequest request, long groupId, boolean privateLayout,
079                            long layoutId, int max)
080                    throws Exception {
081    
082                    Layout layout = LayoutLocalServiceUtil.getLayout(
083                            groupId, privateLayout, layoutId);
084    
085                    long parentLayoutId = layout.getParentLayoutId();
086    
087                    long includedLayoutIndex = LayoutServiceUtil.getLayoutsCount(
088                            groupId, privateLayout, parentLayoutId, layout.getPriority());
089    
090                    int total = LayoutServiceUtil.getLayoutsCount(
091                            groupId, privateLayout, parentLayoutId);
092    
093                    int start = (int)includedLayoutIndex - 1;
094                    int end = (int)includedLayoutIndex + max;
095    
096                    if (end > total) {
097                            start = total - max;
098                            end = total;
099    
100                            if (start < 0) {
101                                    start = 0;
102                            }
103                    }
104    
105                    List<Layout> layouts = LayoutServiceUtil.getLayouts(
106                            groupId, privateLayout, parentLayoutId, true, start, end);
107    
108                    JSONObject jsonObject = _toJSONObject(request, groupId, layouts, total);
109    
110                    List<Layout> ancestorLayouts = LayoutServiceUtil.getAncestorLayouts(
111                                    layout.getPlid());
112    
113                    long[] ancestorLayoutIds = new long[ancestorLayouts.size()];
114                    String[] ancestorLayoutNames = new String[ancestorLayouts.size()];
115    
116                    Locale locale = PortalUtil.getLocale(request);
117    
118                    for (int i = 0; i < ancestorLayouts.size(); i++) {
119                            Layout ancestorLayout = ancestorLayouts.get(i);
120    
121                            ancestorLayoutIds[i] = ancestorLayout.getLayoutId();
122                            ancestorLayoutNames[i] = ancestorLayout.getName(locale);
123                    }
124    
125                    jsonObject.put("ancestorLayoutIds", ancestorLayoutIds);
126                    jsonObject.put("ancestorLayoutNames", ancestorLayoutNames);
127    
128                    jsonObject.put("start", start);
129    
130                    return jsonObject.toString();
131            }
132    
133            public static String getLayoutsJSON(
134                            HttpServletRequest request, long groupId, boolean privateLayout,
135                            long parentLayoutId, long[] expandedLayoutIds, boolean incomplete,
136                            String treeId)
137                    throws Exception {
138    
139                    LayoutTreeNodes layoutTreeNodes = _getLayoutTreeNodes(
140                            request, groupId, privateLayout, parentLayoutId, incomplete,
141                            expandedLayoutIds, treeId);
142    
143                    return _toJSON(request, groupId, layoutTreeNodes);
144            }
145    
146            public static String getLayoutsJSON(
147                            HttpServletRequest request, long groupId, String treeId)
148                    throws Exception {
149    
150                    LayoutTreeNodes layoutTreeNodes = new LayoutTreeNodes();
151    
152                    layoutTreeNodes.addAll(
153                            _getLayoutTreeNodes(
154                                    request, groupId, true,
155                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, false, null, treeId));
156                    layoutTreeNodes.addAll(
157                            _getLayoutTreeNodes(
158                                    request, groupId, false,
159                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, false, null, treeId));
160    
161                    return _toJSON(request, groupId, layoutTreeNodes);
162            }
163    
164            private static Layout _fetchCurrentLayout(HttpServletRequest request)
165                    throws SystemException {
166    
167                    long selPlid = ParamUtil.getLong(request, "selPlid");
168    
169                    if (selPlid > 0) {
170                            return LayoutLocalServiceUtil.fetchLayout(selPlid);
171                    }
172    
173                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
174                            WebKeys.THEME_DISPLAY);
175    
176                    Layout layout = themeDisplay.getLayout();
177    
178                    if (!layout.isTypeControlPanel()) {
179                            return layout;
180                    }
181    
182                    return null;
183            }
184    
185            private static JSONObject _toJSONObject(
186                            HttpServletRequest request, long groupId, List<Layout> layouts,
187                            int total)
188                    throws Exception {
189    
190                    List<LayoutTreeNode> layoutTreeNodesList =
191                            new ArrayList<LayoutTreeNode>();
192    
193                    for (Layout layout : layouts) {
194                            LayoutTreeNode layoutTreeNode = new LayoutTreeNode(layout);
195    
196                            layoutTreeNodesList.add(layoutTreeNode);
197                    }
198    
199                    LayoutTreeNodes layoutTreeNodes = new LayoutTreeNodes(
200                                    layoutTreeNodesList, total);
201    
202                    return _toJSONObject(request, groupId, layoutTreeNodes);
203            }
204    
205            private static List<Layout> _getAncestorLayouts(HttpServletRequest request)
206                    throws Exception {
207    
208                    long selPlid = ParamUtil.getLong(request, "selPlid");
209    
210                    if (selPlid == 0) {
211                            return Collections.emptyList();
212                    }
213    
214                    List<Layout> ancestorLayouts = LayoutServiceUtil.getAncestorLayouts(
215                            selPlid);
216    
217                    Layout layout = LayoutLocalServiceUtil.getLayout(selPlid);
218    
219                    ancestorLayouts.add(layout);
220    
221                    return ancestorLayouts;
222            }
223    
224            private static LayoutTreeNodes _getLayoutTreeNodes(
225                            HttpServletRequest request, long groupId, boolean privateLayout,
226                            long parentLayoutId, boolean incomplete, long[] expandedLayoutIds,
227                            String treeId)
228                    throws Exception {
229    
230                    List<LayoutTreeNode> layoutTreeNodes = new ArrayList<LayoutTreeNode>();
231    
232                    List<Layout> ancestorLayouts = _getAncestorLayouts(request);
233    
234                    List<Layout> layouts = LayoutServiceUtil.getLayouts(
235                            groupId, privateLayout, parentLayoutId, incomplete,
236                            QueryUtil.ALL_POS, QueryUtil.ALL_POS);
237    
238                    for (Layout layout :
239                                    _paginateLayouts(
240                                            request, groupId, privateLayout, parentLayoutId, layouts,
241                                            treeId)) {
242    
243                            LayoutTreeNode layoutTreeNode = new LayoutTreeNode(layout);
244    
245                            LayoutTreeNodes childLayoutTreeNodes = null;
246    
247                            if (_isExpandableLayout(
248                                            request, ancestorLayouts, expandedLayoutIds, layout)) {
249    
250                                    if (layout instanceof VirtualLayout) {
251                                            VirtualLayout virtualLayout = (VirtualLayout)layout;
252    
253                                            childLayoutTreeNodes = _getLayoutTreeNodes(
254                                                    request, virtualLayout.getSourceGroupId(),
255                                                    virtualLayout.isPrivateLayout(),
256                                                    virtualLayout.getLayoutId(), incomplete,
257                                                    expandedLayoutIds, treeId);
258                                    }
259                                    else {
260                                            childLayoutTreeNodes = _getLayoutTreeNodes(
261                                                    request, groupId, layout.isPrivateLayout(),
262                                                    layout.getLayoutId(), incomplete, expandedLayoutIds,
263                                                    treeId);
264                                    }
265                            }
266                            else {
267                                    int childLayoutsCount = LayoutServiceUtil.getLayoutsCount(
268                                            groupId, privateLayout, layout.getLayoutId());
269    
270                                    childLayoutTreeNodes = new LayoutTreeNodes(
271                                            new ArrayList<LayoutTreeNode>(), childLayoutsCount);
272                            }
273    
274                            layoutTreeNode.setChildLayoutTreeNodes(childLayoutTreeNodes);
275    
276                            layoutTreeNodes.add(layoutTreeNode);
277                    }
278    
279                    return new LayoutTreeNodes(layoutTreeNodes, layouts.size());
280            }
281    
282            private static int _getLoadedLayoutsCount(
283                            HttpSession session, long groupId, boolean privateLayout,
284                            long layoutId, String treeId)
285                    throws Exception {
286    
287                    StringBundler sb = new StringBundler(7);
288    
289                    sb.append(treeId);
290                    sb.append(StringPool.COLON);
291                    sb.append(groupId);
292                    sb.append(StringPool.COLON);
293                    sb.append(privateLayout);
294                    sb.append(StringPool.COLON);
295                    sb.append("Pagination");
296    
297                    String paginationJSON = SessionClicks.get(
298                            session, sb.toString(), JSONFactoryUtil.getNullJSON());
299    
300                    JSONObject paginationJSONObject = JSONFactoryUtil.createJSONObject(
301                            paginationJSON);
302    
303                    return paginationJSONObject.getInt(String.valueOf(layoutId), 0);
304            }
305    
306            private static boolean _isExpandableLayout(
307                    HttpServletRequest request, List<Layout> ancestorLayouts,
308                    long[] expandedLayoutIds, Layout layout) {
309    
310                    boolean expandParentLayouts = ParamUtil.getBoolean(
311                            request, "expandParentLayouts");
312    
313                    if (expandParentLayouts || ancestorLayouts.contains(layout) ||
314                            ArrayUtil.contains(expandedLayoutIds, layout.getLayoutId())) {
315    
316                            return true;
317                    }
318    
319                    return false;
320            }
321    
322            private static boolean _isPaginationEnabled(HttpServletRequest request) {
323                    boolean paginate = ParamUtil.getBoolean(request, "paginate", true);
324    
325                    if (paginate &&
326                            (PropsValues.LAYOUT_MANAGE_PAGES_INITIAL_CHILDREN > -1)) {
327    
328                            return true;
329                    }
330    
331                    return false;
332            }
333    
334            private static List<Layout> _paginateLayouts(
335                            HttpServletRequest request, long groupId, boolean privateLayout,
336                            long parentLayoutId, List<Layout> layouts, String treeId)
337                    throws Exception {
338    
339                    if (!_isPaginationEnabled(request)) {
340                            return layouts;
341                    }
342    
343                    HttpSession session = request.getSession();
344    
345                    int loadedLayoutsCount = _getLoadedLayoutsCount(
346                            session, groupId, privateLayout, parentLayoutId, treeId);
347    
348                    int start = ParamUtil.getInteger(request, "start");
349    
350                    start = Math.max(0, Math.min(start, layouts.size()));
351    
352                    int end = ParamUtil.getInteger(
353                            request, "end",
354                            start + PropsValues.LAYOUT_MANAGE_PAGES_INITIAL_CHILDREN);
355    
356                    if (loadedLayoutsCount > end) {
357                            end = loadedLayoutsCount;
358                    }
359    
360                    end = Math.max(start, Math.min(end, layouts.size()));
361    
362                    return layouts.subList(start, end);
363            }
364    
365            private static String _toJSON(
366                            HttpServletRequest request, long groupId,
367                            LayoutTreeNodes layoutTreeNodes)
368                    throws Exception {
369    
370                    JSONObject jsonObject = _toJSONObject(
371                            request, groupId, layoutTreeNodes);
372    
373                    return jsonObject.toString();
374            }
375    
376            private static JSONObject _toJSONObject(
377                            HttpServletRequest request, long groupId,
378                            LayoutTreeNodes layoutTreeNodes)
379                    throws Exception {
380    
381                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
382                            WebKeys.THEME_DISPLAY);
383    
384                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
385    
386                    boolean hasManageLayoutsPermission = GroupPermissionUtil.contains(
387                            themeDisplay.getPermissionChecker(), groupId,
388                            ActionKeys.MANAGE_LAYOUTS);
389    
390                    for (LayoutTreeNode layoutTreeNode : layoutTreeNodes) {
391                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
392    
393                            JSONObject childrenJSONObject = _toJSONObject(
394                                    request, groupId, layoutTreeNode.getChildLayoutTreeNodes());
395    
396                            jsonObject.put("children", childrenJSONObject);
397    
398                            Layout layout = layoutTreeNode.getLayout();
399    
400                            jsonObject.put("contentDisplayPage", layout.isContentDisplayPage());
401                            jsonObject.put("friendlyURL", layout.getFriendlyURL());
402    
403                            if (layout instanceof VirtualLayout) {
404                                    VirtualLayout virtualLayout = (VirtualLayout)layout;
405    
406                                    jsonObject.put("groupId", virtualLayout.getSourceGroupId());
407                            }
408                            else {
409                                    jsonObject.put("groupId", layout.getGroupId());
410                            }
411    
412                            jsonObject.put("hasChildren", layout.hasChildren());
413                            jsonObject.put("layoutId", layout.getLayoutId());
414                            jsonObject.put("name", layout.getName(themeDisplay.getLocale()));
415                            jsonObject.put("parentable", PortalUtil.isLayoutParentable(layout));
416                            jsonObject.put("parentLayoutId", layout.getParentLayoutId());
417                            jsonObject.put("plid", layout.getPlid());
418                            jsonObject.put("priority", layout.getPriority());
419                            jsonObject.put("privateLayout", layout.isPrivateLayout());
420                            jsonObject.put(
421                                    "sortable",
422                                            hasManageLayoutsPermission &&
423                                            SitesUtil.isLayoutSortable(layout));
424                            jsonObject.put("type", layout.getType());
425                            jsonObject.put(
426                                    "updateable",
427                                    LayoutPermissionUtil.contains(
428                                            themeDisplay.getPermissionChecker(), layout,
429                                            ActionKeys.UPDATE));
430                            jsonObject.put("uuid", layout.getUuid());
431    
432                            LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
433                                    layout);
434    
435                            if (layoutRevision != null) {
436                                    User user = themeDisplay.getUser();
437    
438                                    long recentLayoutSetBranchId =
439                                            StagingUtil.getRecentLayoutSetBranchId(
440                                                    user, layout.getLayoutSet().getLayoutSetId());
441    
442                                    if (StagingUtil.isIncomplete(layout, recentLayoutSetBranchId)) {
443                                            jsonObject.put("incomplete", true);
444                                    }
445    
446                                    long layoutSetBranchId = layoutRevision.getLayoutSetBranchId();
447    
448                                    LayoutSetBranch layoutSetBranch =
449                                            LayoutSetBranchLocalServiceUtil.getLayoutSetBranch(
450                                                    layoutSetBranchId);
451    
452                                    LayoutBranch layoutBranch = layoutRevision.getLayoutBranch();
453    
454                                    if (!layoutBranch.isMaster()) {
455                                            jsonObject.put(
456                                                    "layoutBranchId", layoutBranch.getLayoutBranchId());
457                                            jsonObject.put("layoutBranchName", layoutBranch.getName());
458                                    }
459    
460                                    if (layoutRevision.isHead()) {
461                                            jsonObject.put("layoutRevisionHead", true);
462                                    }
463    
464                                    jsonObject.put(
465                                            "layoutRevisionId", layoutRevision.getLayoutRevisionId());
466                                    jsonObject.put("layoutSetBranchId", layoutSetBranchId);
467                                    jsonObject.put(
468                                            "layoutSetBranchName", layoutSetBranch.getName());
469                            }
470    
471                            jsonArray.put(jsonObject);
472                    }
473    
474                    JSONObject responseJSONObject = JSONFactoryUtil.createJSONObject();
475    
476                    responseJSONObject.put("layouts", jsonArray);
477                    responseJSONObject.put("total", layoutTreeNodes.getTotal());
478    
479                    return responseJSONObject;
480            }
481    
482            private static class LayoutTreeNode {
483    
484                    public LayoutTreeNode(Layout layout) {
485                            _layout = layout;
486                    }
487    
488                    public Layout getLayout() {
489                            return _layout;
490                    }
491    
492                    public LayoutTreeNodes getChildLayoutTreeNodes() {
493                            return _childLayoutTreeNodes;
494                    }
495    
496                    public void setChildLayoutTreeNodes(
497                            LayoutTreeNodes childLayoutTreeNodes) {
498    
499                            _childLayoutTreeNodes = childLayoutTreeNodes;
500                    }
501    
502                    private LayoutTreeNodes _childLayoutTreeNodes = new LayoutTreeNodes();
503                    private Layout _layout;
504    
505            }
506    
507            private static class LayoutTreeNodes implements Iterable<LayoutTreeNode> {
508    
509                    public LayoutTreeNodes() {
510                    }
511    
512                    public LayoutTreeNodes(
513                            List<LayoutTreeNode> layoutTreeNodesList, int total) {
514    
515                            _layoutTreeNodesList = layoutTreeNodesList;
516                            _total = total;
517                    }
518    
519                    public void addAll(LayoutTreeNodes layoutTreeNodes) {
520                            _layoutTreeNodesList.addAll(
521                                    layoutTreeNodes.getLayoutTreeNodesList());
522    
523                            _total += layoutTreeNodes.getTotal();
524                    }
525    
526                    public int getTotal() {
527                            return _total;
528                    }
529    
530                    public List<LayoutTreeNode> getLayoutTreeNodesList() {
531                            return _layoutTreeNodesList;
532                    }
533    
534                    @Override
535                    public Iterator<LayoutTreeNode> iterator() {
536                            return _layoutTreeNodesList.iterator();
537                    }
538    
539                    private List<LayoutTreeNode> _layoutTreeNodesList =
540                            new ArrayList<LayoutTreeNode>();
541                    private int _total;
542    
543            }
544    
545    }