001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.workplace.explorer;
029
030import org.opencms.db.CmsResourceState;
031import org.opencms.file.CmsFolder;
032import org.opencms.file.CmsObject;
033import org.opencms.file.CmsProject;
034import org.opencms.file.CmsProperty;
035import org.opencms.file.CmsPropertyDefinition;
036import org.opencms.file.CmsResource;
037import org.opencms.file.CmsResourceFilter;
038import org.opencms.file.types.CmsResourceTypePlain;
039import org.opencms.file.types.I_CmsResourceType;
040import org.opencms.i18n.CmsMessages;
041import org.opencms.jsp.CmsJspActionElement;
042import org.opencms.loader.CmsLoaderException;
043import org.opencms.main.CmsException;
044import org.opencms.main.CmsLog;
045import org.opencms.main.OpenCms;
046import org.opencms.site.CmsSite;
047import org.opencms.util.CmsStringUtil;
048import org.opencms.workplace.CmsWorkplace;
049import org.opencms.workplace.CmsWorkplaceSettings;
050
051import java.util.ArrayList;
052import java.util.Iterator;
053import java.util.List;
054import java.util.Locale;
055import java.util.StringTokenizer;
056
057import javax.servlet.http.HttpServletRequest;
058
059import org.apache.commons.logging.Log;
060
061/**
062 * Generates the tree view for the OpenCms Workplace.<p>
063 *
064 * The following Workplace files use this class:
065 * <ul>
066 * <li>/views/explorer/tree_fs.jsp
067 * <li>/views/explorer/tree_files.jsp
068 * </ul>
069 * <p>
070 *
071 * @since 6.0.0
072 */
073public class CmsTree extends CmsWorkplace {
074
075    /** Request parameter name for the includesfiles parameter. */
076    public static final String PARAM_INCLUDEFILES = "includefiles";
077
078    /** Request parameter name for the lastknown parameter. */
079    public static final String PARAM_LASTKNOWN = "lastknown";
080
081    /** Request parameter name for the projectaware parameter. */
082    public static final String PARAM_PROJECTAWARE = "projectaware";
083
084    /** Request parameter name for the resource parameter. */
085    public static final String PARAM_RESOURCE = "resource";
086
087    /** Request parameter name for the rootloaded parameter. */
088    public static final String PARAM_ROOTLOADED = "rootloaded";
089
090    /** Request parameter name for the showsiteselector parameter. */
091    public static final String PARAM_SHOWSITESELECTOR = "showsiteselector";
092
093    /** Request parameter name for the integrator parameter. */
094    public static final String PARAM_INTEGRATOR = "integrator";
095
096    /** Request parameter name for the treesite parameter. */
097    public static final String PARAM_TREESITE = "treesite";
098
099    /** Request parameter name for the type parameter. */
100    public static final String PARAM_TYPE = "type";
101
102    /** The log object for this class. */
103    private static final Log LOG = CmsLog.getLog(CmsTree.class);
104
105    /** Type name for showing the tree when copying resources. */
106    private static final String TYPE_COPY = "copy";
107
108    /** Type name for showing the tree when creating page links in the editor. */
109    private static final String TYPE_PAGELINK = "pagelink";
110
111    /** Type name for showing the tree in preferences dialog. */
112    private static final String TYPE_PREFERENCES = "preferences";
113
114    /** Type name for showing the tree when creating siblings. */
115    private static final String TYPE_SIBLING = "sibling";
116
117    /** Type name for showing the tree in a widget dialog. */
118    private static final String TYPE_VFSWIDGET = "vfswidget";
119
120    /** Indicates if only folders or files and folders should be included in the tree. */
121    private boolean m_includeFiles;
122
123    /** Indicates if a complete new tree should be created. */
124    private boolean m_newTree;
125
126    /** Indicates project awareness, ie. if resources outside of the current project should be displayed as normal. */
127    private boolean m_projectAware = true;
128
129    /** The name of the root folder to display the tree from, usually "/". */
130    private String m_rootFolder;
131
132    /** Flag to indicate if the site selector should be shown in popup tree window. */
133    private boolean m_showSiteSelector;
134
135    /** The name of the start folder (or "last known" folder) to be loaded. */
136    private String m_startFolder;
137
138    /** The name of the target folder to be loaded. */
139    private String m_targetFolder;
140
141    /** The type of the tree (e.g. "copy", "project" etc.). */
142    private String m_treeType;
143
144    /**
145     * Public constructor.<p>
146     *
147     * @param jsp an initialized JSP action element
148     */
149    public CmsTree(CmsJspActionElement jsp) {
150
151        super(jsp);
152    }
153
154    /**
155     * Returns the HTML for the tree initialization.<p>
156     *
157     * @param cms the CmsObject
158     * @param encoding the current encoding
159     * @param skinUri the current skin URI
160     * @return the HTML for the tree initialization
161     */
162    public static String initTree(CmsObject cms, String encoding, String skinUri) {
163
164        StringBuffer retValue = new StringBuffer(512);
165        String servletUrl = OpenCms.getSystemInfo().getOpenCmsContext();
166
167        // get the localized workplace messages
168        // TODO: Why a new message object, can it not be obtained from session?
169        Locale locale = cms.getRequestContext().getLocale();
170        CmsMessages messages = OpenCms.getWorkplaceManager().getMessages(locale);
171
172        retValue.append("function initTreeResources() {\n");
173        retValue.append("\tinitResources(\"");
174        retValue.append(encoding);
175        retValue.append("\", \"");
176        retValue.append(PATH_WORKPLACE);
177        retValue.append("\", \"");
178        retValue.append(skinUri);
179        retValue.append("\", \"");
180        retValue.append(servletUrl);
181        retValue.append("\");\n");
182
183        // get all available resource types
184        List<I_CmsResourceType> allResTypes = OpenCms.getResourceManager().getResourceTypes();
185        for (int i = 0; i < allResTypes.size(); i++) {
186            // loop through all types
187            I_CmsResourceType type = allResTypes.get(i);
188            int curTypeId = type.getTypeId();
189            String curTypeName = type.getTypeName();
190            // get the settings for the resource type
191            CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(curTypeName);
192            if (settings == null) {
193                if (LOG.isWarnEnabled()) {
194                    LOG.warn(Messages.get().getBundle().key(Messages.LOG_MISSING_SETTINGS_ENTRY_1, curTypeName));
195                }
196                settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
197                    CmsResourceTypePlain.getStaticTypeName());
198            }
199            retValue.append("\taddResourceType(");
200            retValue.append(curTypeId);
201            retValue.append(", \"");
202            retValue.append(curTypeName);
203            retValue.append("\",\t\"");
204            retValue.append(messages.key(settings.getKey()));
205            retValue.append("\",\t\"" + CmsWorkplace.RES_PATH_FILETYPES);
206            retValue.append(settings.getIcon());
207            retValue.append("\");\n");
208        }
209
210        retValue.append("}\n\n");
211        retValue.append("initTreeResources();\n");
212        String sharedFolder = OpenCms.getSiteManager().getSharedFolder();
213        if (sharedFolder != null) {
214            retValue.append("sharedFolderName = '" + sharedFolder + "';");
215        }
216        return retValue.toString();
217    }
218
219    /**
220     * Determines the root folder of the current tree dependent on users setting of explorer view restriction.<p>
221     *
222     * @return the root folder resource name to display
223     */
224    public String getRootFolder() {
225
226        if (m_rootFolder == null) {
227            String folder = "/";
228            if ((getTreeType() == null) && getSettings().getUserSettings().getRestrictExplorerView()) {
229                folder = getSettings().getUserSettings().getStartFolder();
230            }
231            try {
232                getCms().readFolder(folder, CmsResourceFilter.IGNORE_EXPIRATION);
233            } catch (CmsException e) {
234                if (LOG.isInfoEnabled()) {
235                    LOG.info(e.getLocalizedMessage(), e);
236                }
237                folder = "/";
238            }
239            m_rootFolder = folder;
240        }
241        return m_rootFolder;
242    }
243
244    /**
245     * Returns the HTML for the site selector box for the explorer tree window.<p>
246     *
247     * @param htmlAttributes optional attributes for the &lt;select&gt; tag
248     * @return HTML code for the site selector box
249     */
250    public String getSiteSelector(String htmlAttributes) {
251
252        List<String> options = new ArrayList<String>();
253        List<String> values = new ArrayList<String>();
254        int selectedIndex = 0;
255        String preSelection = getSettings().getTreeSite(getTreeType());
256        if (preSelection == null) {
257            if ("".equals(getCms().getRequestContext().getSiteRoot())) {
258                // we are in the root site, getCurrentSite(CmsObject) includes NOT the root site
259                preSelection = "";
260            } else {
261                // get the site root of the current site
262                preSelection = OpenCms.getSiteManager().getCurrentSite(getCms()).getSiteRoot();
263            }
264            // set the tree site to avoid discrepancies between selector and tree
265            getSettings().setTreeSite(getTreeType(), preSelection);
266        }
267
268        boolean includeRootSite = true;
269        boolean showSiteUrls = false;
270        if (TYPE_PAGELINK.equals(getTreeType())) {
271            // in wysiwyg editor link dialog, don't show root site, but show site URLs
272            includeRootSite = false;
273            showSiteUrls = true;
274        }
275        List<CmsSite> sites = OpenCms.getSiteManager().getAvailableSites(
276            getCms(),
277            includeRootSite,
278            true,
279            getCms().getRequestContext().getOuFqn());
280
281        Iterator<CmsSite> i = sites.iterator();
282        int pos = 0;
283        while (i.hasNext()) {
284            CmsSite site = i.next();
285            values.add(site.getSiteRoot());
286            String curOption = substituteSiteTitle(site.getTitle());
287            if (showSiteUrls && (site.getSiteMatcher() != null)) {
288                // show the site URL in editor link dialog tree
289                curOption = site.getUrl() + " (" + curOption + ")";
290                if (getCms().getRequestContext().getSiteRoot().equals(site.getSiteRoot())) {
291                    // mark the current workplace site in selector
292                    curOption = "*" + curOption;
293                }
294            }
295
296            if (site.getSiteRoot().equals(preSelection)) {
297                // this is the user's currently selected site
298                selectedIndex = pos;
299            }
300            options.add(curOption);
301            pos++;
302        }
303
304        return buildSelect(htmlAttributes, options, values, selectedIndex);
305    }
306
307    /**
308     * Returns the html for the explorer tree.<p>
309     *
310     * @return the html for the explorer tree
311     */
312    public String getTree() {
313
314        StringBuffer result = new StringBuffer(2048);
315
316        List<String> targetFolderList = new ArrayList<String>();
317        if (getTargetFolder() != null) {
318            // check if there is more than one folder to update (e.g. move operation)
319            StringTokenizer T = new StringTokenizer(getTargetFolder(), "|");
320            while (T.hasMoreTokens()) {
321                String currentFolder = T.nextToken().trim();
322                //                if (OpenCms.getSiteManager().startsWithShared(currentFolder)) {
323                //                    currentFolder = OpenCms.getSiteManager().cutShared(currentFolder);
324                //                }
325                targetFolderList.add(currentFolder);
326            }
327        } else {
328            targetFolderList.add(null);
329        }
330
331        String storedSiteRoot = null;
332        try {
333            CmsFolder folder = null;
334            List<CmsResource> resources = new ArrayList<CmsResource>();
335            String oldSiteRoot = getCms().getRequestContext().getSiteRoot();
336
337            Iterator<String> targets = targetFolderList.iterator();
338            while (targets.hasNext()) {
339                // iterate over all given target folders
340                String currentTargetFolder = targets.next();
341
342                if (getSettings().getTreeSite(getTreeType()) != null) {
343                    // change the site root for popup window with site selector
344                    storedSiteRoot = getCms().getRequestContext().getSiteRoot();
345                    if (newTree() && (currentTargetFolder == null)) {
346                        currentTargetFolder = "/";
347                    }
348                    getCms().getRequestContext().setSiteRoot(getSettings().getTreeSite(getTreeType()));
349                    try {
350                        // check presence of target folder
351                        getCms().readFolder(currentTargetFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
352                    } catch (CmsException e) {
353                        // target folder not found, set it to "/"
354                        if (LOG.isInfoEnabled()) {
355                            LOG.info(e.getLocalizedMessage(), e);
356                        }
357                        currentTargetFolder = "/";
358                    }
359                }
360
361                // read the selected folder
362                try {
363                    folder = getCms().readFolder(currentTargetFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
364                } catch (CmsException e) {
365                    // return with error
366                    return printError(e);
367                }
368
369                String startFolder = getStartFolder();
370                String rcSite = getCms().getRequestContext().getSiteRoot();
371                if (OpenCms.getSiteManager().startsWithShared(currentTargetFolder)
372                    && OpenCms.getSiteManager().startsWithShared(rcSite)) {
373                    currentTargetFolder = currentTargetFolder.substring(
374                        OpenCms.getSiteManager().getSharedFolder().length() - 1);
375                }
376                if ((startFolder == null) || (!currentTargetFolder.startsWith(startFolder))) {
377                    // no (valid) start folder given, just load current folder
378                    try {
379                        if (includeFiles()) {
380                            resources.addAll(getCms().getResourcesInFolder(
381                                currentTargetFolder,
382                                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
383                        } else {
384                            resources.addAll(
385                                getCms().getSubFolders(currentTargetFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
386                        }
387                    } catch (CmsException e) {
388                        // return with error
389                        return printError(e);
390                    }
391                } else {
392                    // valid start folder given, load all folders between start and current folder
393                    try {
394                        if (includeFiles()) {
395                            resources.addAll(
396                                getCms().getResourcesInFolder(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
397                        } else {
398                            resources.addAll(
399                                getCms().getSubFolders(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
400                        }
401                        StringTokenizer tok = new StringTokenizer(
402                            currentTargetFolder.substring(startFolder.length()),
403                            "/");
404                        while (tok.hasMoreTokens()) {
405                            startFolder += tok.nextToken() + "/";
406                            if (includeFiles()) {
407                                resources.addAll(getCms().getResourcesInFolder(
408                                    startFolder,
409                                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
410                            } else {
411                                resources.addAll(
412                                    getCms().getSubFolders(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
413                            }
414                        }
415                    } catch (CmsException e) {
416                        // return with error
417                        return printError(e);
418                    }
419                }
420            }
421
422            result.append("function init() {\n");
423
424            if (newTree()) {
425                // new tree must be reloaded
426                result.append("parent.initTree();\n");
427                result.append(getRootNode());
428            }
429
430            // read the list of project resource to select which resource is "inside" or "outside"
431            List<String> projectResources = new ArrayList<String>();
432            if (isProjectAware()) {
433                try {
434                    projectResources = getCms().readProjectResources(getCms().getRequestContext().getCurrentProject());
435                } catch (CmsException e) {
436                    // use an empty list (all resources are "outside")
437                    if (LOG.isInfoEnabled()) {
438                        LOG.info(e.getLocalizedMessage(), e);
439                    }
440                }
441            }
442
443            // now output all the tree nodes
444            Iterator<CmsResource> i = resources.iterator();
445            while (i.hasNext()) {
446                CmsResource resource = i.next();
447                boolean grey = false;
448                if (isProjectAware()) {
449                    grey = !CmsProject.isInsideProject(projectResources, resource);
450                }
451                if (!grey) {
452                    try {
453                        OpenCms.getResourceManager().getResourceType(resource.getTypeId());
454                    } catch (CmsLoaderException e) {
455                        // if resource type is not found
456                        grey = true;
457                    }
458                }
459
460                result.append(
461                    getNode(
462                        resource.getRootPath(),
463                        resource.getName(),
464                        resource.getTypeId(),
465                        resource.isFolder(),
466                        resource.getState(),
467                        grey));
468            }
469
470            if (includeFiles()) {
471                result.append("parent.setIncludeFiles(true);\n");
472            }
473            result.append("parent.setProjectAware(").append(isProjectAware()).append(");\n");
474            if (getTreeType() != null) {
475                // this is a popup window tree
476                result.append("parent.setTreeType(\"");
477                result.append(getTreeType());
478                result.append("\");\n");
479                String curSite = getSettings().getTreeSite(getTreeType());
480                if (curSite != null) {
481                    // add the current site as prefix if present
482                    result.append("parent.setSitePrefix(\"");
483                    result.append(getSitePrefix(curSite, oldSiteRoot));
484                    result.append("\");\n");
485                }
486            }
487            // set the root folder in javascript
488            result.append("parent.setRootFolder(\"");
489            result.append(getRootFolder());
490            result.append("\");\n");
491
492            if (folder != null) {
493                if (newTree()) {
494                    // new tree
495                    result.append("parent.showTree(parent.tree_display.document, \"");
496                    result.append(folder.getRootPath().hashCode());
497                    result.append("\");\n");
498                } else {
499                    // update the current tree with the children of the selected node
500                    if (resources.size() == 0) {
501                        // the node had no children
502                        result.append("parent.setNoChilds(\"");
503                        result.append(folder.getRootPath().hashCode());
504                        result.append("\");\n");
505                    }
506                    result.append("parent.showLoadedNodes(parent.tree_display.document,\"");
507                    result.append(folder.getRootPath().hashCode());
508                    result.append("\");\n");
509                }
510            }
511
512            result.append("}\n");
513        } finally {
514            if (storedSiteRoot != null) {
515                getCms().getRequestContext().setSiteRoot(storedSiteRoot);
516            }
517        }
518        return result.toString();
519    }
520
521    /**
522     * Returns the type of this tree (e.g. "copy", "project" etc.),
523     * if null this is the default explorer version.<p>
524     *
525     * @return the current type of the tree (e.g. "copy", "project" etc.)
526     */
527    public String getTreeType() {
528
529        return m_treeType;
530    }
531
532    /**
533     * Indicates if only folders or files and folders should be included in the tree.<p>
534     *
535     * @return true if files and folders should be included in the tree
536     */
537    public boolean includeFiles() {
538
539        return m_includeFiles;
540    }
541
542    /**
543     * Returns the HTML for the tree initialization.<p>
544     *
545     * @return the HTML for the tree initialization
546     */
547    public String initTree() {
548
549        return initTree(getCms(), getEncoding(), getSkinUri());
550    }
551
552    /**
553     * Returns the project awareness flag.<p>
554     *
555     * @return the project awareness flag
556     */
557    public boolean isProjectAware() {
558
559        return m_projectAware;
560    }
561
562    /**
563     * Sets the project awareness flag.<p>
564     *
565     * @param projectAware the project awareness flag to set
566     */
567    public void setProjectAware(boolean projectAware) {
568
569        m_projectAware = projectAware;
570    }
571
572    /**
573     * Indicates if the site selector should be shown depending on the tree type, initial settings and the count of accessible sites.<p>
574     *
575     * @return true if site selector should be shown, otherwise false
576     */
577    public boolean showSiteSelector() {
578
579        return m_showSiteSelector;
580    }
581
582    /**
583     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
584     */
585    @Override
586    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
587
588        setIncludeFiles(Boolean.valueOf(request.getParameter(PARAM_INCLUDEFILES)).booleanValue());
589        setProjectAware(Boolean.valueOf(request.getParameter(PARAM_PROJECTAWARE)).booleanValue());
590        boolean rootloaded = Boolean.valueOf(request.getParameter(PARAM_ROOTLOADED)).booleanValue();
591        String resource = request.getParameter(PARAM_RESOURCE);
592
593        setTreeType(request.getParameter(PARAM_TYPE));
594        String treeSite = request.getParameter(PARAM_TREESITE);
595        if ((getTreeType() != null) && (treeSite != null)) {
596            getSettings().setTreeSite(getTreeType(), treeSite);
597        }
598
599        if (getSettings().getTreeSite(getTreeType()) != null) {
600            String site = getCms().getRequestContext().getSiteRoot();
601            try {
602                getCms().getRequestContext().setSiteRoot(getSettings().getTreeSite(getTreeType()));
603                if (!getCms().existsResource(resource)) {
604                    resource = null;
605                }
606            } finally {
607                getCms().getRequestContext().setSiteRoot(site);
608            }
609        } else {
610            if (!getCms().existsResource(resource)) {
611                resource = null;
612            }
613        }
614
615        computeSiteSelector(request);
616
617        String currentResource;
618        if (getTreeType() == null) {
619            currentResource = getSettings().getExplorerResource();
620        } else {
621            // get the current tree resource from the settings for a special tree type
622            currentResource = getSettings().getTreeResource(getTreeType());
623        }
624
625        String lastknown = request.getParameter(PARAM_LASTKNOWN);
626        // both "resource" and "lastknown" must be folders
627
628        if (resource != null) {
629            resource = CmsResource.getFolderPath(resource);
630        }
631        if ((lastknown != null) && (!lastknown.endsWith("/"))) {
632            lastknown += "/";
633        }
634
635        String rootFolder = getRootFolder();
636        if (rootFolder.equals(resource) && !rootFolder.equals(currentResource) && (lastknown == null) && !rootloaded) {
637            // direct load of a new tree with subtree (e.g. when returning from an editor)
638            lastknown = getRootFolder();
639            resource = CmsResource.getFolderPath(currentResource);
640            setNewTree(true);
641        } else if (rootFolder.equals(resource)) {
642            // load new tree if not already loaded
643            setNewTree(!rootloaded);
644        } else {
645            setNewTree(false);
646        }
647
648        if (getTreeType() != null) {
649            getSettings().setTreeResource(getTreeType(), resource);
650        }
651
652        setTargetFolder(resource);
653        setStartFolder(lastknown);
654    }
655
656    /**
657     * Determines if the site selector frame should be shown depending on the tree type or the value of a request parameter.<p>
658     *
659     * If only one site is available, the site selector is not displayed.<p>
660     *
661     * @param request the HttpServletRequest to check
662     */
663    private void computeSiteSelector(HttpServletRequest request) {
664
665        boolean selectorForType = TYPE_SIBLING.equals(getTreeType())
666            || TYPE_COPY.equals(getTreeType())
667            || TYPE_PAGELINK.equals(getTreeType())
668            || TYPE_PREFERENCES.equals(getTreeType());
669        boolean showFromRequest = Boolean.valueOf(request.getParameter(PARAM_SHOWSITESELECTOR)).booleanValue();
670        if (selectorForType || showFromRequest) {
671            // get all available sites
672            int siteCount = OpenCms.getSiteManager().getAvailableSites(getCms(), true).size();
673            setShowSiteSelector(siteCount > 1);
674            return;
675        }
676        setShowSiteSelector(false);
677    }
678
679    /**
680     * Creates the output for a tree node.<p>
681     *
682     * @param path the path of the resource represented by this tree node
683     * @param title the resource name
684     * @param type the resource type
685     * @param folder if the resource is a folder
686     * @param state the resource state
687     * @param grey if true, the node is displayed in grey
688     *
689     * @return the output for a tree node
690     */
691    private String getNode(String path, String title, int type, boolean folder, CmsResourceState state, boolean grey) {
692
693        StringBuffer result = new StringBuffer(64);
694        String parent = CmsResource.getParentFolder(path);
695        result.append("parent.aC(\"");
696        // name
697        result.append(title);
698        result.append("\",");
699        // type
700        result.append(type);
701        result.append(",");
702        // folder
703        if (folder) {
704            result.append(1);
705        } else {
706            result.append(0);
707        }
708        result.append(",");
709        // hashcode of path
710        result.append(path.hashCode());
711        result.append(",");
712        // hashcode of parent path
713        result.append((parent != null) ? parent.hashCode() : 0);
714        result.append(",");
715        // resource state
716        result.append(state);
717        result.append(",");
718        // project status
719        if (grey) {
720            result.append(1);
721        } else {
722            result.append(0);
723        }
724        result.append(");\n");
725        return result.toString();
726    }
727
728    /**
729     * Creates a node entry for the root node of the current site.<p>
730     *
731     * @return a node entry for the root node of the current site
732     */
733    private String getRootNode() {
734
735        CmsResource resource = null;
736        String title = null;
737        String folder = getRootFolder();
738        try {
739            resource = getCms().readFolder(folder, CmsResourceFilter.IGNORE_EXPIRATION);
740            // get the title information of the folder
741            CmsProperty titleProperty = getCms().readPropertyObject(
742                folder,
743                CmsPropertyDefinition.PROPERTY_TITLE,
744                false);
745
746            if ((titleProperty == null) || titleProperty.isNullProperty()) {
747                getCms().getSitePath(resource);
748                title = resource.getRootPath();
749            } else {
750                title = titleProperty.getValue();
751            }
752            return getNode(resource.getRootPath(), title, resource.getTypeId(), true, resource.getState(), false);
753        } catch (CmsException e) {
754            // should usually never happen
755            if (LOG.isInfoEnabled()) {
756                LOG.info(e.getLocalizedMessage(), e);
757            }
758        }
759        return "";
760    }
761
762    /**
763     * Calculates the prefix that has to be added when selecting a resource in a popup tree window.<p>
764     *
765     * This is needed for the link dialog in editors
766     * as well as the copy, move and link popup dialogs for resources in the VFS.<p>
767     *
768     * @param prefix the current prefix of the resource
769     * @param storedSiteRoot the site root in which the workplace (not the tree!) is
770     * @return the prefix which is added to the resource name
771     */
772    private String getSitePrefix(String prefix, String storedSiteRoot) {
773
774        if (OpenCms.getSiteManager().isSharedFolder(prefix)) {
775            return prefix;
776        }
777        if (TYPE_PAGELINK.equals(getTreeType())) {
778            // in editor link dialog, create a special prefix for internal links
779            if (!storedSiteRoot.equals(prefix)) {
780                // stored site is not selected site, create complete URL as prefix
781                CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(prefix);
782                prefix = getCms().getRequestContext().removeSiteRoot(prefix);
783                prefix = site.getUrl() + OpenCms.getSystemInfo().getOpenCmsContext() + prefix;
784            } else {
785                // stored site is selected site, don't show prefix at all
786                prefix = "";
787            }
788
789        } else if (TYPE_COPY.equals(getTreeType())
790            || TYPE_SIBLING.equals(getTreeType())
791            || TYPE_VFSWIDGET.equals(getTreeType())) {
792            // in vfs copy|move|link or vfs widget mode, don't add the prefix for the current workplace site
793            if (storedSiteRoot.equals(prefix)) {
794                prefix = "";
795            }
796        } else if (TYPE_PREFERENCES.equals(getTreeType())) {
797            prefix = "";
798        }
799
800        return prefix;
801    }
802
803    /**
804     * Returns the name of the start folder (or "last known" folder) to be loaded.<p>
805     *
806     * @return the name of the start folder (or "last known" folder) to be loaded
807     */
808    private String getStartFolder() {
809
810        return m_startFolder;
811    }
812
813    /**
814     * Returns the target folder name.<p>
815     *
816     * @return the target folder name
817     */
818    private String getTargetFolder() {
819
820        return m_targetFolder;
821    }
822
823    /**
824     * Returns true if a complete new tree must be loaded, false if an existing
825     * tree is updated or extended.<p>
826     *
827     * @return true if a complete new tree must be loaded
828     */
829    private boolean newTree() {
830
831        return m_newTree;
832    }
833
834    /**
835     * Creates error information output.<p>
836     *
837     * @param t an error that occurred
838     * @return error information output
839     */
840    private String printError(Throwable t) {
841
842        StringBuffer result = new StringBuffer(1024);
843        result.append("/*\n");
844        result.append(CmsStringUtil.escapeHtml(t.getMessage()));
845        result.append("\n*/\n");
846        result.append("function init() {\n");
847        result.append("}\n");
848        return result.toString();
849    }
850
851    /**
852     * Sets the value to indicate if only folders or files and folders should be included in the tree.<p>
853     *
854     * @param includeFiles if true if files and folders should be included in the tree
855     */
856    private void setIncludeFiles(boolean includeFiles) {
857
858        m_includeFiles = includeFiles;
859    }
860
861    /**
862     * Sets if a complete tree must be loaded.<p>
863     *
864     * @param newTree if true, a complete tree must be loaded
865     */
866    private void setNewTree(boolean newTree) {
867
868        m_newTree = newTree;
869    }
870
871    /**
872     * Sets if the site selector should be shown depending on the tree type and the count of accessible sites.<p>
873     *
874     * @param showSiteSelector true if site selector should be shown, otherwise false
875     */
876    private void setShowSiteSelector(boolean showSiteSelector) {
877
878        m_showSiteSelector = showSiteSelector;
879    }
880
881    /**
882     * Sets the name of the start folder (or "last known" folder) to be loaded.<p>
883     *
884     * @param startFolder the name of the start folder (or "last known" folder) to be loaded
885     */
886    private void setStartFolder(String startFolder) {
887
888        m_startFolder = startFolder;
889    }
890
891    /**
892     * Sets the target folder name.<p>
893     *
894     * @param targetFolder the target folder name
895     */
896    private void setTargetFolder(String targetFolder) {
897
898        m_targetFolder = targetFolder;
899    }
900
901    /**
902     * Sets the type of this tree.<p>
903     *
904     * @param type the type of this tree
905     */
906    private void setTreeType(String type) {
907
908        m_treeType = type;
909    }
910}