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, 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.ade.galleries;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.formatters.CmsFormatterConfigurationCacheState;
032import org.opencms.ade.galleries.CmsGalleryFilteredNavTreeBuilder.NavigationNode;
033import org.opencms.ade.galleries.preview.I_CmsPreviewProvider;
034import org.opencms.ade.galleries.shared.CmsGalleryActionInfo;
035import org.opencms.ade.galleries.shared.CmsGalleryConfiguration;
036import org.opencms.ade.galleries.shared.CmsGalleryDataBean;
037import org.opencms.ade.galleries.shared.CmsGalleryFolderBean;
038import org.opencms.ade.galleries.shared.CmsGalleryGroup;
039import org.opencms.ade.galleries.shared.CmsGallerySearchBean;
040import org.opencms.ade.galleries.shared.CmsGallerySearchScope;
041import org.opencms.ade.galleries.shared.CmsGalleryTabConfiguration;
042import org.opencms.ade.galleries.shared.CmsResourceTypeBean;
043import org.opencms.ade.galleries.shared.CmsResourceTypeBean.TypeVisibility;
044import org.opencms.ade.galleries.shared.CmsResultItemBean;
045import org.opencms.ade.galleries.shared.CmsSitemapEntryBean;
046import org.opencms.ade.galleries.shared.CmsVfsEntryBean;
047import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants;
048import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryMode;
049import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryTabId;
050import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.SortParams;
051import org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService;
052import org.opencms.file.CmsObject;
053import org.opencms.file.CmsProperty;
054import org.opencms.file.CmsPropertyDefinition;
055import org.opencms.file.CmsResource;
056import org.opencms.file.CmsResourceFilter;
057import org.opencms.file.CmsUser;
058import org.opencms.file.CmsVfsResourceNotFoundException;
059import org.opencms.file.types.CmsResourceTypeBinary;
060import org.opencms.file.types.CmsResourceTypeFunctionConfig;
061import org.opencms.file.types.CmsResourceTypeImage;
062import org.opencms.file.types.CmsResourceTypePointer;
063import org.opencms.file.types.CmsResourceTypeXmlContent;
064import org.opencms.file.types.CmsResourceTypeXmlPage;
065import org.opencms.file.types.I_CmsResourceType;
066import org.opencms.flex.CmsFlexController;
067import org.opencms.gwt.CmsCoreService;
068import org.opencms.gwt.CmsGwtService;
069import org.opencms.gwt.CmsIconUtil;
070import org.opencms.gwt.CmsRpcException;
071import org.opencms.gwt.CmsVfsService;
072import org.opencms.gwt.shared.CmsGalleryContainerInfo;
073import org.opencms.gwt.shared.CmsListInfoBean;
074import org.opencms.gwt.shared.CmsTemplateContextInfo;
075import org.opencms.i18n.CmsLocaleManager;
076import org.opencms.i18n.CmsMessages;
077import org.opencms.json.JSONException;
078import org.opencms.json.JSONObject;
079import org.opencms.jsp.CmsJspNavBuilder;
080import org.opencms.jsp.CmsJspNavBuilder.Visibility;
081import org.opencms.jsp.CmsJspNavElement;
082import org.opencms.loader.CmsLoaderException;
083import org.opencms.loader.CmsResourceManager;
084import org.opencms.loader.I_CmsTemplateContextProvider;
085import org.opencms.main.CmsException;
086import org.opencms.main.CmsLog;
087import org.opencms.main.CmsPermalinkResourceHandler;
088import org.opencms.main.CmsStaticResourceHandler;
089import org.opencms.main.OpenCms;
090import org.opencms.search.fields.CmsSearchFieldMapping;
091import org.opencms.search.galleries.CmsGallerySearch;
092import org.opencms.search.galleries.CmsGallerySearchParameters;
093import org.opencms.search.galleries.CmsGallerySearchResult;
094import org.opencms.search.galleries.CmsGallerySearchResultList;
095import org.opencms.security.CmsPermissionSet;
096import org.opencms.security.CmsPermissionViolationException;
097import org.opencms.security.CmsRole;
098import org.opencms.site.CmsSite;
099import org.opencms.staticexport.CmsLinkManager;
100import org.opencms.ui.components.CmsResourceIcon;
101import org.opencms.util.CmsDateUtil;
102import org.opencms.util.CmsPath;
103import org.opencms.util.CmsRequestUtil;
104import org.opencms.util.CmsStringUtil;
105import org.opencms.util.CmsUUID;
106import org.opencms.util.CmsUriSplitter;
107import org.opencms.workplace.CmsWorkplace;
108import org.opencms.workplace.CmsWorkplaceMessages;
109import org.opencms.workplace.CmsWorkplaceSettings;
110import org.opencms.workplace.explorer.CmsResourceUtil;
111import org.opencms.xml.containerpage.CmsADESessionCache;
112import org.opencms.xml.containerpage.CmsFormatterConfiguration;
113import org.opencms.xml.containerpage.CmsFunctionFormatterBean;
114import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler;
115import org.opencms.xml.containerpage.I_CmsFormatterBean;
116
117import java.text.Collator;
118import java.text.DateFormat;
119import java.text.ParseException;
120import java.util.ArrayList;
121import java.util.Arrays;
122import java.util.Collection;
123import java.util.Collections;
124import java.util.Comparator;
125import java.util.Date;
126import java.util.HashMap;
127import java.util.HashSet;
128import java.util.Iterator;
129import java.util.List;
130import java.util.Locale;
131import java.util.Map;
132import java.util.Map.Entry;
133import java.util.Set;
134import java.util.TreeMap;
135import java.util.TreeSet;
136import java.util.function.Predicate;
137
138import javax.servlet.http.HttpServletRequest;
139import javax.servlet.http.HttpSession;
140
141import org.apache.commons.logging.Log;
142
143import com.google.common.collect.ArrayListMultimap;
144import com.google.common.collect.ComparisonChain;
145import com.google.common.collect.Lists;
146import com.google.common.collect.Maps;
147import com.google.common.collect.Multimap;
148import com.google.common.collect.Sets;
149
150/**
151 * Handles all RPC services related to the gallery dialog.<p>
152 *
153 * @since 8.0.0
154 *
155 * @see org.opencms.ade.galleries.CmsGalleryService
156 * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService
157 * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryServiceAsync
158 */
159public class CmsGalleryService extends CmsGwtService implements I_CmsGalleryService {
160
161    /**
162     * Gallery info object.<p>
163     */
164    protected class CmsGalleryTypeInfo {
165
166        /** The content types using this gallery. */
167        private List<I_CmsResourceType> m_contentTypes;
168
169        /** The gallery folder resources. */
170        private List<CmsResource> m_galleries;
171
172        /** The resource type of this gallery. */
173        private I_CmsResourceType m_resourceType;
174
175        /**
176         * Constructor.<p>
177         *
178         * @param resourceType the resource type of the gallery
179         * @param contentType the resource type of the gallery content
180         * @param galleries the gallery resources
181         */
182        protected CmsGalleryTypeInfo(
183            I_CmsResourceType resourceType,
184            I_CmsResourceType contentType,
185            List<CmsResource> galleries) {
186
187            m_resourceType = resourceType;
188            m_contentTypes = new ArrayList<I_CmsResourceType>();
189            m_contentTypes.add(contentType);
190            m_galleries = galleries;
191        }
192
193        /**
194         * Adds a type to the list of content types.<p>
195         *
196         * @param type the type to add
197         */
198        protected void addContentType(I_CmsResourceType type) {
199
200            m_contentTypes.add(type);
201        }
202
203        /**
204         * Returns the contentTypes.<p>
205         *
206         * @return the contentTypes
207         */
208        protected List<I_CmsResourceType> getContentTypes() {
209
210            return m_contentTypes;
211        }
212
213        /**
214         * Returns the gallery folder resources.<p>
215         *
216         * @return the resources
217         */
218        protected List<CmsResource> getGalleries() {
219
220            return m_galleries;
221        }
222
223        /**
224         * Returns the resourceType.<p>
225         *
226         * @return the resourceType
227         */
228        protected I_CmsResourceType getResourceType() {
229
230            return m_resourceType;
231        }
232
233        /**
234         * Sets the contentTypes.<p>
235         *
236         * @param contentTypes the contentTypes to set
237         */
238        protected void setContentTypes(List<I_CmsResourceType> contentTypes) {
239
240            m_contentTypes = contentTypes;
241        }
242
243        /**
244         * Sets the galleries.<p>
245         *
246         * @param galleries the gallery resource list to set
247         */
248        protected void setGalleries(List<CmsResource> galleries) {
249
250            m_galleries = galleries;
251        }
252
253        /**
254         * Sets the resourceType.<p>
255         *
256         * @param resourceType the resourceType to set
257         */
258        protected void setResourceType(I_CmsResourceType resourceType) {
259
260            m_resourceType = resourceType;
261        }
262    }
263
264    /** Bean used to store a single type together with a flag indicating its visibility. */
265    class TypeWithVisibility {
266
267        /** True if the type should only be shown in the full list. */
268        private boolean m_onlyShowInFullList;
269
270        /** The resource type. */
271        private I_CmsResourceType m_type;
272
273        /**
274         * Creates a new instance.<p>
275         *
276         * @param type the resource type
277         * @param onlyShowInFullList the flag to control the visibility
278         */
279        public TypeWithVisibility(I_CmsResourceType type, boolean onlyShowInFullList) {
280
281            m_type = type;
282            m_onlyShowInFullList = onlyShowInFullList;
283        }
284
285        /**
286         * Returns the type.<p>
287         *
288         * @return the type
289         */
290        public I_CmsResourceType getType() {
291
292            return m_type;
293        }
294
295        /**
296         * Returns the onlyShowInFullList.<p>
297         *
298         * @return the onlyShowInFullList
299         */
300        public boolean isOnlyShowInFullList() {
301
302            return m_onlyShowInFullList;
303        }
304
305    }
306
307    /** Key for additional info gallery folder filter. */
308    public static final String FOLDER_FILTER_ADD_INFO_KEY = "gallery_folder_filter";
309
310    /** Limit to the number results loaded on initial search. */
311    public static final int INITIAL_SEARCH_MAX_RESULTS = 200;
312
313    /** The key used for storing the last used gallery in adeview mode. */
314    public static final String KEY_LAST_USED_GALLERY_ADEVIEW = "__adeView";
315
316    /** Name for the 'galleryShowInvalidDefault' preference. */
317    public static final String PREF_GALLERY_SHOW_INVALID_DEFAULT = "galleryShowInvalidDefault";
318
319    /** Storage key for the last gallery sort order used in the content editor and ADE image gallery button. */
320    public static final String RESULT_ORDER_KEY_EDITOR = "editor";
321
322    /** Storage key for the last gallery sort order in other contexts. */
323    public static final String RESULT_ORDER_KEY_OTHER = "other";
324
325    /** Storage key for the last gallery sort order used in the 'magic wand'/new element dialog. */
326    public static final String RESULT_ORDER_KEY_PAGE = "page";
327
328    /** Key for additional info gallery result view type. */
329    public static final String RESULT_VIEW_TYPE_ADD_INFO_KEY = "gallery_result_view_type";
330
331    /** The dynamic function resource type names. */
332    private static final Set<String> FUNCTION_TYPES = new HashSet<>(
333        Arrays.asList(
334            new String[] {CmsXmlDynamicFunctionHandler.TYPE_FUNCTION, CmsResourceTypeFunctionConfig.TYPE_NAME}));
335
336    /** The logger instance for this class. */
337    private static final Log LOG = CmsLog.getLog(CmsGalleryService.class);
338
339    /** Serialization uid. */
340    private static final long serialVersionUID = 1673026761080584889L;
341
342    /** Compares the VFS entry beans. */
343    private static final Comparator<CmsVfsEntryBean> VFS_COMPARATOR = new Comparator<CmsVfsEntryBean>() {
344
345        public int compare(CmsVfsEntryBean o1, CmsVfsEntryBean o2) {
346
347            String o1Path = o1.getRootPath();
348            String o2Path = o2.getRootPath();
349            if (o1Path.endsWith("/")) {
350                o1Path = o1Path.substring(0, o1Path.length() - 1);
351            }
352            if (o2Path.endsWith("/")) {
353                o2Path = o2Path.substring(0, o2Path.length() - 1);
354            }
355            return o1Path.compareTo(o2Path);
356        }
357    };
358
359    /** The instance of the resource manager. */
360    CmsResourceManager m_resourceManager;
361
362    /** The workplace settings of the current user. */
363    private CmsWorkplaceSettings m_workplaceSettings;
364
365    /** The workplace locale from the current user's settings. */
366    private Locale m_wpLocale;
367
368    /**
369     * Converts the gallery mode to the key used for storing the last used search order
370     *
371     * @param mode the gallery mode
372     * @return the key to use for storing the last used search order
373     */
374    public static String convertModeToResultOrderKey(GalleryMode mode) {
375
376        String key = null;
377        switch (mode) {
378            case ade:
379                key = RESULT_ORDER_KEY_PAGE;
380                break;
381            case adeView:
382            case view:
383                key = RESULT_ORDER_KEY_OTHER;
384                break;
385            default:
386                return null;
387
388        }
389        return key;
390
391    }
392
393    /**
394     * Generates the pre-loaded contents for the VFS tab of the gallery dialog.<p>
395     *
396     * @param cms the current CMS context
397     * @param vfsState the saved VFS tree state (may be null)
398     * @param folders the saved search folders (may be null)
399     *
400     * @return the root tree entry for the VFS tab
401     */
402    public static CmsVfsEntryBean generateVfsPreloadData(
403        final CmsObject cms,
404        final CmsTreeOpenState vfsState,
405        final Set<String> folders) {
406
407        CmsVfsEntryBean vfsPreloadData = null;
408
409        A_CmsTreeTabDataPreloader<CmsVfsEntryBean> vfsloader = new A_CmsTreeTabDataPreloader<CmsVfsEntryBean>() {
410
411            @SuppressWarnings("synthetic-access")
412            @Override
413            protected CmsVfsEntryBean createEntry(CmsObject innerCms, CmsResource resource) throws CmsException {
414
415                String title = innerCms.readPropertyObject(
416                    resource,
417                    CmsPropertyDefinition.PROPERTY_TITLE,
418                    false).getValue();
419                boolean isEditable = false;
420                try {
421                    isEditable = innerCms.hasPermissions(
422                        resource,
423                        CmsPermissionSet.ACCESS_WRITE,
424                        false,
425                        CmsResourceFilter.ALL);
426                } catch (CmsException e) {
427                    LOG.info(e.getLocalizedMessage(), e);
428                }
429
430                return internalCreateVfsEntryBean(innerCms, resource, title, true, isEditable, null, false);
431            }
432
433        };
434        Set<CmsResource> treeOpenResources = Sets.newHashSet();
435        if (vfsState != null) {
436
437            for (CmsUUID structureId : vfsState.getOpenItems()) {
438                try {
439                    treeOpenResources.add(cms.readResource(structureId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
440                } catch (CmsException e) {
441                    LOG.warn(e.getLocalizedMessage(), e);
442                }
443            }
444        }
445        CmsObject rootCms = null;
446        Set<CmsResource> folderSetResources = Sets.newHashSet();
447        try {
448            rootCms = OpenCms.initCmsObject(cms);
449            rootCms.getRequestContext().setSiteRoot("");
450            if (!((folders == null) || folders.isEmpty())) {
451                for (String folder : folders) {
452                    try {
453                        folderSetResources.add(rootCms.readResource(folder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
454                    } catch (CmsException e) {
455                        LOG.warn(e.getLocalizedMessage(), e);
456                    }
457                }
458            }
459        } catch (CmsException e1) {
460            LOG.error(e1.getLocalizedMessage(), e1);
461        }
462        try {
463            vfsPreloadData = vfsloader.preloadData(cms, treeOpenResources, folderSetResources);
464        } catch (CmsException e) {
465            LOG.error(e.getLocalizedMessage(), e);
466        }
467
468        return vfsPreloadData;
469
470    }
471
472    /**
473     * Returns the initial gallery settings.<p>
474     *
475     * @param request the current request
476     * @param config the gallery configuration
477     *
478     * @return the initial gallery settings
479     *
480     * @throws CmsRpcException if something goes wrong
481     */
482    public static CmsGalleryDataBean getInitialSettings(HttpServletRequest request, CmsGalleryConfiguration config)
483    throws CmsRpcException {
484
485        CmsGalleryService srv = new CmsGalleryService();
486        srv.setCms(CmsFlexController.getCmsObject(request));
487        srv.setRequest(request);
488        CmsGalleryDataBean result = null;
489        try {
490            result = srv.getInitialSettings(config);
491        } finally {
492            srv.clearThreadStorage();
493        }
494        return result;
495    }
496
497    /**
498     * Returns the initial search data.<p>
499     *
500     * @param request the current request
501     * @param config the gallery configuration
502     *
503     * @return the search data
504     */
505    public static CmsGallerySearchBean getSearch(HttpServletRequest request, CmsGalleryDataBean config) {
506
507        CmsGalleryService srv = new CmsGalleryService();
508        srv.setCms(CmsFlexController.getCmsObject(request));
509        srv.setRequest(request);
510        CmsGallerySearchBean result = null;
511        try {
512            result = srv.getSearch(config);
513        } finally {
514            srv.clearThreadStorage();
515        }
516        return result;
517    }
518
519    /**
520     * Gets the attribute name for a tree open state.<p>
521     *
522     * @param treeName the tree name
523     * @param treeToken the tree token
524     *
525     * @return the attribute name for the tree
526     */
527    public static String getTreeOpenStateAttributeName(String treeName, String treeToken) {
528
529        return "tree_" + treeName + "_" + treeToken;
530    }
531
532    /**
533     * Convenience method for reading the saved VFS tree state from the session.<p>
534     *
535     * @param request the current request
536     * @param treeToken the tree token (may be null)
537     *
538     * @return the saved tree open state (may be null)
539     */
540    public static CmsTreeOpenState getVfsTreeState(HttpServletRequest request, String treeToken) {
541
542        return (CmsTreeOpenState)request.getSession().getAttribute(
543            getTreeOpenStateAttributeName(I_CmsGalleryProviderConstants.TREE_VFS, treeToken));
544
545    }
546
547    /**
548     * Creates the VFS entry bean for a resource.<p>
549     *
550     * @param cms the CMS context to use
551     * @param resource the resource for which to create the VFS entry bean
552     * @param title the title
553     * @param isRoot true if this is a root entry
554     * @param isEditable true if this entry is editable
555     * @param children the children of the entry
556     * @param isMatch true if the VFS entry bean is a match for the quick search
557     *
558     * @return the created VFS entry bean
559     * @throws CmsException if something goes wrong
560     */
561    public static CmsVfsEntryBean internalCreateVfsEntryBean(
562        CmsObject cms,
563        CmsResource resource,
564        String title,
565        boolean isRoot,
566        boolean isEditable,
567        List<CmsVfsEntryBean> children,
568        boolean isMatch)
569    throws CmsException {
570
571        String rootPath = resource.getRootPath();
572        CmsUUID structureId = resource.getStructureId();
573        CmsVfsEntryBean result = new CmsVfsEntryBean(
574            rootPath,
575            structureId,
576            title,
577            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resource), resource.getName(), true),
578            isRoot,
579            isEditable,
580            children,
581            isMatch);
582        String siteRoot = null;
583        if (resource.isFolder()) {
584            cms = OpenCms.initCmsObject(cms);
585            cms.getRequestContext().setSiteRoot("");
586            List<CmsResource> realChildren = cms.getResourcesInFolder(
587                rootPath,
588                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
589            List<CmsResource> effectiveChildren = new ArrayList<CmsResource>();
590            for (CmsResource realChild : realChildren) {
591                if (realChild.isFolder()) {
592                    effectiveChildren.add(realChild);
593                }
594            }
595            if (effectiveChildren.isEmpty()) {
596                result.setChildren(new ArrayList<CmsVfsEntryBean>());
597            }
598        }
599
600        if (OpenCms.getSiteManager().startsWithShared(rootPath)) {
601            siteRoot = OpenCms.getSiteManager().getSharedFolder();
602        } else {
603            String tempSiteRoot = OpenCms.getSiteManager().getSiteRoot(rootPath);
604            if (tempSiteRoot != null) {
605                siteRoot = tempSiteRoot;
606            } else {
607                siteRoot = "";
608            }
609        }
610        result.setSiteRoot(siteRoot);
611        return result;
612    }
613
614    /**
615     * Helper function for getting the IDs of functions which do not fit into a given set of container type/width combinations.
616     *
617     * @param cms the current CMS context
618     * @param config the sitemap configuration
619     * @param containerInfo the information about available container type/width combinations
620     *
621     * @return the set of functions which should be excluded
622     */
623    private static Set<CmsUUID> getExcludedFunctionsForContainerInfo(
624        CmsObject cms,
625        CmsADEConfigData config,
626        CmsGalleryContainerInfo containerInfo) {
627
628        CmsFormatterConfigurationCacheState formatterCache = config.getCachedFormatters();
629        // start with all functions, then go through each item in the container info and remove formatters if they match that item
630        // -> we end up with the functions that don't match anything
631        Map<CmsUUID, I_CmsFormatterBean> remainingUnmatchedFunctions = new HashMap<>(
632            Maps.filterValues(
633                formatterCache.getFormatters(),
634                formatter -> formatter instanceof CmsFunctionFormatterBean));
635        for (CmsGalleryContainerInfo.Item item : containerInfo.getItems()) {
636            Iterator<Map.Entry<CmsUUID, I_CmsFormatterBean>> iterator = remainingUnmatchedFunctions.entrySet().iterator();
637            while (iterator.hasNext()) {
638                Map.Entry<CmsUUID, I_CmsFormatterBean> entry = iterator.next();
639                I_CmsFormatterBean formatter = entry.getValue();
640                if (CmsFormatterConfiguration.matchFormatter(formatter, item.getType(), item.getWidth())) {
641                    iterator.remove();
642                }
643            }
644        }
645        return new TreeSet<>(remainingUnmatchedFunctions.keySet());
646    }
647
648    /**
649     * Returns the resource types beans.<p>
650     *
651     * @param resourceTypes the resource types
652     * @param creatableTypes the creatable types
653     * @param deactivatedTypes the deactivated types
654     * @param typesForTypeTab the types which should be shown in the types tab according to the gallery configuration
655     *
656     * @return the resource types
657     */
658    public List<CmsResourceTypeBean> buildTypesList(
659        List<I_CmsResourceType> resourceTypes,
660        Set<String> creatableTypes,
661        Set<String> deactivatedTypes,
662        final List<String> typesForTypeTab) {
663
664        List<CmsResourceTypeBean> result = buildTypesList(resourceTypes, creatableTypes);
665
666        for (CmsResourceTypeBean typeBean : result) {
667            if ((typesForTypeTab != null) && (typesForTypeTab.size() > 0)) {
668                if (!typesForTypeTab.contains(typeBean.getType())) {
669                    if (typeBean.getVisibility() != TypeVisibility.hidden) {
670                        typeBean.setVisibility(TypeVisibility.showOptional);
671                    }
672                }
673            }
674            typeBean.setDeactivated(deactivatedTypes.contains(typeBean.getType()));
675        }
676        if ((typesForTypeTab != null) && (typesForTypeTab.size() > 0)) {
677            Collections.sort(result, new Comparator<CmsResourceTypeBean>() {
678
679                public int compare(CmsResourceTypeBean first, CmsResourceTypeBean second) {
680
681                    return ComparisonChain.start().compare(searchTypeRank(first), searchTypeRank(second)).compare(
682                        first.getTitle(),
683                        second.getTitle(),
684                        Collator.getInstance(getWorkplaceLocale())).compare(first.getType(), second.getType()).result();
685                }
686
687                int searchTypeRank(CmsResourceTypeBean type) {
688
689                    int index = typesForTypeTab.indexOf(type.getType());
690                    if (index == -1) {
691                        return Integer.MAX_VALUE;
692                    } else {
693                        return index;
694                    }
695                }
696            });
697
698        }
699        return result;
700    }
701
702    /**
703     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#deleteResource(java.lang.String)
704     */
705    public void deleteResource(String resourcePath) throws CmsRpcException {
706
707        try {
708            ensureLock(resourcePath);
709            getCmsObject().deleteResource(resourcePath, CmsResource.DELETE_PRESERVE_SIBLINGS);
710        } catch (Exception e) {
711            error(e);
712        }
713    }
714
715    /**
716     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getAdeViewModeConfiguration()
717     */
718    public CmsGalleryConfiguration getAdeViewModeConfiguration() {
719
720        CmsGalleryConfiguration result = new CmsGalleryConfiguration();
721        List<String> typeNames = new ArrayList<String>();
722
723        for (I_CmsResourceType type : OpenCms.getResourceManager().getResourceTypes()) {
724            Class<?> typeClass = type.getClass();
725            if (CmsResourceTypeXmlContent.class.isAssignableFrom(typeClass)
726                || CmsResourceTypeXmlPage.class.isAssignableFrom(typeClass)) {
727                continue;
728            }
729            if (type.getGalleryTypes().size() > 0) {
730                typeNames.add(type.getTypeName());
731            }
732        }
733        result.setSearchTypes(typeNames);
734        result.setResourceTypes(typeNames);
735        result.setGalleryMode(GalleryMode.adeView);
736        result.setGalleryStoragePrefix("" + GalleryMode.adeView);
737        result.setTabConfiguration(CmsGalleryTabConfiguration.resolve("selectDoc"));
738        return result;
739    }
740
741    /**
742     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getGalleries(java.lang.String, java.util.List)
743     */
744    public List<CmsGalleryFolderBean> getGalleries(String context, List<String> resourceTypes) {
745
746        return buildGalleriesList(context, readGalleryInfosByTypeNames(resourceTypes));
747    }
748
749    /**
750     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getGalleryActionInfo(java.lang.String)
751     */
752    public CmsGalleryActionInfo getGalleryActionInfo(String sitePath) throws CmsRpcException {
753
754        try {
755            CmsObject cms = getCmsObject();
756            try {
757                CmsResource folderRes = cms.readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION);
758                I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(folderRes);
759                String action = type.getConfiguration().get("gallery.upload.action");
760                return new CmsGalleryActionInfo(folderRes.getStructureId(), action);
761            } catch (CmsVfsResourceNotFoundException e) {
762                LOG.info(e.getLocalizedMessage(), e);
763                return null;
764            }
765        } catch (Throwable e) {
766            error(e);
767            return null;
768        }
769
770    }
771
772    /**
773     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getInfoForResource(java.lang.String, java.lang.String)
774     */
775    public CmsResultItemBean getInfoForResource(String linkPath, String locale) throws CmsRpcException {
776
777        CmsResultItemBean result = null;
778        CmsObject cms = getCmsObject();
779        CmsMessages messageBundle = Messages.get().getBundle(getWorkplaceLocale());
780        try {
781            if (new CmsUriSplitter(linkPath).getProtocol() != null) {
782                result = new CmsResultItemBean();
783                result.setTitle(messageBundle.key(Messages.GUI_EXTERNAL_LINK_0));
784                result.setSubTitle("");
785                result.setType(CmsResourceTypePointer.getStaticTypeName());
786                result.setBigIconClasses(
787                    CmsIconUtil.getIconClasses(CmsResourceTypePointer.getStaticTypeName(), null, false));
788            } else if (CmsStaticResourceHandler.isStaticResourceUri(linkPath)) {
789                result = new CmsResultItemBean();
790                result.setTitle(messageBundle.key(Messages.GUI_STATIC_RESOURCE_0));
791                result.setSubTitle(CmsStaticResourceHandler.removeStaticResourcePrefix(linkPath));
792                result.setType(CmsResourceTypeBinary.getStaticTypeName());
793                result.setBigIconClasses(
794                    CmsIconUtil.getIconClasses(CmsResourceTypeBinary.getStaticTypeName(), null, false));
795            } else {
796                boolean notFound = false;
797                String path = linkPath;
798                String siteRoot = OpenCms.getSiteManager().getSiteRoot(linkPath);
799                String oldSite = cms.getRequestContext().getSiteRoot();
800                try {
801                    if (siteRoot != null) {
802                        // only switch the site if needed
803                        cms.getRequestContext().setSiteRoot(siteRoot);
804                        // remove the site root, because the link manager call will append it anyway
805                        path = cms.getRequestContext().removeSiteRoot(linkPath);
806                    }
807                    // remove parameters, if not the link manager call might fail
808                    int pos = path.indexOf(CmsRequestUtil.URL_DELIMITER);
809                    int anchorPos = path.indexOf('#');
810                    if ((pos == -1) || ((anchorPos > -1) && (pos > anchorPos))) {
811                        pos = anchorPos;
812                    }
813                    if (pos > -1) {
814                        path = path.substring(0, pos);
815                    }
816                    // get the root path
817                    path = OpenCms.getLinkManager().getRootPath(cms, path);
818
819                } catch (Exception e) {
820                    notFound = true;
821                } finally {
822                    if (siteRoot != null) {
823                        cms.getRequestContext().setSiteRoot(oldSite);
824                    }
825                }
826                notFound = notFound || (path == null);
827                boolean isInTimeRange = true;
828                if (!notFound) {
829                    CmsObject rootCms = OpenCms.initCmsObject(cms);
830                    rootCms.getRequestContext().setSiteRoot("");
831                    try {
832                        CmsResource selectedResource = rootCms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION);
833                        long currentTime = System.currentTimeMillis();
834                        isInTimeRange = selectedResource.isReleasedAndNotExpired(currentTime);
835                        if (selectedResource.isFolder()) {
836                            result = new CmsResultItemBean();
837
838                            CmsJspNavElement folderNav = new CmsJspNavBuilder(rootCms).getNavigationForResource(
839                                selectedResource.getRootPath(),
840                                CmsResourceFilter.IGNORE_EXPIRATION);
841                            CmsResource defaultFileResource = null;
842                            if (folderNav.isInNavigation() && !folderNav.isNavigationLevel()) {
843                                try {
844                                    defaultFileResource = rootCms.readDefaultFile(
845                                        selectedResource,
846                                        CmsResourceFilter.ONLY_VISIBLE);
847                                } catch (Exception e) {
848                                    log(e.getMessage(), e);
849                                }
850                            }
851                            result.setBigIconClasses(
852                                CmsIconUtil.getIconClasses(
853                                    CmsIconUtil.getDisplayType(rootCms, selectedResource),
854                                    path,
855                                    false));
856                            CmsResource resourceForType = defaultFileResource != null
857                            ? defaultFileResource
858                            : selectedResource;
859                            result.setType(OpenCms.getResourceManager().getResourceType(resourceForType).getTypeName());
860                            if (defaultFileResource != null) {
861                                result.setSmallIconClasses(
862                                    CmsIconUtil.getIconClasses(
863                                        CmsIconUtil.getDisplayType(rootCms, defaultFileResource),
864                                        defaultFileResource.getName(),
865                                        true));
866                            }
867                            String title = folderNav.getProperty(CmsPropertyDefinition.PROPERTY_NAVTEXT);
868                            if (CmsStringUtil.isEmptyOrWhitespaceOnly(title)) {
869                                title = folderNav.getTitle();
870                            } else if (CmsStringUtil.isEmptyOrWhitespaceOnly(title)) {
871                                title = CmsResource.getName(path);
872                                if (title.contains("/")) {
873                                    title = title.substring(0, title.indexOf("/"));
874                                }
875                            }
876                            result.setTitle(title);
877                            try {
878                                String userName = cms.readUser(selectedResource.getUserLastModified()).getFullName();
879                                result.setUserLastModified(userName);
880                            } catch (CmsException e) {
881                                log(e.getMessage(), e);
882                            }
883                            Date date = new Date(selectedResource.getDateLastModified());
884                            String formattedDate = CmsDateUtil.getDateTime(
885                                date,
886                                DateFormat.MEDIUM,
887                                getWorkplaceLocale());
888                            result.setDateLastModified(formattedDate);
889
890                        } else {
891                            CmsGallerySearchResult resultItem = null;
892                            try {
893                                resultItem = CmsGallerySearch.searchByPath(
894                                    cms,
895                                    path,
896                                    CmsLocaleManager.getLocale(locale));
897                            } catch (CmsVfsResourceNotFoundException ex) {
898                                // ignore
899                            }
900                            notFound = resultItem == null;
901                            if (!notFound) {
902                                result = buildSingleSearchResultItem(getCmsObject(), resultItem, null, res -> false);
903                            }
904                        }
905                    } catch (CmsException ex) {
906                        notFound = true;
907                    }
908                }
909                if (notFound) {
910                    result = new CmsResultItemBean();
911                    result.setTitle(messageBundle.key(Messages.GUI_RESOURCE_NOT_FOUND_0));
912                    result.setSubTitle("");
913                    result.setType(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND);
914                    result.setBigIconClasses(
915                        CmsIconUtil.getIconClasses(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND, null, false));
916                } else if (!isInTimeRange && (result != null)) {
917                    result.setType(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND);
918                    result.setTitle(messageBundle.key(Messages.GUI_RESOURCE_OUT_OF_TIME_RANGE_1, result.getTitle()));
919                    result.setBigIconClasses(
920                        CmsIconUtil.getIconClasses(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND, null, false));
921                }
922            }
923        } catch (Throwable t) {
924            error(t);
925        }
926        return result;
927    }
928
929    /**
930     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getInitialSettings(org.opencms.ade.galleries.shared.CmsGalleryConfiguration)
931     */
932    public CmsGalleryDataBean getInitialSettings(CmsGalleryConfiguration conf) throws CmsRpcException {
933
934        try {
935            return getInitialSettingsInternal(conf);
936        } catch (Throwable t) {
937            error(t);
938            return null; // will never be reached
939        }
940    }
941
942    /**
943     * Returns the initial gallery data for the container page editor.<p>
944     *
945     * @param types the available resource types
946     * @param uri the page URI
947     * @param locale the content locale
948     *
949     * @return the gallery data
950     */
951    public CmsGalleryDataBean getInitialSettingsForContainerPage(
952        List<CmsResourceTypeBean> types,
953        String uri,
954        String locale) {
955
956        CmsGalleryDataBean data = null;
957        try {
958            data = new CmsGalleryDataBean();
959            boolean galleryShowInvalidDefault = Boolean.parseBoolean(
960                getWorkplaceSettings().getUserSettings().getAdditionalPreference(
961                    PREF_GALLERY_SHOW_INVALID_DEFAULT,
962                    true));
963            data.setIncludeExpiredDefault(galleryShowInvalidDefault);
964            data.setResultViewType(readResultViewType());
965            data.setMode(GalleryMode.ade);
966            data.setGalleryStoragePrefix("");
967            data.setLocales(buildLocalesMap());
968            data.setLocale(locale);
969
970            data.setVfsRootFolders(getRootEntries());
971
972            data.setScope(getWorkplaceSettings().getLastSearchScope());
973            data.setSortOrder(
974                getWorkplaceSettings().getLastGalleryResultOrder(CmsGalleryService.RESULT_ORDER_KEY_PAGE));
975
976            data.setTabIds(GalleryMode.ade.getTabs());
977            data.setReferenceSitePath(uri);
978            data.setTypes(types);
979            Map<String, CmsGalleryTypeInfo> adeGalleryTypeInfos = readGalleryInfosByTypeBeans(types);
980            data.setGalleries(buildGalleriesList(uri, adeGalleryTypeInfos));
981            data.setStartTab(GalleryTabId.cms_tab_types);
982            Set<String> folderFilter = readFolderFilters();
983            data.setStartFolderFilter(folderFilter);
984            if ((folderFilter != null) && !folderFilter.isEmpty()) {
985                try {
986                    data.setVfsPreloadData(generateVfsPreloadData(getCmsObject(), null, folderFilter));
987                } catch (Exception e) {
988                    LOG.error(e.getLocalizedMessage(), e);
989                }
990            }
991            CmsSiteSelectorOptionBuilder optionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
992            optionBuilder.addNormalSites(true, getWorkplaceSettings().getUserSettings().getStartFolder());
993            optionBuilder.addSharedSite();
994            data.setVfsSiteSelectorOptions(optionBuilder.getOptions());
995
996            CmsSiteSelectorOptionBuilder sitemapOptionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
997            sitemapOptionBuilder.addNormalSites(false, null);
998            if (data.getReferenceSitePath() != null) {
999                sitemapOptionBuilder.addCurrentSubsite(getCmsObject().addSiteRoot(data.getReferenceSitePath()));
1000            }
1001            data.setSitemapSiteSelectorOptions(sitemapOptionBuilder.getOptions());
1002            data.setDefaultScope(OpenCms.getWorkplaceManager().getGalleryDefaultScope());
1003            CmsCoreService service = new CmsCoreService();
1004            service.setCms(getCmsObject());
1005            data.setCategories(service.getCategoriesForSitePath(data.getReferenceSitePath()));
1006        } catch (Exception e) {
1007            LOG.error(e.getLocalizedMessage(), e);
1008        }
1009        return data;
1010    }
1011
1012    /**
1013     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSearch(org.opencms.ade.galleries.shared.CmsGalleryDataBean)
1014     */
1015    public CmsGallerySearchBean getSearch(CmsGalleryDataBean data) {
1016
1017        CmsGallerySearchBean result = null;
1018        // search within all available types
1019        List<String> types = getTypeNames(data);
1020        switch (data.getMode()) {
1021            case editor:
1022            case view:
1023            case adeView:
1024            case widget:
1025                String currentelement = data.getCurrentElement();
1026                try {
1027                    CmsSitemapEntryBean sitemapPreloadData = null;
1028                    CmsVfsEntryBean vfsPreloadData = null;
1029                    boolean disablePreview = false;
1030                    GalleryTabId startTab = null;
1031                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(currentelement)) {
1032                        log("looking up:" + currentelement);
1033                        // removing the servlet context if present
1034                        currentelement = CmsLinkManager.removeOpenCmsContext(currentelement);
1035                        // get search results given resource path
1036                        result = findResourceInGallery(currentelement, data);
1037                        if (result != null) {
1038                            sitemapPreloadData = result.getSitemapPreloadData();
1039                            vfsPreloadData = result.getVfsPreloadData();
1040                        }
1041                        if ((sitemapPreloadData != null)
1042                            && data.getTabConfiguration().getTabs().contains(GalleryTabId.cms_tab_sitemap)) {
1043                            startTab = GalleryTabId.cms_tab_sitemap;
1044                            disablePreview = true;
1045                        }
1046                    } else {
1047                        CmsTreeOpenState sitemapState = getSitemapTreeState(data.getTreeToken());
1048                        if (sitemapState != null) {
1049                            A_CmsTreeTabDataPreloader<CmsSitemapEntryBean> sitemaploader = new A_CmsTreeTabDataPreloader<CmsSitemapEntryBean>() {
1050
1051                                @Override
1052                                protected CmsSitemapEntryBean createEntry(CmsObject cms, CmsResource resource)
1053                                throws CmsException {
1054
1055                                    return internalCreateSitemapEntryBean(cms, resource);
1056                                }
1057
1058                                /**
1059                                 * @see org.opencms.ade.galleries.A_CmsTreeTabDataPreloader#getChildren(org.opencms.file.CmsResource)
1060                                 */
1061                                @Override
1062                                protected List<CmsResource> getChildren(CmsResource resource) throws CmsException {
1063
1064                                    return getSitemapSubEntryResources(resource.getRootPath());
1065                                }
1066
1067                            };
1068                            // in the case
1069                            sitemapPreloadData = sitemaploader.preloadData(
1070                                getCmsObject(),
1071                                Sets.newHashSet(
1072                                    readAll(sitemapState.getOpenItems(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)),
1073                                null);
1074                        }
1075                    }
1076                    if ((result == null) || (result.getResults() == null) || result.getResults().isEmpty()) {
1077                        result = new CmsGallerySearchBean();
1078                        result.setOriginalGalleryData(data);
1079                        result.setGalleryMode(data.getMode());
1080                        result.setGalleryStoragePrefix(data.getGalleryStoragePrefix());
1081                        result.setIgnoreSearchExclude(true);
1082                        String gallery = data.getStartGallery();
1083                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(gallery)) {
1084                            List<String> galleries = new ArrayList<String>();
1085                            galleries.add(gallery);
1086                            result.setGalleries(galleries);
1087                        }
1088                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(data.getStartFolder())) {
1089                            Set<String> folders = new HashSet<String>();
1090                            folders.add(data.getStartFolder());
1091                            result.setFolders(folders);
1092                        } else if (data.getStartFolderFilter() != null) {
1093                            result.setFolders(data.getStartFolderFilter());
1094                        }
1095                        result.setTypes(types);
1096                        result.setLocale(data.getLocale());
1097                        CmsGallerySearchScope scope = data.getScope();
1098                        if (scope == null) {
1099                            scope = OpenCms.getWorkplaceManager().getGalleryDefaultScope();
1100                        }
1101                        result.setSortOrder(data.getSortOrder().name());
1102                        result.setScope(scope);
1103                        result.setIncludeExpired(data.getIncludeExpiredDefault());
1104                        result = search(result);
1105                    }
1106                    result.setSitemapPreloadData(sitemapPreloadData);
1107                    result.setVfsPreloadData(vfsPreloadData);
1108                    result.setInitialTabId(startTab);
1109                    result.setDisablePreview(disablePreview);
1110                    if (types.size() > 1) {
1111                        // only remove types parameter if there is more than one type available
1112                        result.setTypes(null);
1113                    }
1114                } catch (CmsException e) {
1115                    logError(e);
1116                    result = null;
1117                }
1118                break;
1119            case ade:
1120            default:
1121                break;
1122        }
1123        return result;
1124    }
1125
1126    /**
1127     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSearch(CmsGallerySearchBean)
1128     */
1129    public CmsGallerySearchBean getSearch(CmsGallerySearchBean searchObj) throws CmsRpcException {
1130
1131        CmsGallerySearchBean gSearchObj = null;
1132
1133        try {
1134            gSearchObj = search(searchObj);
1135            getWorkplaceSettings().setLastSearchScope(searchObj.getScope());
1136            String resultOrderKey = convertModeToResultOrderKey(searchObj.getGalleryMode());
1137            getWorkplaceSettings().setLastGalleryResultOrder(
1138                resultOrderKey,
1139                SortParams.valueOf(searchObj.getSortOrder()));
1140            setLastOpenedGallery(searchObj);
1141        } catch (Throwable e) {
1142            error(e);
1143        }
1144
1145        return gSearchObj;
1146    }
1147
1148    /**
1149     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSubEntries(java.lang.String, boolean, java.lang.String)
1150     */
1151    public List<CmsSitemapEntryBean> getSubEntries(String rootPath, boolean isRoot, String filter)
1152    throws CmsRpcException {
1153
1154        try {
1155            return getSubEntriesInternal(rootPath, isRoot, filter);
1156        } catch (Throwable e) {
1157            error(e);
1158        }
1159        return null;
1160    }
1161
1162    /**
1163     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSubFolders(java.lang.String)
1164     */
1165    public List<CmsVfsEntryBean> getSubFolders(String rootPath) throws CmsRpcException {
1166
1167        try {
1168            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1169            cms.getRequestContext().setSiteRoot("");
1170            List<CmsVfsEntryBean> result = new ArrayList<CmsVfsEntryBean>();
1171            if (cms.existsResource(rootPath, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1172                CmsResource resource = cms.readResource(rootPath, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1173                List<CmsResource> resources = cms.getSubFolders(
1174                    resource.getRootPath(),
1175                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1176                for (CmsResource res : resources) {
1177                    String title = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
1178                    result.add(
1179                        internalCreateVfsEntryBean(
1180                            getCmsObject(),
1181                            res,
1182                            title,
1183                            false,
1184                            isEditable(cms, res),
1185                            null,
1186                            false));
1187                }
1188            }
1189            Collections.<CmsVfsEntryBean> sort(result, VFS_COMPARATOR);
1190            return result;
1191        } catch (Throwable e) {
1192            error(e);
1193        }
1194        return null;
1195    }
1196
1197    /**
1198     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#loadVfsEntryBean(java.lang.String, java.lang.String)
1199     */
1200    public CmsVfsEntryBean loadVfsEntryBean(String path, String filter) throws CmsRpcException {
1201
1202        try {
1203            if (CmsStringUtil.isEmpty(filter)) {
1204
1205                CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1206                cms.getRequestContext().setSiteRoot("");
1207                if (!cms.existsResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1208                    String startFolder = CmsStringUtil.joinPaths(
1209                        path,
1210                        getWorkplaceSettings().getUserSettings().getStartFolder());
1211                    if (cms.existsResource(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1212                        path = startFolder;
1213                    }
1214                }
1215                CmsResource optionRes = cms.readResource(path);
1216                String title = cms.readPropertyObject(
1217                    optionRes,
1218                    CmsPropertyDefinition.PROPERTY_TITLE,
1219                    false).getValue();
1220                if (CmsStringUtil.isEmpty(title)) {
1221                    title = path;
1222                }
1223                CmsVfsEntryBean entryBean = internalCreateVfsEntryBean(
1224                    getCmsObject(),
1225                    optionRes,
1226                    title,
1227                    true,
1228                    isEditable(cms, optionRes),
1229                    null,
1230                    false);
1231                return entryBean;
1232            } else {
1233                filter = filter.toLowerCase();
1234                CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1235                cms.getRequestContext().setSiteRoot("");
1236                if (!cms.existsResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1237                    String startFolder = CmsStringUtil.joinPaths(
1238                        path,
1239                        getWorkplaceSettings().getUserSettings().getStartFolder());
1240                    if (cms.existsResource(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1241                        path = startFolder;
1242                    }
1243                }
1244                CmsResource optionRes = cms.readResource(path);
1245                List<CmsResource> folders = cms.readResources(
1246                    optionRes.getRootPath(),
1247                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFolder());
1248                folders.add(optionRes);
1249                Set<CmsResource> folderSet = Sets.newHashSet(folders);
1250                List<CmsResource> titleResources = cms.readResourcesWithProperty(
1251                    path,
1252                    CmsPropertyDefinition.PROPERTY_TITLE);
1253                titleResources.retainAll(folderSet);
1254                Set<CmsResource> filterMatches = Sets.newHashSet();
1255                for (CmsResource folder : folderSet) {
1256                    if (folder.getName().toLowerCase().contains(filter)) {
1257                        filterMatches.add(folder);
1258                        titleResources.remove(folder); // we don't need to check the title if the name already matched
1259                    }
1260                }
1261                for (CmsResource titleRes : titleResources) {
1262                    CmsProperty prop = cms.readPropertyObject(titleRes, CmsPropertyDefinition.PROPERTY_TITLE, false);
1263                    String title = prop.getValue();
1264                    if ((title != null) && title.toLowerCase().contains(filter)) {
1265                        filterMatches.add(titleRes);
1266                    }
1267                }
1268                Set<String> filterMatchAncestorPaths = Sets.newHashSet();
1269                if (filterMatches.size() > 0) {
1270                    for (CmsResource filterMatch : filterMatches) {
1271                        String currentPath = filterMatch.getRootPath();
1272                        while (currentPath != null) {
1273                            filterMatchAncestorPaths.add(currentPath);
1274                            currentPath = CmsResource.getParentFolder(currentPath);
1275                        }
1276                    }
1277                    Set<String> allPaths = Sets.newHashSet();
1278                    Set<String> parentPaths = Sets.newHashSet();
1279                    for (CmsResource folder : folderSet) {
1280                        allPaths.add(folder.getRootPath());
1281                        String parent = CmsResource.getParentFolder(folder.getRootPath());
1282                        if (parent != null) {
1283                            parentPaths.add(parent);
1284                        }
1285                    }
1286                    parentPaths.retainAll(allPaths);
1287
1288                    Set<CmsResource> filterMatchAncestors = Sets.newHashSet();
1289                    for (CmsResource folderRes : folderSet) {
1290                        if (filterMatchAncestorPaths.contains(folderRes.getRootPath())) {
1291                            filterMatchAncestors.add(folderRes);
1292                        }
1293                    }
1294                    Map<String, CmsResource> resourcesByPath = Maps.newHashMap();
1295                    for (CmsResource treeRes : filterMatchAncestors) {
1296                        resourcesByPath.put(treeRes.getRootPath(), treeRes);
1297                    }
1298                    Multimap<CmsResource, CmsResource> childMap = ArrayListMultimap.create();
1299                    for (CmsResource res : filterMatchAncestors) {
1300                        CmsResource parent = resourcesByPath.get(CmsResource.getParentFolder(res.getRootPath()));
1301                        if (parent != null) {
1302                            childMap.put(parent, res);
1303                        }
1304                    }
1305                    return buildVfsEntryBeanForQuickSearch(optionRes, childMap, filterMatches, parentPaths, true);
1306                } else {
1307                    return null;
1308                }
1309            }
1310        } catch (Throwable e) {
1311            error(e);
1312            return null;
1313        }
1314    }
1315
1316    /**
1317     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#saveResultViewType(java.lang.String)
1318     */
1319    public void saveResultViewType(String resultViewType) {
1320
1321        CmsUser user = getCmsObject().getRequestContext().getCurrentUser();
1322        user.setAdditionalInfo(RESULT_VIEW_TYPE_ADD_INFO_KEY, resultViewType);
1323        try {
1324            getCmsObject().writeUser(user);
1325        } catch (CmsException e) {
1326            LOG.error(e.getLocalizedMessage(), e);
1327        }
1328    }
1329
1330    /**
1331     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#saveTreeOpenState(java.lang.String, java.lang.String, java.lang.String, java.util.Set)
1332     */
1333    public void saveTreeOpenState(String treeName, String treeToken, String siteRoot, Set<CmsUUID> openItems)
1334    throws CmsRpcException {
1335
1336        try {
1337            HttpServletRequest request = getRequest();
1338            HttpSession session = request.getSession();
1339            String attributeName = getTreeOpenStateAttributeName(treeName, treeToken);
1340            if (openItems.isEmpty()) {
1341                CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1342                cms.getRequestContext().setSiteRoot("");
1343                CmsResource resource = cms.readResource(siteRoot);
1344                openItems = Sets.newHashSet(resource.getStructureId());
1345            }
1346            CmsTreeOpenState treeState = new CmsTreeOpenState(treeName, siteRoot, openItems);
1347            session.setAttribute(attributeName, treeState);
1348        } catch (Throwable e) {
1349            error(e);
1350        }
1351    }
1352
1353    /**
1354     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#updateIndex()
1355     */
1356    public void updateIndex() throws CmsRpcException {
1357
1358        try {
1359            OpenCms.getSearchManager().updateOfflineIndexes();
1360        } catch (Throwable e) {
1361            error(e);
1362        }
1363    }
1364
1365    /**
1366     * Gets an initialized CmsObject to be used for the actual search for a given search bean.<p>
1367     *
1368     * @param searchObj the search object
1369     * @return the initialized CmsObject
1370     *
1371     * @throws CmsException if something goes wrong
1372     */
1373    protected CmsObject getSearchCms(CmsGallerySearchBean searchObj) throws CmsException {
1374
1375        CmsObject searchCms = getCmsObject();
1376        if (searchObj.isIncludeExpired()) {
1377            searchCms = OpenCms.initCmsObject(getCmsObject());
1378            searchCms.getRequestContext().setRequestTime(CmsResource.DATE_RELEASED_EXPIRED_IGNORE);
1379        }
1380        return searchCms;
1381    }
1382
1383    /**
1384     * Gets the sitemap sub entries for a given path as resources.<p>
1385     *
1386     * @param rootPath the root path
1387     * @return the sitemap sub entry resources
1388     * @throws CmsException if something goes wrong
1389     */
1390    protected List<CmsResource> getSitemapSubEntryResources(String rootPath) throws CmsException {
1391
1392        CmsObject rootCms = OpenCms.initCmsObject(getCmsObject());
1393        List<CmsResource> result = new ArrayList<CmsResource>();
1394        rootCms.getRequestContext().setSiteRoot("");
1395        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(rootCms);
1396        for (CmsJspNavElement navElement : navBuilder.getNavigationForFolder(
1397            rootPath,
1398            Visibility.all,
1399            CmsResourceFilter.ONLY_VISIBLE)) {
1400            if ((navElement != null) && navElement.isInNavigation()) {
1401                result.add(navElement.getResource());
1402            }
1403        }
1404        return result;
1405    }
1406
1407    /**
1408     * Internal method for getting sitemap sub entries for a given root path.<p>
1409     *
1410     * @param rootPath the root path
1411     * @param isRoot true if this method is used to get the root entries of a sitemap
1412     * @param filter the filter string (only relevant if isRoot is true)
1413     * @return the list of sitemap sub-entry beans
1414     *
1415     * @throws CmsException if something goes wrong
1416     */
1417    protected List<CmsSitemapEntryBean> getSubEntriesInternal(String rootPath, boolean isRoot, String filter)
1418    throws CmsException {
1419
1420        CmsObject rootCms = OpenCms.initCmsObject(getCmsObject());
1421        rootCms.getRequestContext().setSiteRoot("");
1422        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(rootCms);
1423        if (isRoot) {
1424            if (CmsStringUtil.isEmpty(filter)) {
1425                List<CmsSitemapEntryBean> result = new ArrayList<CmsSitemapEntryBean>();
1426                for (CmsJspNavElement navElement : navBuilder.getNavigationForFolder(
1427                    rootPath,
1428                    Visibility.all,
1429                    CmsResourceFilter.ONLY_VISIBLE)) {
1430                    if ((navElement != null) && navElement.isInNavigation()) {
1431                        CmsSitemapEntryBean nextEntry = prepareSitemapEntry(rootCms, navElement, false, true);
1432                        result.add(nextEntry);
1433                    }
1434                }
1435                CmsJspNavElement navElement = navBuilder.getNavigationForResource(
1436                    rootPath,
1437                    CmsResourceFilter.ONLY_VISIBLE);
1438                if (navElement == null) {
1439                    return result;
1440                }
1441                CmsSitemapEntryBean root = prepareSitemapEntry(rootCms, navElement, isRoot, true);
1442                root.setChildren(result);
1443                return Collections.singletonList(root);
1444            } else {
1445                CmsGalleryFilteredNavTreeBuilder navTreeBuilder = new CmsGalleryFilteredNavTreeBuilder(
1446                    rootCms,
1447                    rootPath);
1448                navTreeBuilder.initTree(filter);
1449                if (navTreeBuilder.hasMatches()) {
1450                    return Lists.newArrayList(convertNavigationTreeToBean(rootCms, navTreeBuilder.getRoot(), true));
1451                } else {
1452                    return Lists.newArrayList();
1453                }
1454            }
1455        } else {
1456            List<CmsSitemapEntryBean> result = new ArrayList<CmsSitemapEntryBean>();
1457            for (CmsJspNavElement navElement : navBuilder.getNavigationForFolder(
1458                rootPath,
1459                Visibility.all,
1460                CmsResourceFilter.ONLY_VISIBLE)) {
1461                if ((navElement != null) && navElement.isInNavigation()) {
1462                    CmsSitemapEntryBean nextEntry = prepareSitemapEntry(rootCms, navElement, false, true);
1463                    result.add(nextEntry);
1464                }
1465            }
1466            return result;
1467        }
1468    }
1469
1470    /**
1471     * Gets the type names from the gallery data bean.<p>
1472     *
1473     * @param data the gallery data bean
1474     * @return the type names
1475     */
1476    protected List<String> getTypeNames(CmsGalleryDataBean data) {
1477
1478        List<String> types = new ArrayList<String>();
1479        for (CmsResourceTypeBean info : data.getTypes()) {
1480            types.add(info.getType());
1481        }
1482        return types;
1483    }
1484
1485    /**
1486     * Checks whether a given resource is a sitemap entry.<p>
1487     *
1488     * This is used for preselected entries in the gallery widget.<p>
1489     *
1490     *
1491     * @param cms the current CMS context
1492     * @param resource the resource to check
1493     * @return true if the resource is a sitemap entry
1494     *
1495     * @throws CmsException if something goes wrong
1496     */
1497    protected boolean isSitemapEntry(CmsObject cms, CmsResource resource) throws CmsException {
1498
1499        CmsResourceFilter filter = CmsResourceFilter.ONLY_VISIBLE_NO_DELETED;
1500        List<CmsResource> ancestors = new ArrayList<CmsResource>();
1501        CmsResource currentResource = resource;
1502        String siteRoot = OpenCms.getSiteManager().getSiteRoot(resource.getRootPath());
1503        if (CmsStringUtil.isEmpty(siteRoot)) {
1504            return false;
1505        }
1506        while (true) {
1507            CmsResource parent = cms.readParentFolder(currentResource.getStructureId());
1508            if ((parent == null) || !cms.existsResource(parent.getStructureId(), filter)) {
1509                break;
1510            }
1511            ancestors.add(parent);
1512            if (CmsStringUtil.comparePaths(siteRoot, parent.getRootPath())) {
1513                break;
1514            }
1515            currentResource = parent;
1516        }
1517        Collections.reverse(ancestors);
1518        boolean first = true;
1519        for (CmsResource ancestor : ancestors) {
1520            if (first) {
1521                if (null == OpenCms.getSiteManager().getSiteRoot(ancestor.getRootPath())) {
1522                    return false;
1523                }
1524            } else {
1525                if (!hasNavigationProperty(cms, ancestor)) {
1526                    return false;
1527                }
1528            }
1529            first = false;
1530        }
1531        if (resource.isFile()) {
1532            if (ancestors.isEmpty()) {
1533                return false;
1534            }
1535            CmsResource defaultFile = cms.readDefaultFile(ancestors.get(ancestors.size() - 1), filter);
1536            if (!resource.equals(defaultFile)) {
1537                return false;
1538            }
1539        } else {
1540            if (!hasNavigationProperty(cms, resource)) {
1541                return false;
1542            }
1543        }
1544        return true;
1545    }
1546
1547    /**
1548     * Reads the resources for a collection of structure ids and returns the list of resources which could be read.<p>
1549     *
1550     * @param structureIds the structure ids for which we want to read the resources
1551     * @param filter the filter used to read the resource
1552     *
1553     * @return the list of resources for the given structure id
1554     */
1555    protected List<CmsResource> readAll(Collection<CmsUUID> structureIds, CmsResourceFilter filter) {
1556
1557        List<CmsResource> result = new ArrayList<CmsResource>();
1558        for (CmsUUID id : structureIds) {
1559            try {
1560                result.add(getCmsObject().readResource(id, filter));
1561            } catch (CmsException e) {
1562                LOG.info(e.getLocalizedMessage(), e);
1563            }
1564        }
1565        return result;
1566    }
1567
1568    /**
1569     * Gets the sitemap tree open state.<p>
1570     *
1571     * @param treeToken the tree token to use
1572     *
1573     * @return the sitemap tree open state
1574     */
1575    CmsTreeOpenState getSitemapTreeState(String treeToken) {
1576
1577        return (CmsTreeOpenState)(getRequest().getSession().getAttribute(
1578            getTreeOpenStateAttributeName(I_CmsGalleryProviderConstants.TREE_SITEMAP, treeToken)));
1579    }
1580
1581    /**
1582     * Gets the VFS tree open state.<p>
1583     *
1584     * @param treeToken the tree token
1585     *
1586     * @return the VFS tree open state
1587     */
1588    CmsTreeOpenState getVfsTreeState(String treeToken) {
1589
1590        return (CmsTreeOpenState)(getRequest().getSession().getAttribute(
1591            getTreeOpenStateAttributeName(I_CmsGalleryProviderConstants.TREE_VFS, treeToken)));
1592    }
1593
1594    /**
1595     * Returns the workplace locale from the current user's settings.<p>
1596     *
1597     * @return the workplace locale
1598     */
1599    Locale getWorkplaceLocale() {
1600
1601        if (m_wpLocale == null) {
1602            m_wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
1603        }
1604        return m_wpLocale;
1605    }
1606
1607    /**
1608     * Creates the sitemap entry bean for a resource.<p>
1609     *
1610     * @param cms the current CMS context
1611     * @param resource the resource for which the sitemap entry bean should be created
1612     *
1613     * @return the created sitemap entry bean
1614     *
1615     * @throws CmsException if something goes wrong
1616     */
1617    CmsSitemapEntryBean internalCreateSitemapEntryBean(CmsObject cms, CmsResource resource) throws CmsException {
1618
1619        cms = OpenCms.initCmsObject(cms);
1620        cms.getRequestContext().setSiteRoot("");
1621        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms);
1622        CmsJspNavElement entry = navBuilder.getNavigationForResource(resource.getRootPath());
1623        if (entry == null) {
1624            // may be null for expired resources
1625            return null;
1626        }
1627        return prepareSitemapEntry(cms, entry, false, true);
1628    }
1629
1630    /**
1631     * Checks if the current user has write permissions on the given resource.<p>
1632     *
1633     * @param cms the current cms context
1634     * @param resource the resource to check
1635     *
1636     * @return <code>true</code> if the current user has write permissions on the given resource
1637     */
1638    boolean isEditable(CmsObject cms, CmsResource resource) {
1639
1640        try {
1641            return cms.hasPermissions(resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
1642        } catch (CmsException e) {
1643            return false;
1644        }
1645    }
1646
1647    /**
1648     * Adds galleries for a given type.<p>
1649     *
1650     * @param galleryTypeInfos the gallery type infos
1651     * @param typeName the type name
1652     *
1653     * @throws CmsLoaderException if something goes wrong
1654     */
1655    @SuppressWarnings("deprecation")
1656    private void addGalleriesForType(Map<String, CmsGalleryTypeInfo> galleryTypeInfos, String typeName)
1657    throws CmsLoaderException {
1658
1659        I_CmsResourceType contentType = getResourceManager().getResourceType(typeName);
1660        for (I_CmsResourceType galleryType : contentType.getGalleryTypes()) {
1661
1662            if (galleryTypeInfos.containsKey(galleryType.getTypeName())) {
1663                CmsGalleryTypeInfo typeInfo = galleryTypeInfos.get(galleryType.getTypeName());
1664                typeInfo.addContentType(contentType);
1665            } else {
1666                CmsGalleryTypeInfo typeInfo;
1667
1668                typeInfo = new CmsGalleryTypeInfo(
1669                    galleryType,
1670                    contentType,
1671                    getGalleriesByType(galleryType.getTypeId()));
1672
1673                galleryTypeInfos.put(galleryType.getTypeName(), typeInfo);
1674            }
1675
1676        }
1677    }
1678
1679    /**
1680     * Returns the map with the available galleries.<p>
1681     *
1682     * The map uses gallery path as the key and stores the CmsGalleriesListInfoBean as the value.<p>
1683     * @param contextPath the site path used as the current context
1684     * @param galleryTypes the galleries
1685     *
1686     * @return the map with gallery info beans
1687     */
1688    private List<CmsGalleryFolderBean> buildGalleriesList(
1689        String contextPath,
1690        Map<String, CmsGalleryTypeInfo> galleryTypes) {
1691
1692        CmsObject cms = getCmsObject();
1693        Locale wpLocale = getWorkplaceLocale();
1694        String rootPath = cms.getRequestContext().addSiteRoot(contextPath);
1695        CmsADEConfigData sitemapConfig = OpenCms.getADEManager().lookupConfigurationWithCache(cms, rootPath);
1696        String subsitePath = sitemapConfig.getBasePath();
1697        CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(rootPath);
1698
1699        List<CmsGalleryFolderBean> list = new ArrayList<CmsGalleryFolderBean>();
1700        if (galleryTypes == null) {
1701            return list;
1702        }
1703        for (Entry<String, CmsGalleryTypeInfo> ent : galleryTypes.entrySet()) {
1704            CmsGalleryTypeInfo tInfo = ent.getValue();
1705            ArrayList<String> contentTypes = new ArrayList<String>();
1706            Iterator<I_CmsResourceType> it = tInfo.getContentTypes().iterator();
1707            while (it.hasNext()) {
1708                contentTypes.add(String.valueOf(it.next().getTypeName()));
1709            }
1710            for (CmsResource res : tInfo.getGalleries()) {
1711                CmsGalleryFolderBean bean = new CmsGalleryFolderBean();
1712                String sitePath = getCmsObject().getSitePath(res);
1713                String title = "";
1714                try {
1715                    // read the gallery title
1716                    title = getCmsObject().readPropertyObject(
1717                        sitePath,
1718                        CmsPropertyDefinition.PROPERTY_TITLE,
1719                        false,
1720                        getWorkplaceLocale()).getValue("");
1721                } catch (CmsException e) {
1722                    // error reading title property
1723                    logError(e);
1724                }
1725                // sitepath as gallery id
1726                bean.setPath(sitePath);
1727                bean.setId(res.getStructureId());
1728                // content types
1729                bean.setContentTypes(contentTypes);
1730                // title
1731                bean.setTitle(title);
1732                CmsGalleryGroup group = null;
1733                String groupLabel = null;
1734                if ((site != null)
1735                    && (subsitePath != null)
1736                    && CmsStringUtil.isPrefixPath(subsitePath, res.getRootPath())
1737                    && !new CmsPath(subsitePath).equals(new CmsPath(site.getSiteRoot()))) {
1738                    // we are in a proper subsite, not just the site itself
1739                    group = CmsGalleryGroup.subsite;
1740
1741                    String labelSuffix = cms.getRequestContext().removeSiteRoot(subsitePath);
1742                    try {
1743                        Map<String, String> properties = CmsProperty.toMap(
1744                            cms.readPropertyObjects(cms.getRequestContext().removeSiteRoot(subsitePath), false));
1745                        for (String propName : new String[] {
1746                            CmsPropertyDefinition.PROPERTY_TITLE,
1747                            CmsPropertyDefinition.PROPERTY_NAVTEXT}) {
1748                            String propValue = properties.get(propName);
1749                            if (propValue != null) {
1750                                labelSuffix = propValue;
1751                                break;
1752                            }
1753                        }
1754                    } catch (Exception e) {
1755                        LOG.error(e.getLocalizedMessage(), e);
1756                    }
1757                    groupLabel = Messages.get().getBundle(wpLocale).key(
1758                        Messages.GUI_GALLERIES_GROUP_SUBSITE_1,
1759                        labelSuffix);
1760                } else if ((site != null) && CmsStringUtil.isPrefixPath(site.getSiteRoot(), res.getRootPath())) {
1761                    group = CmsGalleryGroup.site;
1762                    String labelSuffix;
1763                    labelSuffix = site.getTitle();
1764                    if (CmsStringUtil.isEmptyOrWhitespaceOnly(labelSuffix)) {
1765                        labelSuffix = site.getSiteRoot();
1766                    }
1767                    groupLabel = Messages.get().getBundle(wpLocale).key(
1768                        Messages.GUI_GALLERIES_GROUP_SITE_1,
1769                        labelSuffix);
1770                } else if (CmsStringUtil.isPrefixPath(CmsResource.VFS_FOLDER_SYSTEM, res.getRootPath())
1771                    || OpenCms.getSiteManager().startsWithShared(res.getRootPath())) {
1772                    group = CmsGalleryGroup.shared;
1773                    groupLabel = Messages.get().getBundle(wpLocale).key(Messages.GUI_GALLERIES_GROUP_SHARED_0);
1774                } else {
1775                    group = CmsGalleryGroup.other;
1776                    groupLabel = Messages.get().getBundle(wpLocale).key(Messages.GUI_GALLERIES_GROUP_OTHER_0);
1777                }
1778                bean.setGroup(group);
1779                bean.setGroupLabel(groupLabel);
1780                bean.setResourceType(tInfo.getResourceType().getTypeName());
1781                bean.setUploadAction(tInfo.getResourceType().getConfiguration().get("gallery.upload.action"));
1782
1783                boolean isOptimizeGalleryType = Arrays.asList("imagegallery", "downloadgallery").stream().anyMatch(
1784                    typeName -> OpenCms.getResourceManager().matchResourceType(typeName, res.getTypeId()));
1785
1786                // For performance reasons, we only do a general role check for EDITOR which does not take the concrete gallery path or context path into account.
1787                bean.setOptimizable(
1788                    OpenCms.getRoleManager().hasRole(getCmsObject(), CmsRole.EDITOR) && isOptimizeGalleryType);
1789
1790                bean.setEditable(isEditable(getCmsObject(), res));
1791                bean.setBigIconClasses(
1792                    CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(getCmsObject(), res), sitePath, false));
1793                list.add(bean);
1794            }
1795        }
1796        return list;
1797    }
1798
1799    /**
1800     * Returns a map with the available locales.<p>
1801     *
1802     * The map entry key is the current locale and the value the localized nice name.<p>
1803     *
1804     * @return the map representation of all available locales
1805     */
1806    private Map<String, String> buildLocalesMap() {
1807
1808        TreeMap<String, String> localesMap = new TreeMap<String, String>();
1809        Iterator<Locale> it = OpenCms.getLocaleManager().getAvailableLocales().iterator();
1810        while (it.hasNext()) {
1811            Locale locale = it.next();
1812            localesMap.put(locale.toString(), locale.getDisplayName(getWorkplaceLocale()));
1813        }
1814        return localesMap;
1815    }
1816
1817    /**
1818     * Returns the list of beans for the given search results.<p>
1819     *
1820     * @param searchResult the list of search results
1821     * @param presetResult the search result which corresponds to a preset value in the editor
1822     * @param checkDeactivated checks if search results should be shown as deactivated
1823     *
1824     * @return the list with the current search results
1825     */
1826    private List<CmsResultItemBean> buildSearchResultList(
1827        List<CmsGallerySearchResult> searchResult,
1828        CmsGallerySearchResult presetResult,
1829        Predicate<CmsResource> checkDeactivated) {
1830
1831        ArrayList<CmsResultItemBean> list = new ArrayList<CmsResultItemBean>();
1832        if ((searchResult == null) || (searchResult.size() == 0)) {
1833            return list;
1834        }
1835        CmsObject cms = getCmsObject();
1836        for (CmsGallerySearchResult sResult : searchResult) {
1837            try {
1838                CmsResultItemBean bean = buildSingleSearchResultItem(cms, sResult, presetResult, checkDeactivated);
1839                list.add(bean);
1840            } catch (Exception e) {
1841                logError(e);
1842            }
1843        }
1844        return list;
1845    }
1846
1847    /**
1848     * Builds a single search result list item for the client from a server-side search result.<p>
1849     *
1850     * @param cms the current CMS context
1851     * @param sResult the server-side search result
1852     * @param presetResult the preselected result
1853     * @param checkDeactivated checks if search results should be shown as deactivated
1854     *
1855     * @return the client side search result item
1856     *
1857     * @throws CmsException if something goes wrong
1858     * @throws ParseException if date parsing fails
1859     */
1860    private CmsResultItemBean buildSingleSearchResultItem(
1861        CmsObject cms,
1862        CmsGallerySearchResult sResult,
1863        CmsGallerySearchResult presetResult,
1864        Predicate<CmsResource> checkDeactivated)
1865    throws CmsException, ParseException {
1866
1867        Locale wpLocale = getWorkplaceLocale();
1868        CmsResultItemBean bean = new CmsResultItemBean();
1869        if (sResult == presetResult) {
1870            bean.setPreset(true);
1871        }
1872        bean.setReleasedAndNotExpired(sResult.isReleaseAndNotExpired(cms));
1873        String path = sResult.getPath();
1874        path = cms.getRequestContext().removeSiteRoot(path);
1875
1876        // resource path as id
1877        bean.setPath(path);
1878
1879        // title
1880        String rawTitle = CmsStringUtil.isEmptyOrWhitespaceOnly(sResult.getTitle())
1881        ? CmsResource.getName(sResult.getPath())
1882        : sResult.getTitle();
1883        bean.setTitle(rawTitle);
1884        bean.setRawTitle(rawTitle);
1885        // resource type
1886        bean.setType(sResult.getResourceType());
1887        CmsResource resultResource = cms.readResource(
1888            new CmsUUID(sResult.getStructureId()),
1889            CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1890        bean.setBigIconClasses(
1891            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resultResource), path, false));
1892        String detailType = CmsResourceIcon.getDefaultFileOrDetailType(cms, resultResource);
1893        if (detailType != null) {
1894            bean.setSmallIconClasses(CmsIconUtil.getIconClasses(detailType, null, true));
1895        }
1896        // structured id
1897        bean.setClientId(sResult.getStructureId());
1898
1899        CmsVfsService.addLockInfo(cms, resultResource, bean);
1900        String extension = CmsResource.getExtension(resultResource.getRootPath());
1901        String suffix = extension != null ? "." + extension : "";
1902
1903        String permalinkId = sResult.getStructureId().toString();
1904        String permalink = CmsStringUtil.joinPaths(
1905            OpenCms.getSystemInfo().getOpenCmsContext(),
1906            CmsPermalinkResourceHandler.PERMALINK_HANDLER,
1907            permalinkId) + suffix;
1908
1909        bean.setViewLink(permalink);
1910        // set nice resource type name as subtitle
1911        I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(sResult.getResourceType());
1912        String resourceTypeDisplayName = CmsWorkplaceMessages.getResourceTypeName(wpLocale, type.getTypeName());
1913        String description = sResult.getDescription();
1914        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(description)) {
1915            bean.setDescription(description);
1916            bean.addAdditionalInfo(
1917                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DESCRIPTION_0),
1918                description);
1919            if (sResult.getResourceType().equals(CmsResourceTypeFunctionConfig.TYPE_NAME)) {
1920                bean.setSubTitle(description);
1921            }
1922        } else {
1923            bean.setDescription(resourceTypeDisplayName);
1924        }
1925        bean.setUserLastModified(sResult.getUserLastModified());
1926        Date lastModDate = sResult.getDateLastModified();
1927        String formattedDate = lastModDate != null
1928        ? CmsDateUtil.getDateTime(lastModDate, DateFormat.MEDIUM, wpLocale)
1929        : "";
1930        bean.setDateLastModified(formattedDate);
1931        if (!type.getTypeName().equals(CmsResourceTypeImage.getStaticTypeName())) {
1932            bean.addAdditionalInfo(
1933                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_RESOURCE_TYPE_0),
1934                resourceTypeDisplayName);
1935        }
1936        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(sResult.getExcerpt())) {
1937            bean.addAdditionalInfo(
1938                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_EXCERPT_0),
1939                sResult.getExcerpt(),
1940                CmsListInfoBean.CSS_CLASS_MULTI_LINE);
1941        }
1942        if (type instanceof CmsResourceTypeImage) {
1943            CmsProperty copyrightProp = cms.readPropertyObject(
1944                resultResource,
1945                CmsPropertyDefinition.PROPERTY_COPYRIGHT,
1946                false);
1947            if (!copyrightProp.isNullProperty()) {
1948                bean.addAdditionalInfo(
1949                    Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_COPYRIGHT_0),
1950                    copyrightProp.getValue());
1951            }
1952            CmsProperty imageDimensionProp = cms.readPropertyObject(
1953                resultResource,
1954                CmsPropertyDefinition.PROPERTY_IMAGE_SIZE,
1955                false);
1956            if (!imageDimensionProp.isNullProperty()) {
1957                String dimensions = imageDimensionProp.getValue();
1958                dimensions = dimensions.substring(2).replace(",h:", " x ");
1959                bean.setDimension(dimensions);
1960                bean.addAdditionalInfo(
1961                    Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DIMENSION_0),
1962                    dimensions);
1963            }
1964        }
1965
1966        if (type instanceof CmsResourceTypeXmlContent) {
1967            CmsProperty elementModelProperty = cms.readPropertyObject(
1968                resultResource,
1969                CmsPropertyDefinition.PROPERTY_ELEMENT_MODEL,
1970                true);
1971            if (!elementModelProperty.isNullProperty()) {
1972                if (Boolean.valueOf(elementModelProperty.getValue()).booleanValue()) {
1973                    bean.setIsCopyModel(true);
1974                }
1975            }
1976        }
1977        bean.setResourceState(resultResource.getState());
1978        bean.addAdditionalInfo(
1979            Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_SIZE_0),
1980            (sResult.getLength() / 1000) + " kb");
1981        if (lastModDate != null) {
1982            bean.addAdditionalInfo(
1983                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DATE_CHANGED_0),
1984                CmsDateUtil.getDate(lastModDate, DateFormat.SHORT, getWorkplaceLocale()));
1985        }
1986        if ((sResult.getDateExpired().getTime() != CmsResource.DATE_EXPIRED_DEFAULT)
1987            && !sResult.getDateExpired().equals(CmsSearchFieldMapping.getDefaultDateExpired())) {
1988            bean.addAdditionalInfo(
1989                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DATE_EXPIRED_0),
1990                CmsDateUtil.getDate(sResult.getDateExpired(), DateFormat.SHORT, getWorkplaceLocale()));
1991        }
1992
1993        bean.setNoEditReson(
1994            new CmsResourceUtil(cms, resultResource).getNoEditReason(
1995                OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)));
1996        bean.setMarkChangedState(true);
1997        if (checkDeactivated.test(resultResource)) {
1998            bean.setDeactivated(true);
1999        }
2000        return bean;
2001    }
2002
2003    /**
2004     * Generates a map with all available content types.<p>
2005     *
2006     * The map uses resource type name as the key and stores the CmsTypesListInfoBean as the value.
2007     *
2008     * @param types the resource types
2009     * @param creatableTypes the creatable types
2010     *
2011     * @return the map containing the available resource types
2012     */
2013    private List<CmsResourceTypeBean> buildTypesList(List<I_CmsResourceType> types, Set<String> creatableTypes) {
2014
2015        ArrayList<CmsResourceTypeBean> list = new ArrayList<CmsResourceTypeBean>();
2016        if (types == null) {
2017            return list;
2018        }
2019        Map<I_CmsResourceType, I_CmsPreviewProvider> typeProviderMapping = getPreviewProviderForTypes(types);
2020        Iterator<I_CmsResourceType> it = types.iterator();
2021        while (it.hasNext()) {
2022
2023            I_CmsResourceType type = it.next();
2024            try {
2025                CmsResourceTypeBean bean = createTypeBean(
2026                    type,
2027                    typeProviderMapping.get(type),
2028                    creatableTypes.contains(type.getTypeName()));
2029                list.add(bean);
2030            } catch (Exception e) {
2031                if (type != null) {
2032                    log(
2033                        Messages.get().getBundle(getWorkplaceLocale()).key(
2034                            Messages.ERR_BUILD_TYPE_LIST_1,
2035                            type.getTypeName()),
2036                        e);
2037                }
2038            }
2039        }
2040        return list;
2041    }
2042
2043    /**
2044     * Recursively builds the VFS entry bean for the quick filtering function in the folder tab.<p<
2045     *
2046     * @param resource the resource
2047     * @param childMap map from parent to child resources
2048     * @param filterMatches the resources matching the filter
2049     * @param parentPaths root paths of resources which are not leaves
2050     * @param isRoot true if this the root node
2051     *
2052     * @return the VFS entry bean for the client
2053     *
2054     * @throws CmsException if something goes wrong
2055     */
2056    private CmsVfsEntryBean buildVfsEntryBeanForQuickSearch(
2057        CmsResource resource,
2058        Multimap<CmsResource, CmsResource> childMap,
2059        Set<CmsResource> filterMatches,
2060        Set<String> parentPaths,
2061        boolean isRoot)
2062    throws CmsException {
2063
2064        CmsObject cms = getCmsObject();
2065        String title = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
2066        boolean isMatch = filterMatches.contains(resource);
2067        List<CmsVfsEntryBean> childBeans = Lists.newArrayList();
2068
2069        Collection<CmsResource> children = childMap.get(resource);
2070        if (!children.isEmpty()) {
2071            for (CmsResource child : children) {
2072                CmsVfsEntryBean childBean = buildVfsEntryBeanForQuickSearch(
2073                    child,
2074                    childMap,
2075                    filterMatches,
2076                    parentPaths,
2077                    false);
2078                childBeans.add(childBean);
2079            }
2080        } else if (filterMatches.contains(resource)) {
2081            if (parentPaths.contains(resource.getRootPath())) {
2082                childBeans = null;
2083            }
2084            // otherwise childBeans remains an empty list
2085        }
2086
2087        String rootPath = resource.getRootPath();
2088        CmsVfsEntryBean result = new CmsVfsEntryBean(
2089            rootPath,
2090            resource.getStructureId(),
2091            title,
2092            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resource), resource.getName(), true),
2093            isRoot,
2094            isEditable(cms, resource),
2095            childBeans,
2096            isMatch);
2097        String siteRoot = null;
2098        if (OpenCms.getSiteManager().startsWithShared(rootPath)) {
2099            siteRoot = OpenCms.getSiteManager().getSharedFolder();
2100        } else {
2101            String tempSiteRoot = OpenCms.getSiteManager().getSiteRoot(rootPath);
2102            if (tempSiteRoot != null) {
2103                siteRoot = tempSiteRoot;
2104            } else {
2105                siteRoot = "";
2106            }
2107        }
2108        result.setSiteRoot(siteRoot);
2109        return result;
2110    }
2111
2112    /**
2113     * Helper method to construct a sitemap entry bean for the sitemap tab filter functionality.<p>
2114     *
2115     * @param cms the CMS context
2116     * @param node the root node of the filtered tree
2117     * @param isRoot true if this is the root node
2118     *
2119     * @return the sitemap entry bean
2120     */
2121    private CmsSitemapEntryBean convertNavigationTreeToBean(CmsObject cms, NavigationNode node, boolean isRoot) {
2122
2123        CmsSitemapEntryBean bean = null;
2124        try {
2125            bean = prepareSitemapEntry(cms, node.getNavElement(), isRoot, false);
2126            bean.setSearchMatch(node.isMatch());
2127            List<NavigationNode> children = node.getChildren();
2128            List<CmsSitemapEntryBean> childBeans = Lists.newArrayList();
2129            if (children.size() > 0) {
2130                for (NavigationNode child : children) {
2131                    childBeans.add(convertNavigationTreeToBean(cms, child, false));
2132                }
2133            } else if (node.isLeaf()) {
2134                childBeans = Lists.newArrayList();
2135            } else {
2136                // no children in filter result, but can still load children by clicking on tree item
2137                childBeans = null;
2138            }
2139            bean.setChildren(childBeans);
2140
2141        } catch (CmsException e) {
2142            LOG.error(e.getLocalizedMessage(), e);
2143        }
2144        return bean;
2145    }
2146
2147    /**
2148     * Returns a list of resource types by a request parameter.<p>
2149     *
2150     * @param resourceTypes the resource types parameter
2151     *
2152     * @return the resource types
2153     */
2154    private List<I_CmsResourceType> convertTypeNamesToTypes(List<String> resourceTypes) {
2155
2156        List<I_CmsResourceType> result = new ArrayList<I_CmsResourceType>();
2157        if (resourceTypes != null) {
2158            for (String type : resourceTypes) {
2159                try {
2160                    result.add(getResourceManager().getResourceType(type.trim()));
2161                } catch (Exception e) {
2162                    logError(e);
2163                }
2164            }
2165        }
2166
2167        return result;
2168    }
2169
2170    /**
2171     * Creates a resource type bean for the given type.<p>
2172     *
2173     * @param type the resource type
2174     * @param preview the preview provider
2175     * @param creatable if the type may be created by the current user
2176     *
2177     * @return the resource type bean
2178     */
2179    @SuppressWarnings("deprecation")
2180    private CmsResourceTypeBean createTypeBean(
2181        I_CmsResourceType type,
2182        I_CmsPreviewProvider preview,
2183        boolean creatable) {
2184
2185        CmsResourceTypeBean result = new CmsResourceTypeBean();
2186
2187        result.setResourceType(type.getTypeName());
2188        result.setTypeId(type.getTypeId());
2189        Locale wpLocale = getWorkplaceLocale();
2190        // type title and subtitle
2191        result.setTitle(CmsWorkplaceMessages.getResourceTypeName(wpLocale, type.getTypeName()));
2192        result.setSubTitle(CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, type.getTypeName()));
2193        result.setBigIconClasses(CmsIconUtil.getIconClasses(type.getTypeName(), null, false));
2194        // gallery id of corresponding galleries
2195        ArrayList<String> galleryNames = new ArrayList<String>();
2196        Iterator<I_CmsResourceType> galleryTypes = type.getGalleryTypes().iterator();
2197        while (galleryTypes.hasNext()) {
2198            I_CmsResourceType galleryType = galleryTypes.next();
2199            galleryNames.add(galleryType.getTypeName());
2200        }
2201        result.setGalleryTypeNames(galleryNames);
2202        if (preview != null) {
2203            result.setPreviewProviderName(preview.getPreviewName());
2204        }
2205        if (type.isFolder()) {
2206            result.setVisibility(TypeVisibility.hidden);
2207        }
2208        result.setCreatableType(creatable);
2209        return result;
2210    }
2211
2212    /**
2213     * Returns the search object containing the list with search results and the path to the specified resource.<p>
2214     *
2215     * @param resourceName the given resource
2216     * @param data the gallery data bean
2217     *
2218     * @return the gallery search object containing the current search parameter and the search result list
2219     *
2220     * @throws CmsException if the search fails
2221     */
2222    private CmsGallerySearchBean findResourceInGallery(String resourceName, CmsGalleryDataBean data)
2223    throws CmsException {
2224
2225        CmsResource resource = null;
2226        int pos = resourceName.indexOf("?");
2227        String resName = resourceName;
2228        String query = "";
2229        if (pos > -1) {
2230            query = resourceName.substring(pos);
2231            resName = resourceName.substring(0, pos);
2232        }
2233        String resNameWithoutServer = OpenCms.getLinkManager().getRootPath(getCmsObject(), resName);
2234        if (resNameWithoutServer != null) {
2235            // also cut off fragment if it has one
2236            resName = resNameWithoutServer.replaceFirst("#.*$", "");
2237        }
2238        CmsObject cms = getCmsObject();
2239        try {
2240            log("reading resource: " + resName);
2241            resource = cms.readResource(resName, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2242        } catch (CmsException e) {
2243            String originalSiteRoot = cms.getRequestContext().getSiteRoot();
2244            try {
2245                cms.getRequestContext().setSiteRoot("");
2246                resource = cms.readResource(resName, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2247            } catch (CmsException e2) {
2248                logError(e);
2249                return null;
2250            } finally {
2251                cms.getRequestContext().setSiteRoot(originalSiteRoot);
2252            }
2253        }
2254        boolean typeOk = true;
2255        if ((data.getTypes() != null) && !data.getTypes().isEmpty()) {
2256            typeOk = false;
2257            for (CmsResourceTypeBean type : data.getTypes()) {
2258                if (OpenCms.getResourceManager().matchResourceType(type.getType(), resource.getTypeId())) {
2259                    typeOk = true;
2260                }
2261            }
2262        }
2263        if (!typeOk) {
2264            LOG.debug(
2265                "Selected resource " + resource.getRootPath() + " has invalid type for configured gallery widget.");
2266            return null;
2267        }
2268        ArrayList<String> types = new ArrayList<String>();
2269        String resType = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
2270        types.add(resType);
2271        Set<String> folders = null;
2272        if (data.getStartFolderFilter() != null) {
2273            for (String folder : data.getStartFolderFilter()) {
2274                if (resource.getRootPath().startsWith(folder)) {
2275                    folders = data.getStartFolderFilter();
2276                    break;
2277                }
2278            }
2279        }
2280        CmsGallerySearchBean initialSearchObj = new CmsGallerySearchBean();
2281        initialSearchObj.setGalleryMode(data.getMode());
2282        initialSearchObj.setGalleryStoragePrefix(data.getGalleryStoragePrefix());
2283        initialSearchObj.setIncludeExpired(data.getIncludeExpiredDefault());
2284        initialSearchObj.setIgnoreSearchExclude(true);
2285        initialSearchObj.setTypes(types);
2286        if (folders != null) {
2287            initialSearchObj.setFolders(folders);
2288        }
2289        ArrayList<String> galleries = new ArrayList<String>();
2290        for (CmsGalleryFolderBean gallery : data.getGalleries()) {
2291            String galleryPath = gallery.getPath();
2292            String galleryRootPath = cms.addSiteRoot(galleryPath);
2293            String folderPath = CmsResource.getFolderPath(resName);
2294            if (galleryPath.equals(folderPath) || galleryRootPath.equals(folderPath)) {
2295                galleries.add(gallery.getPath());
2296                initialSearchObj.setGalleries(galleries);
2297                break;
2298            }
2299        }
2300        if (galleries.isEmpty()) {
2301            ArrayList<String> vfsFolders = new ArrayList<String>();
2302            vfsFolders.add(CmsResource.getFolderPath(resource.getRootPath()));
2303            initialSearchObj.setFolders(new HashSet<String>(vfsFolders));
2304        }
2305        initialSearchObj.setLocale(data.getLocale());
2306        CmsGallerySearchBean searchObj = new CmsGallerySearchBean(initialSearchObj);
2307        CmsWorkplaceSettings wpSettings = getWorkplaceSettings();
2308        String resultOrderKey = convertModeToResultOrderKey(data.getMode());
2309        SortParams sortOrder = wpSettings.getLastGalleryResultOrder(resultOrderKey);
2310        if (sortOrder == null) {
2311            sortOrder = SortParams.dateLastModified_desc;
2312        }
2313        try {
2314            // Make sure that the SortParams name corresponds to a valid CmsGallerySortParam name
2315            searchObj.setSortOrder(CmsGallerySearchParameters.CmsGallerySortParam.valueOf(sortOrder.toString()).name());
2316        } catch (Exception e) {
2317            LOG.error(e.getLocalizedMessage(), e);
2318            searchObj.setSortOrder(CmsGallerySearchParameters.CmsGallerySortParam.dateLastModified_desc.name());
2319        }
2320
2321        int currentPage = 1;
2322        boolean found = false;
2323        searchObj.setPage(currentPage);
2324        CmsGallerySearchParameters params = prepareSearchParams(searchObj, CmsAddContentRestriction.EMPTY);
2325        CmsObject searchCms = getSearchCms(searchObj);
2326        org.opencms.search.galleries.CmsGallerySearch searchBean = new org.opencms.search.galleries.CmsGallerySearch();
2327        searchBean.init(searchCms);
2328        searchBean.setIndexForProject(searchCms);
2329        CmsGallerySearchResultList searchResults = null;
2330        CmsGallerySearchResultList totalResults = new CmsGallerySearchResultList();
2331        CmsGallerySearchResult foundItem = null;
2332        while (!found) {
2333            params.setResultPage(currentPage);
2334            searchResults = searchBean.getResult(params);
2335            totalResults.append(searchResults);
2336            Iterator<CmsGallerySearchResult> resultsIt = searchResults.listIterator();
2337            while (resultsIt.hasNext()) {
2338                CmsGallerySearchResult searchResult = resultsIt.next();
2339                if (searchResult.getPath().equals(resource.getRootPath())) {
2340                    found = true;
2341                    foundItem = searchResult;
2342                    break;
2343                }
2344            }
2345            if (!found && ((searchResults.getHitCount() / (currentPage * params.getMatchesPerPage())) >= 1)) {
2346                currentPage++;
2347            } else {
2348                break;
2349            }
2350            if (searchResults.getHitCount() > INITIAL_SEARCH_MAX_RESULTS) {
2351                // in case the hit count is too large, don't continue the search to avoid slow load times
2352                break;
2353            }
2354        }
2355        boolean hasResults = searchResults != null;
2356        searchResults = totalResults;
2357        if (hasResults) {
2358            initialSearchObj.setSortOrder(params.getSortOrder().name());
2359            initialSearchObj.setResultCount(searchResults.getHitCount());
2360            initialSearchObj.setPage(params.getResultPage());
2361            initialSearchObj.setResults(buildSearchResultList(searchResults, foundItem, res -> false));
2362            initialSearchObj.setPage(1);
2363            initialSearchObj.setLastPage(currentPage);
2364            initialSearchObj.setTabId(I_CmsGalleryProviderConstants.GalleryTabId.cms_tab_results.name());
2365            initialSearchObj.setResourcePath(resName + query);
2366            initialSearchObj.setResourceType(resType);
2367            updateNoUploadReason(searchCms, searchObj);
2368        } else {
2369            log("could not find selected resource");
2370        }
2371        if ((resource != null)) {
2372            if (isSitemapEntry(cms, resource)) {
2373                A_CmsTreeTabDataPreloader<CmsSitemapEntryBean> loader = new A_CmsTreeTabDataPreloader<CmsSitemapEntryBean>() {
2374
2375                    @Override
2376                    protected CmsSitemapEntryBean createEntry(CmsObject innerCms, CmsResource innerResource)
2377                    throws CmsException {
2378
2379                        return internalCreateSitemapEntryBean(innerCms, innerResource);
2380                    }
2381
2382                    /**
2383                     * @see org.opencms.ade.galleries.A_CmsTreeTabDataPreloader#getChildren(org.opencms.file.CmsResource)
2384                     */
2385                    @Override
2386                    protected List<CmsResource> getChildren(CmsResource parent) throws CmsException {
2387
2388                        return getSitemapSubEntryResources(parent.getRootPath());
2389                    }
2390                };
2391                CmsSitemapEntryBean entryBean = loader.preloadData(
2392                    cms,
2393                    Sets.newHashSet(Collections.singletonList(resource)),
2394                    null);
2395                initialSearchObj.setSitemapPreloadData(entryBean);
2396            } else if (resource.isFolder()) {
2397                A_CmsTreeTabDataPreloader<CmsVfsEntryBean> loader = new A_CmsTreeTabDataPreloader<CmsVfsEntryBean>() {
2398
2399                    @Override
2400                    protected CmsVfsEntryBean createEntry(CmsObject innerCms, CmsResource innerResource)
2401                    throws CmsException {
2402
2403                        String title = innerCms.readPropertyObject(
2404                            innerResource,
2405                            CmsPropertyDefinition.PROPERTY_TITLE,
2406                            false).getValue();
2407                        return internalCreateVfsEntryBean(
2408                            getCmsObject(),
2409                            innerResource,
2410                            title,
2411                            true,
2412                            isEditable(innerCms, innerResource),
2413                            null,
2414                            false);
2415                    }
2416                };
2417                CmsVfsEntryBean entryBean = loader.preloadData(
2418                    cms,
2419                    Sets.newHashSet(Collections.singletonList(resource)),
2420                    null);
2421                initialSearchObj.setVfsPreloadData(entryBean);
2422            }
2423        }
2424
2425        return initialSearchObj;
2426    }
2427
2428    /**
2429     * Get default types for gallery together with visibility.<p>
2430     *
2431     * @return the default types
2432     */
2433    private List<I_CmsResourceType> getDefaultTypesForGallery() {
2434
2435        return OpenCms.getResourceManager().getResourceTypes();
2436    }
2437
2438    /**
2439     * Generates a list of available galleries for the given gallery-type.<p>
2440     *
2441     * @param galleryTypeId the gallery-type
2442     *
2443     * @return the list of galleries
2444     *
2445     */
2446    @SuppressWarnings("deprecation")
2447    private List<CmsResource> getGalleriesByType(int galleryTypeId) {
2448
2449        Set<CmsResource> galleries = new HashSet<CmsResource>();
2450
2451        // We swallow errors in this method because we don't  want a failure to read some folders (e.g. because of permission problems) to
2452        // cause an empty gallery list as a result
2453
2454        try {
2455            galleries.addAll(
2456                getCmsObject().readResources(
2457                    "/",
2458                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryTypeId)));
2459        } catch (Exception e) {
2460            LOG.error("Could not read site galleries: " + e.getLocalizedMessage(), e);
2461        }
2462
2463        String siteRoot = getCmsObject().getRequestContext().getSiteRoot();
2464        // if the current site is NOT the root site - add all other galleries from the system path
2465
2466        try {
2467            if (!siteRoot.equals("")) {
2468                List<CmsResource> systemGalleries = null;
2469                // get the galleries in the /system/ folder
2470                systemGalleries = getCmsObject().readResources(
2471                    CmsWorkplace.VFS_PATH_SYSTEM,
2472                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryTypeId));
2473                if (systemGalleries != null) {
2474                    // add the found system galleries to the result
2475                    galleries.addAll(systemGalleries);
2476                }
2477            }
2478        } catch (Exception e) {
2479            LOG.info("Could not read system galleries: " + e.getLocalizedMessage(), e);
2480        }
2481
2482        try {
2483            if (!OpenCms.getSiteManager().isSharedFolder(siteRoot)) {
2484                String shared = OpenCms.getSiteManager().getSharedFolder();
2485                List<CmsResource> sharedGalleries = getCmsObject().readResources(
2486                    shared,
2487                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryTypeId));
2488                if (sharedGalleries != null) {
2489                    galleries.addAll(sharedGalleries);
2490                }
2491            }
2492        } catch (Exception e) {
2493            LOG.info("Could not read shared galleries: " + e.getLocalizedMessage(), e);
2494        }
2495        List<CmsResource> galleriesList = new ArrayList<>(galleries);
2496        Collections.sort(
2497            galleriesList,
2498            (a, b) -> ComparisonChain.start().compare(a.getRootPath(), b.getRootPath()).result());
2499        return galleriesList;
2500    }
2501
2502    /**
2503     * Helper method for getting the initial gallery settings.<p>
2504     *
2505     * @param conf the gallery configration
2506     * @return the gallery settings
2507     *
2508     * @throws CmsRpcException if something goes wrong
2509     */
2510    private CmsGalleryDataBean getInitialSettingsInternal(CmsGalleryConfiguration conf) throws CmsRpcException {
2511
2512        CmsObject cms = getCmsObject();
2513        CmsGalleryDataBean data = new CmsGalleryDataBean();
2514        data.setMode(conf.getGalleryMode());
2515        data.setResultViewType(readResultViewType());
2516        boolean galleryShowInvalidDefault = Boolean.parseBoolean(
2517            getWorkplaceSettings().getUserSettings().getAdditionalPreference(PREF_GALLERY_SHOW_INVALID_DEFAULT, true));
2518        data.setIncludeExpiredDefault(galleryShowInvalidDefault);
2519
2520        data.setGalleryStoragePrefix(conf.getGalleryStoragePrefix());
2521        data.setLocales(buildLocalesMap());
2522        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(conf.getLocale())) {
2523            data.setLocale(conf.getLocale());
2524        } else {
2525            data.setLocale(getCmsObject().getRequestContext().getLocale().toString());
2526        }
2527        data.setVfsRootFolders(getRootEntries());
2528        data.setScope(getWorkplaceSettings().getLastSearchScope());
2529        String resultOrderKey = convertModeToResultOrderKey(conf.getGalleryMode());
2530        data.setSortOrder(getWorkplaceSettings().getLastGalleryResultOrder(resultOrderKey));
2531
2532        List<CmsResourceTypeBean> types = null;
2533        data.setTabIds(conf.getGalleryMode().getTabs());
2534        switch (conf.getGalleryMode()) {
2535            case editor:
2536            case view:
2537            case adeView:
2538            case widget:
2539                if (conf.getTabIds() != null) {
2540                    data.setTabIds(conf.getTabIds());
2541                }
2542                data.setCurrentElement(conf.getCurrentElement());
2543                String referencePath = conf.getReferencePath();
2544                if (CmsStringUtil.isEmptyOrWhitespaceOnly(referencePath)) {
2545                    referencePath = conf.getGalleryPath();
2546                }
2547                data.setReferenceSitePath(referencePath);
2548                types = getResourceTypeBeans(
2549                    conf.getGalleryMode(),
2550                    data.getReferenceSitePath(),
2551                    conf.getResourceTypes(),
2552                    conf.getSearchTypes());
2553                data.setTypes(types);
2554                Map<String, CmsGalleryTypeInfo> galleryTypeInfos = readGalleryInfosByTypeBeans(types);
2555                // in case the 'gallerytypes' parameter is set, allow only the given galleries
2556                if (conf.getGalleryTypes() != null) {
2557                    Map<String, CmsGalleryTypeInfo> infos = new HashMap<String, CmsGalleryTypeInfo>();
2558                    for (int i = 0; i < conf.getGalleryTypes().length; i++) {
2559                        CmsGalleryTypeInfo typeInfo = galleryTypeInfos.get(conf.getGalleryTypes()[i]);
2560                        if (typeInfo != null) {
2561                            infos.put(conf.getGalleryTypes()[i], typeInfo);
2562                        }
2563                    }
2564                    galleryTypeInfos = infos;
2565                }
2566
2567                String uri = cms.getRequestContext().getUri();
2568                String galleryContext = referencePath;
2569                if (conf.getPageId() != null) {
2570                    // This covers the case where the user is in the page editor,
2571                    // then edits an element of the page with the content editor, and then
2572                    // opens the gallery from a WYSIWYG field in the content editor.
2573                    try {
2574                        CmsResource page = cms.readResource(
2575                            new CmsUUID(conf.getPageId()),
2576                            CmsResourceFilter.IGNORE_EXPIRATION);
2577                        galleryContext = cms.getSitePath(page);
2578                    } catch (Exception e) {
2579                        LOG.error(e.getLocalizedMessage(), e);
2580                    }
2581                } else if (!uri.endsWith(".gwt") && !uri.endsWith(".jsp")) {
2582                    galleryContext = uri;
2583                }
2584                if (galleryContext == null) {
2585                    galleryContext = "/";
2586                }
2587                data.setGalleries(buildGalleriesList(galleryContext, galleryTypeInfos));
2588                String startGallery = conf.getGalleryPath();
2589                // check if the configured gallery path really is an existing gallery
2590                boolean galleryAvailable = false;
2591                for (CmsGalleryFolderBean folderBean : data.getGalleries()) {
2592                    if (folderBean.getPath().equals(startGallery)) {
2593                        galleryAvailable = true;
2594                        break;
2595                    }
2596                }
2597                data.setStartGallery(galleryAvailable ? startGallery : null);
2598                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(conf.getStartFolder())) {
2599                    try {
2600                        CmsObject cloneCms = OpenCms.initCmsObject(getCmsObject());
2601                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(conf.getStartSite())) {
2602                            cloneCms.getRequestContext().setSiteRoot(conf.getStartSite());
2603                        }
2604                        if (cloneCms.existsResource(conf.getStartFolder(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
2605                            data.setStartFolder(cloneCms.getRequestContext().addSiteRoot(conf.getStartFolder()));
2606                        }
2607                    } catch (CmsException e) {
2608                        log(e.getMessage(), e);
2609                    }
2610                }
2611
2612                if (CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartGallery()) && !data.getGalleries().isEmpty()) {
2613
2614                    String key = "";
2615                    if (!types.isEmpty() && !CmsStringUtil.isEmptyOrWhitespaceOnly(conf.getReferencePath())) {
2616                        key = types.get(0).getType();
2617                        try {
2618                            CmsResource refResource = getCmsObject().readResource(conf.getReferencePath());
2619                            String referenceType = OpenCms.getResourceManager().getResourceType(
2620                                refResource).getTypeName();
2621                            key = CmsGallerySearchBean.getGalleryStorageKey(
2622                                data.getGalleryStoragePrefix(),
2623                                referenceType);
2624                        } catch (Exception e) {
2625                            LOG.error("Could not read reference resource: " + conf.getReferencePath());
2626                        }
2627                    }
2628
2629                    if (!data.getGalleries().isEmpty()) {
2630                        startGallery = getWorkplaceSettings().getLastUsedGallery(key);
2631                        if (CmsStringUtil.isEmptyOrWhitespaceOnly(startGallery)) {
2632                            // check the user preferences for any configured start gallery
2633                            String galleryTypeName = data.getGalleries().get(0).getType();
2634                            startGallery = getWorkplaceSettings().getUserSettings().getStartGallery(
2635                                galleryTypeName,
2636                                getCmsObject());
2637                            if (CmsWorkplace.INPUT_DEFAULT.equals(startGallery)) {
2638                                startGallery = OpenCms.getWorkplaceManager().getDefaultUserSettings().getStartGallery(
2639                                    galleryTypeName);
2640                            }
2641                            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(startGallery)) {
2642                                startGallery = getCmsObject().getRequestContext().removeSiteRoot(startGallery);
2643                            }
2644                        }
2645                    }
2646                    // check if the gallery is available in this site and still exists
2647                    if (!conf.isResultsSelectable()) {
2648                        // if selecting results is explicitly disabled, opening the start gallery does not make much sense
2649                        data.setStartGallery(null);
2650                    } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(startGallery)) {
2651                        boolean galleryExists = getCmsObject().existsResource(startGallery);
2652                        if (galleryExists) {
2653                            data.setStartGallery(startGallery);
2654                        } else {
2655                            LOG.error("Could not read start gallery: " + startGallery);
2656                            data.setStartGallery(null);
2657                        }
2658                    } else {
2659                        data.setStartGallery(null);
2660                    }
2661                }
2662
2663                GalleryTabId defaultTab = conf.getTabConfiguration().getDefaultTab();
2664                data.setTabConfiguration(conf.getTabConfiguration());
2665                if (CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartGallery())
2666                    && CmsStringUtil.isEmptyOrWhitespaceOnly(data.getCurrentElement())
2667                    && CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartFolder())) {
2668                    data.setStartTab(defaultTab);
2669                } else {
2670                    data.setStartTab(GalleryTabId.cms_tab_results);
2671                }
2672                break;
2673            case ade:
2674                data.setReferenceSitePath(getCmsObject().getRequestContext().getUri());
2675                types = getResourceTypeBeans(
2676                    conf.getGalleryMode(),
2677                    data.getReferenceSitePath(),
2678                    conf.getResourceTypes(),
2679                    conf.getSearchTypes());
2680                data.setTypes(types);
2681                Map<String, CmsGalleryTypeInfo> adeGalleryTypeInfos = readGalleryInfosByTypeBeans(types);
2682                data.setGalleries(buildGalleriesList(data.getReferenceSitePath(), adeGalleryTypeInfos));
2683                data.setStartTab(GalleryTabId.cms_tab_types);
2684                break;
2685            default:
2686                break;
2687        }
2688
2689        if (CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartGallery())) {
2690            Set<String> folderFilter = readFolderFilters();
2691            data.setStartFolderFilter(folderFilter);
2692            if ((folderFilter != null) && !folderFilter.isEmpty()) {
2693                try {
2694                    data.setVfsPreloadData(
2695                        generateVfsPreloadData(
2696                            getCmsObject(),
2697                            CmsGalleryService.getVfsTreeState(getRequest(), conf.getTreeToken()),
2698                            folderFilter));
2699                } catch (Exception e) {
2700                    LOG.error(e.getLocalizedMessage(), e);
2701                }
2702            }
2703        }
2704
2705        CmsSiteSelectorOptionBuilder optionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
2706        optionBuilder.addNormalSites(true, getWorkplaceSettings().getUserSettings().getStartFolder());
2707        optionBuilder.addSharedSite();
2708        data.setVfsSiteSelectorOptions(optionBuilder.getOptions());
2709
2710        CmsSiteSelectorOptionBuilder sitemapOptionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
2711        sitemapOptionBuilder.addNormalSites(false, null);
2712        if (data.getReferenceSitePath() != null) {
2713            sitemapOptionBuilder.addCurrentSubsite(getCmsObject().addSiteRoot(data.getReferenceSitePath()));
2714        }
2715        data.setSitemapSiteSelectorOptions(sitemapOptionBuilder.getOptions());
2716        data.setDefaultScope(OpenCms.getWorkplaceManager().getGalleryDefaultScope());
2717        return data;
2718    }
2719
2720    /**
2721     * Reads the preview provider configuration and generates needed type-provider mappings.<p>
2722     *
2723     * @param types the resource types
2724     *
2725     * @return a map from resource types to preview providers
2726     */
2727    private Map<I_CmsResourceType, I_CmsPreviewProvider> getPreviewProviderForTypes(List<I_CmsResourceType> types) {
2728
2729        Map<String, I_CmsPreviewProvider> previewProviderMap = new HashMap<String, I_CmsPreviewProvider>();
2730        Map<I_CmsResourceType, I_CmsPreviewProvider> typeProviderMapping = new HashMap<I_CmsResourceType, I_CmsPreviewProvider>();
2731        for (I_CmsResourceType type : types) {
2732            String providerClass = type.getGalleryPreviewProvider();
2733            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(providerClass)) {
2734                providerClass = providerClass.trim();
2735                try {
2736                    if (previewProviderMap.containsKey(providerClass)) {
2737                        typeProviderMapping.put(type, previewProviderMap.get(providerClass));
2738                    } else {
2739                        I_CmsPreviewProvider previewProvider = (I_CmsPreviewProvider)Class.forName(
2740                            providerClass).newInstance();
2741                        previewProviderMap.put(providerClass, previewProvider);
2742                        typeProviderMapping.put(type, previewProvider);
2743                    }
2744                } catch (Exception e) {
2745                    logError(
2746                        new CmsException(
2747                            Messages.get().container(
2748                                Messages.ERR_INSTANCING_PREVIEW_PROVIDER_2,
2749                                providerClass,
2750                                type.getTypeName()),
2751                            e));
2752                }
2753            }
2754        }
2755        return typeProviderMapping;
2756    }
2757
2758    /**
2759     * Returns the resourceManager.<p>
2760     *
2761     * @return the resourceManager
2762     */
2763    private CmsResourceManager getResourceManager() {
2764
2765        if (m_resourceManager == null) {
2766            m_resourceManager = OpenCms.getResourceManager();
2767        }
2768        return m_resourceManager;
2769    }
2770
2771    /**
2772     * Returns the resource types configured to be used within the given gallery mode.<p>
2773     *
2774     * @param galleryMode the gallery mode
2775     * @param referenceSitePath the reference site-path to check permissions for
2776     * @param resourceTypesList the resource types parameter
2777     * @param typesForTypeTab the types which should be shown in the types tab according to the gallery configuration
2778     *
2779     * @return the resource types
2780     */
2781    private List<CmsResourceTypeBean> getResourceTypeBeans(
2782        GalleryMode galleryMode,
2783        String referenceSitePath,
2784        List<String> resourceTypesList,
2785        final List<String> typesForTypeTab) {
2786
2787        List<I_CmsResourceType> resourceTypes = null;
2788        Set<String> creatableTypes = null;
2789        switch (galleryMode) {
2790            case editor:
2791            case view:
2792            case adeView:
2793            case widget:
2794                resourceTypes = convertTypeNamesToTypes(resourceTypesList);
2795                if (resourceTypes.size() == 0) {
2796                    resourceTypes = Lists.newArrayList(getDefaultTypesForGallery());
2797                }
2798                creatableTypes = Collections.<String> emptySet();
2799                break;
2800            case ade:
2801                throw new IllegalStateException("This code should never be called");
2802            // ADE case is handled by container page service
2803            default:
2804                resourceTypes = Collections.<I_CmsResourceType> emptyList();
2805                creatableTypes = Collections.<String> emptySet();
2806        }
2807        return buildTypesList(resourceTypes, creatableTypes, Collections.<String> emptySet(), typesForTypeTab);
2808    }
2809
2810    /**
2811     * Returns the VFS root entries.<p>
2812     *
2813     * @return the VFS root entries
2814     *
2815     * @throws CmsRpcException if something goes wrong
2816     */
2817    private List<CmsVfsEntryBean> getRootEntries() throws CmsRpcException {
2818
2819        List<CmsVfsEntryBean> rootFolders = new ArrayList<CmsVfsEntryBean>();
2820        CmsObject cms = getCmsObject();
2821        try {
2822            String path = "/";
2823            if (!cms.existsResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
2824                String startFolder = getWorkplaceSettings().getUserSettings().getStartFolder();
2825                if (cms.existsResource(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
2826                    path = startFolder;
2827                } else {
2828                    path = null;
2829                }
2830            }
2831            if (path != null) {
2832                CmsResource rootFolderResource = getCmsObject().readResource(
2833                    path,
2834                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2835                String title = cms.readPropertyObject(path, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
2836                rootFolders.add(
2837                    internalCreateVfsEntryBean(
2838                        getCmsObject(),
2839                        rootFolderResource,
2840                        title,
2841                        true,
2842                        isEditable(getCmsObject(), rootFolderResource),
2843                        null,
2844                        false));
2845            }
2846
2847        } catch (CmsException e) {
2848            error(e);
2849        }
2850        return rootFolders;
2851    }
2852
2853    /**
2854     * Returns the workplace settings of the current user.<p>
2855     *
2856     * @return the workplace settings
2857     */
2858    private CmsWorkplaceSettings getWorkplaceSettings() {
2859
2860        if (m_workplaceSettings == null) {
2861            m_workplaceSettings = CmsWorkplace.getWorkplaceSettings(getCmsObject(), getRequest());
2862        }
2863        return m_workplaceSettings;
2864    }
2865
2866    /**
2867     * Checks whether a resource has a navigation property.<p>
2868     *
2869     * @param cms the current CMS context
2870     * @param resource the resource to use
2871     *
2872     * @return true if the resource has a navigation property
2873     *
2874     * @throws CmsException if something goes wrong
2875     */
2876    private boolean hasNavigationProperty(CmsObject cms, CmsResource resource) throws CmsException {
2877
2878        List<CmsProperty> props = cms.readPropertyObjects(resource, false);
2879        Map<String, String> propMap = CmsProperty.toMap(props);
2880        return propMap.containsKey(CmsPropertyDefinition.PROPERTY_NAVPOS)
2881            || propMap.containsKey(CmsPropertyDefinition.PROPERTY_NAVTEXT);
2882    }
2883
2884    /**
2885     * Returns the search parameters for the given query data.<p>
2886     *
2887     * @param searchData the query data
2888     * @param replacementConfig the replacement configuration
2889     *
2890     * @return the prepared search parameters
2891     */
2892    private CmsGallerySearchParameters prepareSearchParams(
2893        CmsGallerySearchBean searchData,
2894        CmsAddContentRestriction replacementConfig) {
2895
2896        // create a new search parameter object
2897        CmsGallerySearchParameters params = new CmsGallerySearchParameters();
2898        CmsObject cms = getCmsObject();
2899
2900        // set the selected types to the parameters
2901        if (searchData.getServerSearchTypes() != null) {
2902            params.setResourceTypes(searchData.getServerSearchTypes());
2903        }
2904
2905        // set the selected galleries to the parameters
2906        if (searchData.getGalleries() != null) {
2907            List<String> paramGalleries = new ArrayList<String>();
2908            for (String gallerySitePath : searchData.getGalleries()) {
2909                paramGalleries.add(cms.getRequestContext().addSiteRoot(gallerySitePath));
2910            }
2911            params.setGalleries(paramGalleries);
2912        }
2913
2914        // set the sort order for the galleries to the parameters
2915        CmsGallerySearchParameters.CmsGallerySortParam sortOrder;
2916        String temp = searchData.getSortOrder();
2917        try {
2918            sortOrder = CmsGallerySearchParameters.CmsGallerySortParam.valueOf(temp);
2919        } catch (Exception e) {
2920            sortOrder = CmsGallerySearchParameters.CmsGallerySortParam.DEFAULT;
2921        }
2922        params.setSortOrder(sortOrder);
2923        if (searchData.getScope() == null) {
2924            params.setScope(OpenCms.getWorkplaceManager().getGalleryDefaultScope());
2925        } else {
2926            params.setScope(searchData.getScope());
2927        }
2928        params.setReferencePath(searchData.getReferencePath());
2929
2930        // set the selected folders to the parameters
2931        params.setFolders(new ArrayList<String>(searchData.getFolders()));
2932
2933        // set the categories to the parameters
2934        if (searchData.getCategories() != null) {
2935            params.setCategories(searchData.getCategories());
2936        }
2937
2938        // set the search query to the parameters
2939        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(searchData.getQuery())) {
2940            params.setSearchWords(searchData.getQuery());
2941        }
2942
2943        // set the result page to the parameters
2944        int page = searchData.getPage();
2945        params.setResultPage(page);
2946
2947        // set the locale to the parameters
2948        String locale = searchData.getLocale();
2949        if (CmsStringUtil.isEmptyOrWhitespaceOnly(locale)) {
2950            locale = getCmsObject().getRequestContext().getLocale().toString();
2951        }
2952        params.setSearchLocale(locale);
2953
2954        // set the matches per page to the parameters
2955        params.setMatchesPerPage(searchData.getMatchesPerPage());
2956
2957        // get the date range input
2958        long dateCreatedStart = searchData.getDateCreatedStart();
2959        long dateCreatedEnd = searchData.getDateCreatedEnd();
2960        long dateModifiedStart = searchData.getDateModifiedStart();
2961        long dateModifiedEnd = searchData.getDateModifiedEnd();
2962
2963        // set the date created range to the parameters
2964        if ((dateCreatedStart != -1L) && (dateCreatedEnd != -1L)) {
2965            params.setDateCreatedTimeRange(dateCreatedStart, dateCreatedEnd);
2966        } else if (dateCreatedStart != -1L) {
2967            params.setDateCreatedTimeRange(dateCreatedStart, Long.MAX_VALUE);
2968        } else if (dateCreatedEnd != -1L) {
2969            params.setDateCreatedTimeRange(Long.MIN_VALUE, dateCreatedEnd);
2970        }
2971
2972        // set the date modified range to the parameters
2973        if ((dateModifiedStart != -1L) && (dateModifiedEnd != -1L)) {
2974            params.setDateLastModifiedTimeRange(dateModifiedStart, dateModifiedEnd);
2975        } else if (dateModifiedStart != -1L) {
2976            params.setDateLastModifiedTimeRange(dateModifiedStart, Long.MAX_VALUE);
2977        } else if (dateModifiedEnd != -1L) {
2978            params.setDateLastModifiedTimeRange(Long.MIN_VALUE, dateModifiedEnd);
2979        }
2980        params.setIgnoreSearchExclude(searchData.isIgnoreSearchExclude());
2981        if (GalleryMode.ade.equals(searchData.getGalleryMode())) {
2982            if (searchData.getTypes().isEmpty() || !Collections.disjoint(FUNCTION_TYPES, searchData.getTypes())) {
2983                CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
2984                    cms,
2985                    cms.getRequestContext().addSiteRoot(searchData.getReferencePath()));
2986                CmsFormatterConfigurationCacheState formatterState = OpenCms.getADEManager().getCachedFormatters(
2987                    cms.getRequestContext().getCurrentProject().isOnlineProject());
2988                params.setFunctionAvailability(config.getDynamicFunctionAvailability(formatterState));
2989                if (config.isHideNonMatchingFunctions()) {
2990                    if (searchData.getContainerInfo() != null) {
2991                        Set<CmsUUID> excludedFunctions = getExcludedFunctionsForContainerInfo(
2992                            cms,
2993                            config,
2994                            searchData.getContainerInfo());
2995                        params.setExcludedFunctions(excludedFunctions);
2996                    }
2997                }
2998            }
2999            CmsTemplateContextInfo templateContextInfo = searchData.getTemplateContextInfo();
3000            if ((templateContextInfo != null)
3001                && (templateContextInfo.getContextProvider() != null)
3002                && (templateContextInfo.getCurrentContext() != null)) {
3003                I_CmsTemplateContextProvider provider = OpenCms.getTemplateContextManager().getTemplateContextProvider(
3004                    templateContextInfo.getContextProvider());
3005                if (provider != null) {
3006                    Set<CmsUUID> allowedFunctions = provider.getFunctionsForGallery(
3007                        cms,
3008                        templateContextInfo.getCurrentContext());
3009                    // allowed functions may be null - this is fine
3010                    params.setIncludedFunctions(allowedFunctions);
3011                    String compatibility = provider.getTemplateCompatibility(templateContextInfo.getCurrentContext());
3012                    params.setTemplateCompatibility(compatibility);
3013                }
3014            }
3015            if (replacementConfig != null) {
3016                // if the search replacement configuration didn't already handle the replacement,
3017                // exclude the type from search results (this happens when searching for multiple types).
3018                Set<String> excludedTypes = replacementConfig.getTypes();
3019                if ((excludedTypes.size() > 0) && (params.getResourceTypes() != null)) {
3020                    List<String> types = new ArrayList<>(params.getResourceTypes());
3021                    boolean removed = types.removeAll(excludedTypes);
3022                    if (removed && (types.size() == 0)) {
3023                        params.setForceEmptyResult(true);
3024                    }
3025                    params.setResourceTypes(types);
3026                }
3027            }
3028        }
3029
3030        // set include expired/unreleased
3031        if (searchData.isIncludeExpired()) {
3032            params.setIncludeExpired(true);
3033        }
3034        return params;
3035    }
3036
3037    /**
3038     * Prepares a sitemap entry bean from the given navigation element.<p>
3039     *
3040     * @param cms the cms context
3041     * @param navElement the navigation element
3042     * @param isRoot <code>true</code> if this is a site root entry
3043     * @param checkHasChildren if true, check if the entry has any children; set to false if you want to handle the list of children manually
3044     *
3045     * @return the sitemap entry
3046     *
3047     * @throws CmsException if something goes wrong reading types and resources
3048     */
3049    private CmsSitemapEntryBean prepareSitemapEntry(
3050        CmsObject cms,
3051        CmsJspNavElement navElement,
3052        boolean isRoot,
3053        boolean checkHasChildren)
3054    throws CmsException {
3055
3056        CmsResource ownResource = navElement.getResource();
3057        CmsResource defaultFileResource = null;
3058        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms);
3059        if (ownResource.isFolder() && !navElement.isNavigationLevel()) {
3060            try {
3061                defaultFileResource = cms.readDefaultFile(ownResource, CmsResourceFilter.ONLY_VISIBLE);
3062            } catch (CmsPermissionViolationException e) {
3063                // user has insufficient rights, can be ignored
3064            }
3065        }
3066        String type;
3067        if (defaultFileResource != null) {
3068            type = OpenCms.getResourceManager().getResourceType(defaultFileResource.getTypeId()).getTypeName();
3069        } else {
3070            type = OpenCms.getResourceManager().getResourceType(ownResource.getTypeId()).getTypeName();
3071        }
3072        // make sure not to show ??? NavText ???
3073        String title = null;
3074        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(navElement.getProperty(CmsPropertyDefinition.PROPERTY_NAVTEXT))) {
3075            title = navElement.getProperty(CmsPropertyDefinition.PROPERTY_NAVTEXT);
3076        } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(
3077            navElement.getProperty(CmsPropertyDefinition.PROPERTY_TITLE))) {
3078            title = navElement.getProperty(CmsPropertyDefinition.PROPERTY_TITLE);
3079        } else {
3080            title = navElement.getFileName();
3081            if (title.contains("/")) {
3082                title = title.substring(0, title.indexOf("/"));
3083            }
3084        }
3085        String childPath = navElement.getResource().getRootPath();
3086        boolean noChildren = true;
3087
3088        if (checkHasChildren) {
3089            List<CmsJspNavElement> childNav = navBuilder.getNavigationForFolder(
3090                childPath,
3091                Visibility.all,
3092                CmsResourceFilter.ONLY_VISIBLE);
3093            for (CmsJspNavElement childNavEntry : childNav) {
3094                if (childNavEntry.isInNavigation()) {
3095                    noChildren = false;
3096                    break;
3097                }
3098            }
3099        }
3100
3101        CmsSitemapEntryBean result = new CmsSitemapEntryBean(
3102            navElement.getResource().getRootPath(),
3103            navElement.getResourceName(),
3104            ownResource.getStructureId(),
3105            title,
3106            type,
3107            ownResource.isFolder(),
3108            isRoot,
3109            navElement.isHiddenNavigationEntry());
3110        result.setSiteRoot(OpenCms.getSiteManager().getSiteRoot(ownResource.getRootPath()));
3111        String displayType = CmsIconUtil.getDisplayType(
3112            cms,
3113            defaultFileResource != null ? defaultFileResource : ownResource);
3114        result.setBigIconClasses(
3115            CmsIconUtil.getIconClasses(
3116                displayType,
3117                defaultFileResource != null ? defaultFileResource.getName() : ownResource.getName(),
3118                false));
3119        result.setSmallIconClasses(
3120            CmsIconUtil.getIconClasses(
3121                displayType,
3122                defaultFileResource != null ? defaultFileResource.getName() : ownResource.getName(),
3123                true));
3124        if (checkHasChildren && noChildren) {
3125            result.setChildren(new ArrayList<CmsSitemapEntryBean>());
3126        }
3127
3128        return result;
3129    }
3130
3131    /**
3132     * Reads the folder filters for the current site.<p>
3133     *
3134     * @return the folder filters
3135     */
3136    private Set<String> readFolderFilters() {
3137
3138        JSONObject storedFilters = readUserFolderFilters();
3139        Set<String> result = null;
3140        if (storedFilters.has(getCmsObject().getRequestContext().getSiteRoot())) {
3141            try {
3142                org.opencms.json.JSONArray folders = storedFilters.getJSONArray(
3143                    getCmsObject().getRequestContext().getSiteRoot());
3144                result = new HashSet<String>();
3145                for (int i = 0; i < folders.length(); i++) {
3146                    result.add(folders.getString(i));
3147                }
3148            } catch (JSONException e) {
3149                LOG.error(e.getLocalizedMessage(), e);
3150            }
3151        }
3152        return result;
3153    }
3154
3155    /**
3156     * Returns a map with gallery type names associated with the list of available galleries for this type.<p>
3157     *
3158     * @param resourceTypes the resources types to collect the galleries for
3159     *
3160     * @return a map with gallery type and  the associated galleries
3161     */
3162    private Map<String, CmsGalleryTypeInfo> readGalleryInfosByTypeBeans(List<CmsResourceTypeBean> resourceTypes) {
3163
3164        Map<String, CmsGalleryTypeInfo> galleryTypeInfos = new HashMap<String, CmsGalleryTypeInfo>();
3165        for (CmsResourceTypeBean typeBean : resourceTypes) {
3166            try {
3167                if (!typeBean.isDeactivated()) {
3168                    addGalleriesForType(galleryTypeInfos, typeBean.getType());
3169                }
3170            } catch (CmsLoaderException e1) {
3171                logError(e1);
3172            }
3173        }
3174        return galleryTypeInfos;
3175    }
3176
3177    /**
3178     * Returns a map with gallery type names associated with the list of available galleries for this type.<p>
3179     *
3180     * @param resourceTypes the resources types to collect the galleries for
3181     *
3182     * @return a map with gallery type and  the associated galleries
3183     */
3184    private Map<String, CmsGalleryTypeInfo> readGalleryInfosByTypeNames(List<String> resourceTypes) {
3185
3186        Map<String, CmsGalleryTypeInfo> galleryTypeInfos = new HashMap<String, CmsGalleryTypeInfo>();
3187        for (String typeName : resourceTypes) {
3188            try {
3189                addGalleriesForType(galleryTypeInfos, typeName);
3190            } catch (CmsLoaderException e1) {
3191                logError(e1);
3192            }
3193        }
3194        return galleryTypeInfos;
3195    }
3196
3197    /**
3198     * Reads the result view type from the current user.<p>
3199     *
3200     * @return the result view type
3201     */
3202    private String readResultViewType() {
3203
3204        return (String)getCmsObject().getRequestContext().getCurrentUser().getAdditionalInfo(
3205            RESULT_VIEW_TYPE_ADD_INFO_KEY);
3206    }
3207
3208    /**
3209     * Reads the users folder filters from the additional info.<p>
3210     *
3211     * @return the folder filters
3212     */
3213    private JSONObject readUserFolderFilters() {
3214
3215        CmsUser user = getCmsObject().getRequestContext().getCurrentUser();
3216        String addInfo = (String)user.getAdditionalInfo(FOLDER_FILTER_ADD_INFO_KEY);
3217        JSONObject result = null;
3218        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(addInfo)) {
3219            try {
3220                result = new JSONObject(addInfo);
3221            } catch (JSONException e) {
3222                LOG.error(e.getLocalizedMessage(), e);
3223            }
3224        }
3225        if (result == null) {
3226            result = new JSONObject();
3227        }
3228        return result;
3229    }
3230
3231    /**
3232     * Returns the gallery search object containing the results for the current parameter.<p>
3233     *
3234     * @param searchObj the current search object
3235     *
3236     * @return the search result
3237     *
3238     * @throws CmsException if the search fails
3239     */
3240    private CmsGallerySearchBean search(CmsGallerySearchBean searchObj) throws CmsException {
3241
3242        CmsGallerySearchBean searchObjBean = new CmsGallerySearchBean(searchObj);
3243        if (searchObj == null) {
3244            return searchObjBean;
3245        }
3246        // store folder filter
3247        storeFolderFilter(searchObj.getFolders());
3248        CmsObject cms = getCmsObject();
3249        CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache(
3250            cms,
3251            cms.getRequestContext().addSiteRoot(cms.getRequestContext().getUri()));
3252        CmsAddContentRestriction replacementConfig = config.getAddContentRestriction();
3253        CmsGallerySearchResultList searchResults = null;
3254        List<String> types = searchObj.getTypes();
3255        Predicate<CmsResource> deactivatedCheck = res -> false;
3256        if (searchObj.getGalleryMode().equals(GalleryMode.ade)
3257            && types.contains(CmsResourceTypeFunctionConfig.TYPE_NAME)
3258            && !config.isHideNonMatchingFunctions()
3259            && (searchObj.getContainerInfo() != null)) {
3260            final Set<CmsUUID> excludedFunctions = getExcludedFunctionsForContainerInfo(
3261                cms,
3262                config,
3263                searchObj.getContainerInfo());
3264            deactivatedCheck = res -> excludedFunctions.contains(res.getStructureId());
3265        }
3266
3267        searchObjBean.setReplacedResults(false);
3268        if (searchObj.getGalleryMode().equals(GalleryMode.ade)
3269            && (types.size() == 1)
3270            && replacementConfig.getTypes().contains(types.iterator().next())) {
3271
3272            List<CmsGallerySearchResult> items = replacementConfig.getResult(cms, types.iterator().next());
3273            searchResults = new CmsGallerySearchResultList();
3274            searchResults.addAll(items);
3275            searchObjBean.setReplacedResults(true);
3276            searchObjBean.setPage(1);
3277            searchObjBean.setFolders(new HashSet<>());
3278            searchObjBean.setGalleries(new ArrayList<>());
3279            searchObjBean.setCategories(new ArrayList<>());
3280            // searchObjBean.setMatchesPerPage(searchResults.size());
3281            searchObjBean.setNoUploadReason(
3282                Messages.get().getBundle(m_wpLocale).key(Messages.GUI_NO_UPLOAD_FOR_REPLACED_SEARCH_RESULTS_0));
3283            searchObjBean.setResults(buildSearchResultList(searchResults, null, deactivatedCheck));
3284            searchObjBean.setResultCount(searchResults.size());
3285            if (searchObjBean.getResultCount() > 0) {
3286                CmsADESessionCache cache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3287                cache.setLastPageEditorGallerySearch(searchObj);
3288            }
3289
3290        } else {
3291            // search
3292            CmsGallerySearchParameters params = prepareSearchParams(searchObj, replacementConfig);
3293            CmsObject searchCms = getSearchCms(searchObj);
3294            searchResults = OpenCms.getSearchManager().getIndexSolr("Solr Offline").gallerySearch(searchCms, params);
3295            searchResults.calculatePages(params.getResultPage(), params.getMatchesPerPage());
3296
3297            // set only the result dependent search params for this search
3298            // the user dependent params(galleries, types etc.) remain unchanged
3299            searchObjBean.setSortOrder(params.getSortOrder().name());
3300            searchObjBean.setScope(params.getScope());
3301            searchObjBean.setResultCount(searchResults.getHitCount());
3302            searchObjBean.setPage(params.getResultPage());
3303            searchObjBean.setLastPage(params.getResultPage());
3304            searchObjBean.setResults(buildSearchResultList(searchResults, null, deactivatedCheck));
3305            if (searchObj.getGalleryMode().equals(GalleryMode.ade)) {
3306                if (searchObjBean.getResultCount() > 0) {
3307                    CmsADESessionCache cache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3308                    cache.setLastPageEditorGallerySearch(searchObj);
3309                }
3310            }
3311            updateNoUploadReason(searchCms, searchObjBean);
3312        }
3313        return searchObjBean;
3314    }
3315
3316    /**
3317     * Sets the last opened gallery information for the current user.<p>
3318     *
3319     * @param searchObject the current search
3320     */
3321    private void setLastOpenedGallery(CmsGallerySearchBean searchObject) {
3322
3323        if ((searchObject.getGalleries() != null)
3324            && (searchObject.getGalleries().size() <= 1) // if the size is 0, the user has actively deselected the galleries, so we want to handle this case too
3325            && searchObject.haveGalleriesChanged()) {
3326            String galleryPath = searchObject.getGalleries().isEmpty() ? null : searchObject.getGalleries().get(0);
3327            CmsWorkplaceSettings settings = getWorkplaceSettings();
3328            if (searchObject.getGalleryMode() == GalleryMode.adeView) {
3329                settings.setLastUsedGallery("" + GalleryMode.adeView, galleryPath);
3330            } else {
3331                String referencePath = searchObject.getReferencePath();
3332
3333                String referenceTypeName = "";
3334
3335                try {
3336                    CmsObject cms = getCmsObject();
3337                    CmsResource referenceResource = cms.readResource(referencePath);
3338                    I_CmsResourceType referenceType = OpenCms.getResourceManager().getResourceType(referenceResource);
3339                    referenceTypeName = referenceType.getTypeName();
3340                } catch (CmsException e) {
3341                    LOG.error(e.getLocalizedMessage(), e);
3342                }
3343                settings.setLastUsedGallery(
3344                    CmsGallerySearchBean.getGalleryStorageKey(
3345                        searchObject.getGalleryStoragePrefix(),
3346                        referenceTypeName),
3347                    galleryPath);
3348            }
3349        }
3350    }
3351
3352    /**
3353     * Stores the folder filters for the current site.<p>
3354     *
3355     * @param folders the folder filters
3356     */
3357    private void storeFolderFilter(Set<String> folders) {
3358
3359        JSONObject storedFilters = readUserFolderFilters();
3360        try {
3361            storedFilters.put(getCmsObject().getRequestContext().getSiteRoot(), folders);
3362            CmsUser user = getCmsObject().getRequestContext().getCurrentUser();
3363            user.setAdditionalInfo(FOLDER_FILTER_ADD_INFO_KEY, storedFilters.toString());
3364            getCmsObject().writeUser(user);
3365        } catch (Exception e) {
3366            LOG.error(e.getLocalizedMessage(), e);
3367        }
3368    }
3369
3370    /**
3371     * Checks the current users permissions on the upload target folder to update the no upload reason.<p>
3372     *
3373     * @param searchCms the cms context
3374     * @param searchObj the search data
3375     */
3376    private void updateNoUploadReason(CmsObject searchCms, CmsGallerySearchBean searchObj) {
3377
3378        if ((searchObj.getGalleries().size() + searchObj.getFolders().size()) == 1) {
3379            String target = !searchObj.getGalleries().isEmpty()
3380            ? searchObj.getGalleries().get(0)
3381            : searchObj.getFolders().iterator().next();
3382            try {
3383                CmsResource targetRes;
3384                if (searchCms.existsResource(target, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
3385                    targetRes = searchCms.readResource(target, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3386                } else {
3387                    CmsObject rootCms = OpenCms.initCmsObject(searchCms);
3388                    rootCms.getRequestContext().setSiteRoot("");
3389                    targetRes = rootCms.readResource(target, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3390                }
3391                searchObj.setNoUploadReason(
3392                    new CmsResourceUtil(searchCms, targetRes).getNoEditReason(getWorkplaceLocale(), true));
3393            } catch (CmsException e) {
3394                searchObj.setNoUploadReason(e.getLocalizedMessage(getWorkplaceLocale()));
3395            }
3396        } else {
3397            searchObj.setNoUploadReason(null);
3398        }
3399    }
3400}