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.ui.apps.lists;
029
030import org.opencms.acacia.shared.I_CmsSerialDateValue;
031import org.opencms.ade.configuration.CmsADEConfigData;
032import org.opencms.ade.configuration.CmsResourceTypeConfig;
033import org.opencms.ade.containerpage.shared.CmsDialogOptions;
034import org.opencms.file.CmsFile;
035import org.opencms.file.CmsObject;
036import org.opencms.file.CmsPropertyDefinition;
037import org.opencms.file.CmsResource;
038import org.opencms.file.CmsResourceFilter;
039import org.opencms.file.types.CmsResourceTypeXmlContent;
040import org.opencms.file.types.I_CmsResourceType;
041import org.opencms.gwt.shared.CmsResourceStatusTabId;
042import org.opencms.i18n.CmsLocaleManager;
043import org.opencms.jsp.search.config.CmsSearchConfiguration;
044import org.opencms.jsp.search.config.CmsSearchConfigurationPagination;
045import org.opencms.jsp.search.config.I_CmsSearchConfigurationCommon;
046import org.opencms.jsp.search.config.I_CmsSearchConfigurationPagination;
047import org.opencms.jsp.search.config.parser.CmsSimpleSearchConfigurationParser;
048import org.opencms.jsp.search.config.parser.CmsSimpleSearchConfigurationParser.SortOption;
049import org.opencms.jsp.search.controller.CmsSearchController;
050import org.opencms.jsp.search.controller.I_CmsSearchControllerFacetField;
051import org.opencms.jsp.search.controller.I_CmsSearchControllerFacetRange;
052import org.opencms.jsp.search.result.CmsSearchResultWrapper;
053import org.opencms.jsp.search.state.I_CmsSearchStateFacet;
054import org.opencms.loader.CmsLoaderException;
055import org.opencms.lock.CmsLockActionRecord;
056import org.opencms.lock.CmsLockActionRecord.LockChange;
057import org.opencms.lock.CmsLockUtil;
058import org.opencms.main.CmsException;
059import org.opencms.main.CmsLog;
060import org.opencms.main.OpenCms;
061import org.opencms.relations.CmsCategoryService;
062import org.opencms.relations.CmsLink;
063import org.opencms.search.CmsSearchException;
064import org.opencms.search.CmsSearchResource;
065import org.opencms.search.fields.CmsSearchField;
066import org.opencms.search.solr.CmsSolrIndex;
067import org.opencms.search.solr.CmsSolrQuery;
068import org.opencms.search.solr.CmsSolrResultList;
069import org.opencms.ui.A_CmsUI;
070import org.opencms.ui.CmsVaadinUtils;
071import org.opencms.ui.FontOpenCms;
072import org.opencms.ui.I_CmsDialogContext;
073import org.opencms.ui.I_CmsDialogContext.ContextType;
074import org.opencms.ui.I_CmsUpdateListener;
075import org.opencms.ui.actions.A_CmsWorkplaceAction;
076import org.opencms.ui.actions.CmsContextMenuActionItem;
077import org.opencms.ui.actions.CmsDeleteDialogAction;
078import org.opencms.ui.actions.CmsEditDialogAction;
079import org.opencms.ui.actions.CmsResourceInfoAction;
080import org.opencms.ui.apps.A_CmsWorkplaceApp;
081import org.opencms.ui.apps.CmsAppView;
082import org.opencms.ui.apps.CmsAppView.CacheStatus;
083import org.opencms.ui.apps.CmsAppWorkplaceUi;
084import org.opencms.ui.apps.CmsEditor;
085import org.opencms.ui.apps.CmsEditorConfiguration;
086import org.opencms.ui.apps.CmsFileExplorer;
087import org.opencms.ui.apps.CmsFileExplorerSettings;
088import org.opencms.ui.apps.I_CmsAppUIContext;
089import org.opencms.ui.apps.I_CmsCachableApp;
090import org.opencms.ui.apps.I_CmsContextProvider;
091import org.opencms.ui.apps.Messages;
092import org.opencms.ui.apps.lists.CmsListManager.ListConfigurationBean.ListCategoryFolderRestrictionBean;
093import org.opencms.ui.apps.lists.CmsListManager.ListConfigurationBean.ListGeoFilterBean;
094import org.opencms.ui.apps.lists.CmsOptionDialog.I_OptionHandler;
095import org.opencms.ui.apps.lists.daterestrictions.CmsDateRestrictionParser;
096import org.opencms.ui.apps.lists.daterestrictions.I_CmsListDateRestriction;
097import org.opencms.ui.apps.projects.CmsProjectManagerConfiguration;
098import org.opencms.ui.components.CmsBasicDialog;
099import org.opencms.ui.components.CmsErrorDialog;
100import org.opencms.ui.components.CmsFileTable;
101import org.opencms.ui.components.CmsFileTableDialogContext;
102import org.opencms.ui.components.CmsResourceTable;
103import org.opencms.ui.components.CmsResourceTable.I_ResourcePropertyProvider;
104import org.opencms.ui.components.CmsResourceTableProperty;
105import org.opencms.ui.components.CmsToolBar;
106import org.opencms.ui.components.I_CmsWindowCloseListener;
107import org.opencms.ui.components.OpenCmsTheme;
108import org.opencms.ui.components.extensions.CmsGwtDialogExtension;
109import org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode;
110import org.opencms.ui.contextmenu.CmsResourceContextMenuBuilder;
111import org.opencms.ui.contextmenu.I_CmsContextMenuItem;
112import org.opencms.ui.contextmenu.I_CmsContextMenuItemProvider;
113import org.opencms.util.CmsGeoUtil;
114import org.opencms.util.CmsStringUtil;
115import org.opencms.util.CmsUUID;
116import org.opencms.workplace.editors.directedit.CmsDateSeriesEditHandler;
117import org.opencms.workplace.editors.directedit.I_CmsEditHandler;
118import org.opencms.workplace.explorer.CmsResourceUtil;
119import org.opencms.xml.CmsXmlUtils;
120import org.opencms.xml.containerpage.CmsContainerElementBean;
121import org.opencms.xml.content.CmsXmlContent;
122import org.opencms.xml.content.CmsXmlContentFactory;
123import org.opencms.xml.content.CmsXmlContentValueLocation;
124import org.opencms.xml.types.CmsXmlDisplayFormatterValue;
125import org.opencms.xml.types.CmsXmlVfsFileValue;
126import org.opencms.xml.types.I_CmsXmlContentValue;
127
128import java.util.ArrayList;
129import java.util.Arrays;
130import java.util.Collection;
131import java.util.Collections;
132import java.util.Date;
133import java.util.HashMap;
134import java.util.HashSet;
135import java.util.LinkedHashMap;
136import java.util.List;
137import java.util.Locale;
138import java.util.Map;
139import java.util.Set;
140
141import org.apache.commons.logging.Log;
142
143import com.vaadin.navigator.View;
144import com.vaadin.navigator.ViewChangeListener;
145import com.vaadin.server.Sizeable.Unit;
146import com.vaadin.ui.Button;
147import com.vaadin.ui.Button.ClickEvent;
148import com.vaadin.ui.Button.ClickListener;
149import com.vaadin.ui.Component;
150import com.vaadin.ui.HorizontalSplitPanel;
151import com.vaadin.ui.UI;
152import com.vaadin.ui.Window;
153import com.vaadin.ui.themes.ValoTheme;
154import com.vaadin.v7.data.Item;
155import com.vaadin.v7.data.Property.ValueChangeEvent;
156import com.vaadin.v7.data.Property.ValueChangeListener;
157import com.vaadin.v7.event.FieldEvents.TextChangeEvent;
158import com.vaadin.v7.event.FieldEvents.TextChangeListener;
159import com.vaadin.v7.ui.AbstractSelect.ItemDescriptionGenerator;
160import com.vaadin.v7.ui.ComboBox;
161import com.vaadin.v7.ui.Table;
162import com.vaadin.v7.ui.Table.CellStyleGenerator;
163import com.vaadin.v7.ui.TextField;
164
165/**
166 * Manager for list configuration files.<p>
167 */
168@SuppressWarnings("deprecation")
169public class CmsListManager extends A_CmsWorkplaceApp
170implements I_ResourcePropertyProvider, I_CmsContextProvider, ViewChangeListener, I_CmsWindowCloseListener,
171I_CmsCachableApp {
172
173    /**
174     * Enum representing how selected categories should be combined in a search.<p>
175     */
176    public static enum CategoryMode {
177        /** Combine categories with AND. */
178        AND,
179
180        /** Combine categories with OR. */
181        OR;
182    }
183
184    /**
185     * The list configuration data.<p>
186     */
187    public static class ListConfigurationBean {
188
189        /** Wrapper for a combined category and folder restriction. */
190        public static class ListCategoryFolderRestrictionBean {
191
192            /** The categories to restrict the search to. */
193            private List<String> m_categories;
194
195            /** The folders to restrict the search to. */
196            private List<String> m_folders;
197
198            /** The category combination mode, i.e., "AND" or "OR". */
199            private CategoryMode m_categoryMode;
200
201            /**
202             * Constructor for the wrapper.
203             * @param categories the categories to filter
204             * @param folders the folders to filter
205             * @param categoryMode the combination mode for categories
206             */
207            public ListCategoryFolderRestrictionBean(
208                List<String> categories,
209                List<String> folders,
210                CategoryMode categoryMode) {
211
212                m_categories = categories == null ? Collections.<String> emptyList() : categories;
213                m_folders = folders == null ? Collections.<String> emptyList() : folders;
214                m_categoryMode = categoryMode == null ? CategoryMode.OR : categoryMode;
215            }
216
217            /**
218             * Outputs the restriction as Solr filter query.
219             *
220             * @see java.lang.Object#toString()
221             */
222            @Override
223            public String toString() {
224
225                if (m_categories.isEmpty() && m_folders.isEmpty()) {
226                    return "";
227                }
228                String result = "(";
229                if (!m_categories.isEmpty()) {
230                    result += "category_exact:(";
231                    if (m_categories.size() > 1) {
232                        result += m_categories.stream().reduce(
233                            (cat1, cat2) -> "\"" + cat1 + "\" " + m_categoryMode + " \"" + cat2 + "\"").get();
234                    } else {
235                        result += "\"" + m_categories.get(0) + "\"";
236                    }
237                    result += ")";
238                }
239                if (!m_folders.isEmpty()) {
240                    if (!m_categories.isEmpty()) {
241                        result += " AND ";
242                    }
243                    result += "parent-folders:(";
244                    if (m_folders.size() > 1) {
245                        result += m_folders.stream().reduce((f1, f2) -> "\"" + f1 + "\" OR \"" + f2 + "\"").get();
246                    } else {
247                        result += "\"" + m_folders.get(0) + "\"";
248                    }
249                    result += ")";
250                }
251                result += ")";
252                return result;
253            }
254        }
255
256        /**
257         * Bean representing a Geo filter.
258         */
259        public static class ListGeoFilterBean {
260
261            /** The center point coordinates. */
262            private String m_coordinates;
263
264            /** The search radius. */
265            private String m_radius;
266
267            /**
268             * Creates a new Geo filter bean.
269             * @param coordinates the coordinates
270             * @param radius the radius
271             */
272            public ListGeoFilterBean(String coordinates, String radius) {
273
274                m_coordinates = coordinates;
275                m_radius = radius;
276            }
277
278            /**
279             * Returns the center point coordinates.
280             * @return the center point coordinates
281             */
282            public String getCoordinates() {
283
284                return m_coordinates;
285            }
286
287            /**
288             * Returns the search radius.
289             * @return the search radius
290             */
291            public String getRadius() {
292
293                return m_radius;
294            }
295        }
296
297        /** Special parameter to configure the maximally returned results. */
298        private static final String ADDITIONAL_PARAM_MAX_RETURNED_RESULTS = "maxresults";
299
300        /** The additional content parameters. */
301        private Map<String, String> m_additionalParameters;
302
303        /** The resource blacklist. */
304        private List<CmsUUID> m_blacklist;
305
306        /** The categories. */
307        private List<String> m_categories;
308
309        /** The category mode. */
310        private CategoryMode m_categoryMode;
311
312        /** The date restriction. */
313        private I_CmsListDateRestriction m_dateRestriction;
314
315        /** The display types. */
316        private List<String> m_dislayTypes;
317
318        /** The Geo filter */
319        private ListGeoFilterBean m_geoFilter;
320
321        /** The folders. */
322        private List<String> m_folders;
323
324        /** Search parameters by configuration node name. */
325        private Map<String, String> m_parameterFields;
326
327        /** Combined category and folder restrictions. */
328        private List<ListCategoryFolderRestrictionBean> m_categoryFolderRestrictions = new ArrayList<>();
329
330        /**
331         * Constructor.<p>
332         */
333        public ListConfigurationBean() {
334
335            m_parameterFields = new HashMap<String, String>();
336        }
337
338        /**
339         * Add a combined category-folder restriction.
340         * @param listCategoryFolderRestrictionBean the category-folder restriction to add.
341         */
342        public void addCategoryFolderFilter(ListCategoryFolderRestrictionBean listCategoryFolderRestrictionBean) {
343
344            m_categoryFolderRestrictions.add(listCategoryFolderRestrictionBean);
345
346        }
347
348        /**
349         * Returns the additional content parameters.<p>
350         *
351         * @return the additional content parameters
352         */
353        public Map<String, String> getAdditionalParameters() {
354
355            return m_additionalParameters;
356        }
357
358        /**
359         * Returns the black list.<p>
360         *
361         * @return the black list
362         */
363        public List<CmsUUID> getBlacklist() {
364
365            return m_blacklist;
366        }
367
368        /**
369         * Returns the categories.<p>
370         *
371         * @return the categories
372         */
373        public List<String> getCategories() {
374
375            return m_categories;
376        }
377
378        /**
379         * Returns the combined category-folder restrictions.<p>
380         *
381         * @return the combined category-folder restrictions
382         */
383        public List<ListCategoryFolderRestrictionBean> getCategoryFolderRestrictions() {
384
385            return m_categoryFolderRestrictions;
386        }
387
388        /**
389         * Gets the category mode.<p>
390         *
391         * @return the category mode
392         */
393        public CategoryMode getCategoryMode() {
394
395            return m_categoryMode;
396        }
397
398        /**
399         * Gets the date restriction.<p>
400         *
401         * @return the date restriction
402         */
403        public I_CmsListDateRestriction getDateRestriction() {
404
405            return m_dateRestriction;
406        }
407
408        /**
409         * Returns the display types.<p>
410         *
411         * @return the display types
412         */
413        public List<String> getDisplayTypes() {
414
415            return m_dislayTypes;
416        }
417
418        /**
419         * Gets the filter query.<p>
420         *
421         * @return the filter query
422         */
423        public String getFilterQuery() {
424
425            return m_parameterFields.get(N_FILTER_QUERY);
426        }
427
428        /**
429         * Returns the folders.<p>
430         *
431         * @return the folders
432         */
433        public List<String> getFolders() {
434
435            return m_folders;
436        }
437
438        /**
439         * Returns the Geo filter.<p>
440         *
441         * @return the Geo filter
442         */
443        public ListGeoFilterBean getGeoFilter() {
444
445            return m_geoFilter;
446        }
447
448        /**
449         * Returns the number of results to return maximally, or <code>null</code> if not explicitly specified.
450         * @return the number of results to return maximally, or <code>null</code> if not explicitly specified.
451         */
452        public Integer getMaximallyReturnedResults() {
453
454            String resString = m_parameterFields.get(N_MAX_RESULTS);
455            // Fallback, we first added the restriction as additional parameter. To make it more obvious, we integrated it as extra field.
456            // Only if the extra field is not set, we use the additional parameter to be backward compatible.
457            if (null == resString) {
458                m_additionalParameters.get(ADDITIONAL_PARAM_MAX_RETURNED_RESULTS);
459            }
460            if (null != resString) {
461                try {
462                    return Integer.valueOf(resString);
463                } catch (NumberFormatException e) {
464                    if (LOG.isErrorEnabled()) {
465                        LOG.error("Ignoring invalid maxresults param " + resString + " in list-config.");
466                    }
467                }
468            }
469            return null;
470        }
471
472        /**
473         * Returns the parameter map.<p>
474         *
475         * @return the parameters
476         */
477        public Map<String, String> getParameters() {
478
479            return m_parameterFields;
480        }
481
482        /**
483         * Returns the parameter by name.<p>
484         *
485         * @param key the parameter name
486         *
487         * @return the parameter value
488         */
489        public String getParameterValue(String key) {
490
491            return m_parameterFields.get(key);
492        }
493
494        /**
495         * Gets the sort order.<p>
496         *
497         * @return the sort order
498         */
499        public String getSortOrder() {
500
501            return getParameterValue(N_SORT_ORDER);
502        }
503
504        /**
505         * Returns the search types.<p>
506         *
507         * @return the search types
508         */
509        public List<String> getTypes() {
510
511            List<String> result = new ArrayList<String>();
512            if (m_dislayTypes != null) {
513                for (String displayType : m_dislayTypes) {
514                    String type = displayType;
515                    if (type.contains(CmsXmlDisplayFormatterValue.SEPARATOR)) {
516                        type = type.substring(0, type.indexOf(CmsXmlDisplayFormatterValue.SEPARATOR));
517                    }
518                    if (!result.contains(type)) {
519                        result.add(type);
520                    }
521                }
522            }
523            return result;
524        }
525
526        /**
527         * Returns the 'show expired' setting.<p>
528         *
529         * @return the 'show expired' setting
530         */
531        public boolean isShowExpired() {
532
533            return Boolean.parseBoolean(m_parameterFields.get(N_SHOW_EXPIRED));
534
535        }
536
537        /**
538         * Sets the additional content parameters.<p>
539         *
540         * @param additionalParameters the additional content parameters to set
541         */
542        public void setAdditionalParameters(Map<String, String> additionalParameters) {
543
544            m_additionalParameters = additionalParameters;
545        }
546
547        /**
548         * Sets the blacklist.<p>
549         *
550         * @param blacklist the blacklist
551         */
552        public void setBlacklist(List<CmsUUID> blacklist) {
553
554            m_blacklist = blacklist;
555        }
556
557        /**
558         * Sets the categories.<p>
559         *
560         * @param categories the categories
561         */
562        public void setCategories(List<String> categories) {
563
564            m_categories = categories;
565        }
566
567        /**
568         * Sets the category mode.<p>
569         *
570         * @param categoryMode the category mode to set
571         */
572        public void setCategoryMode(CategoryMode categoryMode) {
573
574            m_categoryMode = categoryMode;
575        }
576
577        /**
578         * Sets the date restrictions.<p>
579         *
580         * @param restriction the date restrictions
581         */
582        public void setDateRestriction(I_CmsListDateRestriction restriction) {
583
584            m_dateRestriction = restriction;
585        }
586
587        /**
588         * Sets the display types.<p>
589         *
590         * @param displayTypes the display types
591         */
592        public void setDisplayTypes(List<String> displayTypes) {
593
594            m_dislayTypes = displayTypes;
595        }
596
597        /**
598         * Sets the folders.<p>
599         *
600         * @param folders the folders
601         */
602        public void setFolders(List<String> folders) {
603
604            m_folders = folders;
605        }
606
607        /**
608         * Sets the Geo filter.<p>
609         *
610         * @param geoFilter the Geo filter
611         */
612        public void setGeoFilter(ListGeoFilterBean geoFilter) {
613
614            m_geoFilter = geoFilter;
615        }
616
617        /**
618         * Sets the parameter by name.<p>
619         *
620         * @param name the parameter name
621         * @param value the parameter value
622         */
623        public void setParameterValue(String name, String value) {
624
625            m_parameterFields.put(name, value);
626
627        }
628    }
629
630    /**
631     * Extended dialog context.<p>
632     */
633    protected class DialogContext extends CmsFileTableDialogContext {
634
635        /** The selected table items. */
636        private List<Item> m_selectedItems;
637
638        /**
639         * Constructor.<p>
640         *
641         * @param appId the app id
642         * @param contextType the context type
643         * @param fileTable the file table instance
644         * @param resources the list of selected resources
645         */
646        public DialogContext(
647            String appId,
648            ContextType contextType,
649            CmsFileTable fileTable,
650            List<CmsResource> resources) {
651
652            super(appId, contextType, fileTable, resources);
653        }
654
655        /**
656         * @see org.opencms.ui.components.CmsFileTableDialogContext#finish(java.util.Collection)
657         */
658        @Override
659        public void finish(Collection<CmsUUID> ids) {
660
661            if (m_selectedItems == null) {
662                super.finish(ids);
663            } else {
664                refreshResult();
665                closeWindow();
666            }
667        }
668
669        /**
670         * Returns the selected table items.<p>
671         *
672         * @return the selected table items
673         */
674        public List<Item> getSelectedItems() {
675
676            return m_selectedItems;
677        }
678
679        /**
680         * Sets the table items.<p>
681         *
682         * @param items the table items
683         */
684        public void setSelectedItems(List<Item> items) {
685
686            m_selectedItems = items;
687        }
688    }
689
690    /**
691     * Overrides the standard delete action to enable use of edit handlers.<p>
692     */
693    class DeleteAction extends CmsDeleteDialogAction {
694
695        /**
696         * @see org.opencms.ui.actions.CmsDeleteDialogAction#executeAction(org.opencms.ui.I_CmsDialogContext)
697         */
698        @Override
699        public void executeAction(final I_CmsDialogContext context) {
700
701            final CmsResource resource = context.getResources().get(0);
702            I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(resource);
703            if ((resourceType instanceof CmsResourceTypeXmlContent)
704                && (((CmsResourceTypeXmlContent)resourceType).getEditHandler(context.getCms()) != null)) {
705                final I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)resourceType).getEditHandler(
706                    context.getCms());
707                final CmsContainerElementBean elementBean = getElementForEditHandler((DialogContext)context);
708                CmsDialogOptions options = handler.getDeleteOptions(
709                    context.getCms(),
710                    elementBean,
711                    null,
712                    Collections.<String, String[]> emptyMap());
713                if (options == null) {
714                    super.executeAction(context);
715                } else if (options.getOptions().size() == 1) {
716                    deleteForOption(resource, elementBean, options.getOptions().get(0).getValue(), handler, context);
717                } else {
718                    Window window = CmsBasicDialog.prepareWindow();
719                    window.setCaption(options.getTitle());
720                    CmsOptionDialog dialog = new CmsOptionDialog(resource, options, new I_OptionHandler() {
721
722                        public void handleOption(String option) {
723
724                            deleteForOption(resource, elementBean, option, handler, context);
725                        }
726                    }, null, window);
727                    window.setContent(dialog);
728                    CmsAppWorkplaceUi.get().addWindow(window);
729                    dialog.initActionHandler(window);
730
731                }
732            } else {
733                super.executeAction(context);
734            }
735        }
736
737        /**
738         * Deletes with the given option.<p>
739         *
740         * @param resource the resource to delete
741         * @param elementBean the element bean
742         * @param deleteOption the delete option
743         * @param editHandler edit handler
744         * @param context the dialog context
745         */
746        void deleteForOption(
747            CmsResource resource,
748            CmsContainerElementBean elementBean,
749            String deleteOption,
750            I_CmsEditHandler editHandler,
751            I_CmsDialogContext context) {
752
753            try {
754                editHandler.handleDelete(context.getCms(), elementBean, deleteOption, null, null);
755            } catch (CmsException e) {
756                CmsErrorDialog.showErrorDialog(e);
757            }
758        }
759    }
760
761    /**
762     * Overrides the standard edit action to enable use of edit handlers.<p>
763     */
764    class EditAction extends CmsEditDialogAction {
765
766        /**
767         * @see org.opencms.ui.actions.CmsEditDialogAction#executeAction(org.opencms.ui.I_CmsDialogContext)
768         */
769        @Override
770        public void executeAction(final I_CmsDialogContext context) {
771
772            final CmsResource resource = context.getResources().get(0);
773            I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(resource);
774            if ((resourceType instanceof CmsResourceTypeXmlContent)
775                && (((CmsResourceTypeXmlContent)resourceType).getEditHandler(context.getCms()) != null)) {
776                final I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)resourceType).getEditHandler(
777                    context.getCms());
778                final CmsContainerElementBean elementBean = getElementForEditHandler((DialogContext)context);
779                CmsDialogOptions options = handler.getEditOptions(
780                    context.getCms(),
781                    elementBean,
782                    null,
783                    Collections.<String, String[]> emptyMap(),
784                    true);
785                if (options == null) {
786                    super.executeAction(context);
787                } else if (options.getOptions().size() == 1) {
788                    editForOption(resource, elementBean, options.getOptions().get(0).getValue(), handler, context);
789                } else {
790                    Window window = CmsBasicDialog.prepareWindow();
791                    window.setCaption(options.getTitle());
792                    CmsOptionDialog dialog = new CmsOptionDialog(resource, options, new I_OptionHandler() {
793
794                        public void handleOption(String option) {
795
796                            editForOption(resource, elementBean, option, handler, context);
797                        }
798                    }, null, window);
799                    window.setContent(dialog);
800                    CmsAppWorkplaceUi.get().addWindow(window);
801                    dialog.initActionHandler(window);
802
803                }
804            } else {
805                super.executeAction(context);
806            }
807        }
808
809        /**
810         * Calls the editor with the given option.<p>
811         *
812         * @param resource the resource to delete
813         * @param elementBean the element bean
814         * @param editOption the edit option
815         * @param editHandler edit handler
816         * @param context the dialog context
817         */
818        void editForOption(
819            CmsResource resource,
820            CmsContainerElementBean elementBean,
821            String editOption,
822            I_CmsEditHandler editHandler,
823            I_CmsDialogContext context) {
824
825            try {
826                CmsUUID id = editHandler.prepareForEdit(
827                    context.getCms(),
828                    elementBean,
829                    editOption,
830                    null,
831                    Collections.<String, String[]> emptyMap());
832                if (resource.getStructureId().equals(id)) {
833                    super.executeAction(context);
834                } else if (id != null) {
835                    CmsFileTableDialogContext changedContext = new CmsFileTableDialogContext(
836                        CmsProjectManagerConfiguration.APP_ID,
837                        ContextType.fileTable,
838                        m_resultTable,
839                        Collections.singletonList(context.getCms().readResource(id)));
840                    super.executeAction(changedContext);
841                }
842            } catch (CmsException e) {
843                CmsErrorDialog.showErrorDialog(e);
844            }
845        }
846    }
847
848    /** SOLR field name. */
849    public static final String FIELD_CATEGORIES = "category_exact";
850
851    /** SOLR field name. */
852    public static final String FIELD_DATE = "instancedate_%s_dt";
853
854    /** SOLR field name. */
855    public static final String FIELD_DATE_RANGE = "instancedaterange_%s_dr";
856
857    /** SOLR field name. */
858    public static final String FIELD_DATE_FACET_NAME = "instancedate";
859
860    /** SOLR field name. */
861    public static final String FIELD_PARENT_FOLDERS = "parent-folders";
862
863    /** List configuration node name and field key. */
864    public static final String N_BLACKLIST = "Blacklist";
865
866    /** List configuration node name and field key. */
867    public static final String N_CATEGORY = "Category";
868
869    /** List configuration node name and field key. */
870    private static final String N_CATEGORY_FOLDER_RESTRICTION = "CategoryFolderFilter";
871
872    /** List configuration node name and field key. */
873    private static final String N_COORDINATES = "Coordinates";
874
875    /** List configuration node name and field key. */
876    private static final String N_FOLDER = "Folder";
877
878    /** List configuration node name for the category mode. */
879    public static final String N_CATEGORY_MODE = "CategoryMode";
880
881    /** XML content node name. */
882    public static final String N_DATE_RESTRICTION = "DateRestriction";
883
884    /** List configuration node name and field key. */
885    public static final String N_DISPLAY_TYPE = "TypesToCollect";
886
887    /** List configuration node name and field key. */
888    public static final String N_FILTER_MULTI_DAY = "FilterMultiDay";
889
890    /** List configuration node name and field key. */
891    public static final String N_FILTER_QUERY = "FilterQuery";
892
893    /** List configuration node name and field key. */
894    public static final String N_GEO_FILTER = "GeoFilter";
895
896    /** List configuration node name and field key. */
897    public static final String N_KEY = "Key";
898
899    /** List configuration node name and field key. */
900    public static final String N_PARAMETER = "Parameter";
901
902    /** List configuration node name and field key. */
903    public static final String N_RADIUS = "Radius";
904
905    /** List configuration node name and field key. */
906    public static final String N_SEARCH_FOLDER = "SearchFolder";
907
908    /** List configuration node name and field key. */
909    public static final String N_SHOW_EXPIRED = "ShowExpired";
910
911    /** List configuration node name and field key. */
912    public static final String N_SORT_ORDER = "SortOrder";
913
914    /** List configuration node name and field key. */
915    public static final String N_TITLE = "Title";
916
917    /** List configuration node name and field key. */
918    public static final String N_VALUE = "Value";
919
920    /** List configuration node name and field key. */
921    public static final String PARAM_LOCALE = "locale";
922
923    /** List configuration node name and field key. */
924    public static final String N_MAX_RESULTS = "MaxResults";
925
926    /** The parameter fields. */
927    public static final String[] PARAMETER_FIELDS = new String[] {
928        N_TITLE,
929        N_CATEGORY,
930        N_FILTER_MULTI_DAY,
931        N_FILTER_QUERY,
932        N_SORT_ORDER,
933        N_SHOW_EXPIRED,
934        N_MAX_RESULTS};
935
936    /** The view content list path name. */
937    public static final String PATH_NAME_VIEW = "view";
938
939    /** The list configuration resource type name. */
940    public static final String RES_TYPE_LIST_CONFIG = "listconfig";
941
942    /** The blacklisted table column property id. */
943    protected static final CmsResourceTableProperty BLACKLISTED_PROPERTY = new CmsResourceTableProperty(
944        "BLACKLISTED",
945        Boolean.class,
946        Boolean.FALSE,
947        Messages.GUI_LISTMANAGER_COLUMN_BLACKLISTED_0,
948        true,
949        0,
950        110);
951
952    /** The date series info table column property id. */
953    protected static final CmsResourceTableProperty INFO_PROPERTY = new CmsResourceTableProperty(
954        "INFO_PROPERTY",
955        String.class,
956        null,
957        null,
958        true,
959        1,
960        0);
961
962    /** The date series info label table column property id. */
963    protected static final CmsResourceTableProperty INFO_PROPERTY_LABEL = new CmsResourceTableProperty(
964        "INFO_PROPERTY_LABEL",
965        String.class,
966        null,
967        Messages.GUI_LISTMANAGER_COLUMN_INFO_0,
968        true,
969        0,
970        110);
971
972    /** The blacklisted table column property id. */
973    protected static final CmsResourceTableProperty INSTANCEDATE_PROPERTY = new CmsResourceTableProperty(
974        "INSTANCEDATE_PROPERTY",
975        Date.class,
976        null,
977        Messages.GUI_LISTMANAGER_COLUMN_INSTANCEDATE_0,
978        true,
979        0,
980        145);
981
982    /** The available sort options. */
983    protected static final String[][] SORT_OPTIONS = new String[][] {
984        {
985            SortOption.DATE_ASC.toString(),
986            SortOption.DATE_DESC.toString(),
987            SortOption.TITLE_ASC.toString(),
988            SortOption.TITLE_DESC.toString(),
989            SortOption.ORDER_ASC.toString(),
990            SortOption.ORDER_DESC.toString()},
991        {
992            Messages.GUI_LISTMANAGER_SORT_DATE_ASC_0,
993            Messages.GUI_LISTMANAGER_SORT_DATE_DESC_0,
994            Messages.GUI_LISTMANAGER_SORT_TITLE_ASC_0,
995            Messages.GUI_LISTMANAGER_SORT_TITLE_DESC_0,
996            Messages.GUI_LISTMANAGER_SORT_ORDER_ASC_0,
997            Messages.GUI_LISTMANAGER_SORT_ORDER_DESC_0}};
998
999    /** The month name abbreviations. */
1000    static final String[] MONTHS = new String[] {
1001        "JAN",
1002        "FEB",
1003        "MAR",
1004        "APR",
1005        "MAY",
1006        "JUN",
1007        "JUL",
1008        "AUG",
1009        "SEP",
1010        "OCT",
1011        "NOV",
1012        "DEC"};
1013
1014    /** The logger for this class. */
1015    static final Log LOG = CmsLog.getLog(CmsListManager.class.getName());
1016
1017    /** Default backend pagination. */
1018    private static final I_CmsSearchConfigurationPagination PAGINATION = new CmsSearchConfigurationPagination(
1019        null,
1020        Integer.valueOf(10000),
1021        Integer.valueOf(1));
1022
1023    /** The serial version id. */
1024    private static final long serialVersionUID = -25954374225590319L;
1025
1026    /** The current list configuration data. */
1027    ListConfigurationBean m_currentConfig;
1028
1029    /** The current list configuration resource. */
1030    CmsResource m_currentResource;
1031
1032    /** The result table. */
1033    CmsResultTable m_resultTable;
1034
1035    /** The create new button. */
1036    private Button m_createNewButton;
1037
1038    /** The current search parser. */
1039    private CmsSimpleSearchConfigurationParser m_currentConfigParser;
1040
1041    /** The current app state. */
1042    private String m_currentState;
1043
1044    /** The current edit dialog window. */
1045    private Window m_dialogWindow;
1046
1047    /** The edit current configuration button. */
1048    private Button m_editCurrentButton;
1049
1050    /** Indicates multiple instances of a series are present in the current search result. */
1051    private boolean m_hasSeriesInstances;
1052
1053    /** Indicates series types are present in the current search result. */
1054    private boolean m_hasSeriesType;
1055
1056    /** Flag indicating individual instances of a date series should be hidden. */
1057    private boolean m_hideSeriesInstances;
1058
1059    /** The info button. */
1060    private Button m_infoButton;
1061
1062    /** Indicates if the overview list is shown. */
1063    private boolean m_isOverView;
1064
1065    /** The locale select. */
1066    private ComboBox m_localeSelect;
1067
1068    /** The current lock action. */
1069    private CmsLockActionRecord m_lockAction;
1070
1071    /** The list configurations overview table. */
1072    private CmsFileTable m_overviewTable;
1073
1074    /** The publish button. */
1075    private Button m_publishButton;
1076
1077    /** The resetting flag. */
1078    private boolean m_resetting;
1079
1080    /** The facet result display. */
1081    private CmsResultFacets m_resultFacets;
1082
1083    /** The mail layout. */
1084    private HorizontalSplitPanel m_resultLayout;
1085
1086    /** The sort select. */
1087    private ComboBox m_resultSorter;
1088
1089    /** The table filter input. */
1090    private TextField m_tableFilter;
1091
1092    /** The text search input. */
1093    private TextField m_textSearch;
1094
1095    /** The toggle date series display. */
1096    private Button m_toggleSeriesButton;
1097
1098    /**
1099     * Parses the list configuration resource.<p>
1100     *
1101     * @param cms the CMS context to use
1102     * @param res the list configuration resource
1103     *
1104     * @return the configuration data bean
1105     */
1106    public static ListConfigurationBean parseListConfiguration(CmsObject cms, CmsResource res) {
1107
1108        ListConfigurationBean result = new ListConfigurationBean();
1109        try {
1110            CmsFile configFile = cms.readFile(res);
1111            CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, configFile);
1112            Locale locale = CmsLocaleManager.MASTER_LOCALE;
1113
1114            if (!content.hasLocale(locale)) {
1115                locale = content.getLocales().get(0);
1116            }
1117            for (String field : PARAMETER_FIELDS) {
1118                String val = content.getStringValue(cms, field, locale);
1119                if (N_CATEGORY.equals(field)) {
1120                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(val)) {
1121                        result.setCategories(Arrays.asList(val.split(",")));
1122                    } else {
1123                        result.setCategories(Collections.<String> emptyList());
1124                    }
1125                } else {
1126                    result.setParameterValue(field, val);
1127                }
1128            }
1129
1130            I_CmsXmlContentValue restrictValue = content.getValue(N_DATE_RESTRICTION, locale);
1131            if (restrictValue != null) {
1132                CmsDateRestrictionParser parser = new CmsDateRestrictionParser(cms);
1133                I_CmsListDateRestriction restriction = parser.parse(new CmsXmlContentValueLocation(restrictValue));
1134                if (restriction == null) {
1135                    LOG.warn(
1136                        "Improper date restriction configuration in content "
1137                            + content.getFile().getRootPath()
1138                            + ", online="
1139                            + cms.getRequestContext().getCurrentProject().isOnlineProject());
1140                }
1141                result.setDateRestriction(restriction);
1142            }
1143
1144            I_CmsXmlContentValue geoFilterValue = content.getValue(N_GEO_FILTER, locale);
1145            if (geoFilterValue != null) {
1146                String coordinatesPath = geoFilterValue.getPath() + "/" + N_COORDINATES;
1147                String radiusPath = geoFilterValue.getPath() + "/" + N_RADIUS;
1148                I_CmsXmlContentValue coordinatesValue = content.getValue(coordinatesPath, locale);
1149                I_CmsXmlContentValue radiusValue = content.getValue(radiusPath, locale);
1150                String coordinates = CmsGeoUtil.parseCoordinates(coordinatesValue.getStringValue(cms));
1151                String radius = radiusValue.getStringValue(cms);
1152                boolean radiusValid = false;
1153                try {
1154                    Float.parseFloat(radius);
1155                    radiusValid = true;
1156                } catch (NumberFormatException e) {
1157                    radiusValid = false;
1158                }
1159                if ((coordinates != null) && radiusValid) {
1160                    ListGeoFilterBean listGeoFilterBean = new ListGeoFilterBean(coordinates, radius);
1161                    result.setGeoFilter(listGeoFilterBean);
1162                } else {
1163                    LOG.warn(
1164                        "Improper Geo filter in content "
1165                            + content.getFile().getRootPath()
1166                            + ", online="
1167                            + cms.getRequestContext().getCurrentProject().isOnlineProject());
1168                }
1169            }
1170
1171            I_CmsXmlContentValue categoryModeVal = content.getValue(N_CATEGORY_MODE, locale);
1172            CategoryMode categoryMode = CategoryMode.OR;
1173            if (categoryModeVal != null) {
1174                try {
1175                    categoryMode = CategoryMode.valueOf(categoryModeVal.getStringValue(cms));
1176                } catch (Exception e) {
1177                    LOG.error(e.getLocalizedMessage(), e);
1178                }
1179            }
1180            result.setCategoryMode(categoryMode);
1181
1182            LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>();
1183            for (I_CmsXmlContentValue parameter : content.getValues(N_PARAMETER, locale)) {
1184                I_CmsXmlContentValue keyVal = content.getValue(parameter.getPath() + "/" + N_KEY, locale);
1185                I_CmsXmlContentValue valueVal = content.getValue(parameter.getPath() + "/" + N_VALUE, locale);
1186                if ((keyVal != null)
1187                    && CmsStringUtil.isNotEmptyOrWhitespaceOnly(keyVal.getStringValue(cms))
1188                    && (valueVal != null)) {
1189                    parameters.put(keyVal.getStringValue(cms), valueVal.getStringValue(cms));
1190                }
1191            }
1192            result.setAdditionalParameters(parameters);
1193            List<String> displayTypes = new ArrayList<String>();
1194            List<I_CmsXmlContentValue> typeValues = content.getValues(N_DISPLAY_TYPE, locale);
1195            if (!typeValues.isEmpty()) {
1196                for (I_CmsXmlContentValue value : typeValues) {
1197                    displayTypes.add(value.getStringValue(cms));
1198                }
1199            }
1200            result.setDisplayTypes(displayTypes);
1201            List<String> folders = new ArrayList<String>();
1202            List<I_CmsXmlContentValue> folderValues = content.getValues(N_SEARCH_FOLDER, locale);
1203            if (!folderValues.isEmpty()) {
1204                for (I_CmsXmlContentValue value : folderValues) {
1205                    CmsLink val = ((CmsXmlVfsFileValue)value).getLink(cms);
1206                    if (val != null) {
1207                        // we are using root paths
1208                        folders.add(cms.getRequestContext().addSiteRoot(val.getSitePath(cms)));
1209                    }
1210                }
1211            }
1212            result.setFolders(folders);
1213            List<CmsUUID> blackList = new ArrayList<CmsUUID>();
1214            List<I_CmsXmlContentValue> blacklistValues = content.getValues(N_BLACKLIST, locale);
1215            if (!blacklistValues.isEmpty()) {
1216                for (I_CmsXmlContentValue value : blacklistValues) {
1217                    CmsLink link = ((CmsXmlVfsFileValue)value).getLink(cms);
1218                    if (link != null) {
1219                        blackList.add(link.getStructureId());
1220                    }
1221                }
1222            }
1223            List<I_CmsXmlContentValue> categoryFolderRestrictions = content.getValues(
1224                N_CATEGORY_FOLDER_RESTRICTION,
1225                locale);
1226            if (!categoryFolderRestrictions.isEmpty()) {
1227                for (I_CmsXmlContentValue restriction : categoryFolderRestrictions) {
1228                    List<String> restrictionFolders = new ArrayList<>();
1229                    List<I_CmsXmlContentValue> folderVals = content.getValues(
1230                        CmsXmlUtils.concatXpath(restriction.getPath(), N_FOLDER),
1231                        locale);
1232                    for (I_CmsXmlContentValue folderVal : folderVals) {
1233                        CmsLink val = ((CmsXmlVfsFileValue)folderVal).getLink(cms);
1234                        if (val != null) {
1235                            // we are using root paths
1236                            restrictionFolders.add(cms.getRequestContext().addSiteRoot(val.getSitePath(cms)));
1237                        }
1238                    }
1239                    List<String> restrictionCategorySitePaths;
1240                    I_CmsXmlContentValue categoryVal = content.getValue(
1241                        CmsXmlUtils.concatXpath(restriction.getPath(), N_CATEGORY),
1242                        locale);
1243                    String categoryString = null != categoryVal ? categoryVal.getStringValue(cms) : "";
1244                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(categoryString)) {
1245                        restrictionCategorySitePaths = Arrays.asList(categoryString.split(","));
1246                    } else {
1247                        restrictionCategorySitePaths = Collections.<String> emptyList();
1248                    }
1249                    List<String> restrictionCategories = new ArrayList<>(restrictionCategorySitePaths.size());
1250                    for (String sitePath : restrictionCategorySitePaths) {
1251                        try {
1252                            String path = CmsCategoryService.getInstance().getCategory(
1253                                cms,
1254                                cms.getRequestContext().addSiteRoot(sitePath)).getPath();
1255                            restrictionCategories.add(path);
1256                        } catch (CmsException e) {
1257                            LOG.warn(e.getLocalizedMessage(), e);
1258                        }
1259                    }
1260                    String restrictionCategoryMode = content.getValue(
1261                        CmsXmlUtils.concatXpath(restriction.getPath(), N_CATEGORY_MODE),
1262                        locale).getStringValue(cms);
1263                    result.addCategoryFolderFilter(
1264                        new ListCategoryFolderRestrictionBean(
1265                            restrictionCategories,
1266                            restrictionFolders,
1267                            null == restrictionCategoryMode ? null : CategoryMode.valueOf(restrictionCategoryMode)));
1268
1269                }
1270            }
1271            result.setBlacklist(blackList);
1272        } catch (CmsException e) {
1273            e.printStackTrace();
1274        }
1275        return result;
1276    }
1277
1278    /**
1279     * @see org.opencms.ui.components.CmsResourceTable.I_ResourcePropertyProvider#addItemProperties(com.vaadin.v7.data.Item, org.opencms.file.CmsObject, org.opencms.file.CmsResource, java.util.Locale)
1280     */
1281    @Override
1282    public void addItemProperties(Item resourceItem, CmsObject cms, CmsResource resource, Locale locale) {
1283
1284        if ((m_currentConfig != null) && (resourceItem.getItemProperty(CmsListManager.BLACKLISTED_PROPERTY) != null)) {
1285            resourceItem.getItemProperty(CmsListManager.BLACKLISTED_PROPERTY).setValue(
1286                Boolean.valueOf(m_currentConfig.getBlacklist().contains(resource.getStructureId())));
1287        }
1288        if ((m_currentConfig != null)
1289            && (resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TITLE) != null)) {
1290            CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource);
1291            String title = resUtil.getGalleryTitle((Locale)m_localeSelect.getValue());
1292            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(title)) {
1293                resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TITLE).setValue(title);
1294            }
1295        }
1296        if ((resource instanceof CmsSearchResource)
1297            && (resourceItem.getItemProperty(CmsListManager.INFO_PROPERTY_LABEL) != null)) {
1298            String seriesType = ((CmsSearchResource)resource).getField(CmsSearchField.FIELD_SERIESDATES_TYPE);
1299            resourceItem.getItemProperty(CmsListManager.INFO_PROPERTY_LABEL).setValue(
1300                CmsVaadinUtils.getMessageText(
1301                    "GUI_LISTMANAGER_SERIES_TYPE_" + (seriesType == null ? "DEFAULT" : seriesType) + "_0"));
1302            resourceItem.getItemProperty(CmsListManager.INFO_PROPERTY).setValue(seriesType);
1303
1304        }
1305        if ((resource instanceof CmsSearchResource)
1306            && (resourceItem.getItemProperty(CmsListManager.INSTANCEDATE_PROPERTY) != null)) {
1307            Date date = ((CmsSearchResource)resource).getDateField(m_resultTable.getDateFieldKey());
1308            resourceItem.getItemProperty(CmsListManager.INSTANCEDATE_PROPERTY).setValue(date);
1309        }
1310    }
1311
1312    /**
1313     * @see com.vaadin.navigator.ViewChangeListener#afterViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
1314     */
1315    @Override
1316    public void afterViewChange(ViewChangeEvent event) {
1317
1318        // nothing to do
1319    }
1320
1321    /**
1322     * @see com.vaadin.navigator.ViewChangeListener#beforeViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
1323     */
1324    @Override
1325    public boolean beforeViewChange(ViewChangeEvent event) {
1326
1327        unlockCurrent();
1328        return true;
1329    }
1330
1331    /**
1332     * @see org.opencms.ui.apps.I_CmsContextProvider#getDialogContext()
1333     */
1334    @Override
1335    public I_CmsDialogContext getDialogContext() {
1336
1337        CmsFileTable table = isOverView() ? m_overviewTable : m_resultTable;
1338        List<CmsResource> resources = table.getSelectedResources();
1339        DialogContext context = new DialogContext(
1340            CmsProjectManagerConfiguration.APP_ID,
1341            ContextType.fileTable,
1342            table,
1343            resources);
1344        if (!isOverView()) {
1345            context.setSelectedItems(m_resultTable.getSelectedItems());
1346        }
1347        return context;
1348    }
1349
1350    /**
1351     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext)
1352     */
1353    @Override
1354    public void initUI(I_CmsAppUIContext uiContext) {
1355
1356        super.initUI(uiContext);
1357        m_publishButton = CmsToolBar.createButton(
1358            FontOpenCms.PUBLISH,
1359            CmsVaadinUtils.getMessageText(Messages.GUI_PUBLISH_BUTTON_TITLE_0));
1360        if (CmsAppWorkplaceUi.isOnlineProject()) {
1361            // disable publishing in online project
1362            m_publishButton.setEnabled(false);
1363            m_publishButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0));
1364        }
1365
1366        m_publishButton.addClickListener(new ClickListener() {
1367
1368            /** Serial version id. */
1369            private static final long serialVersionUID = 1L;
1370
1371            @Override
1372            public void buttonClick(ClickEvent event) {
1373
1374                publish();
1375            }
1376        });
1377        uiContext.addToolbarButton(m_publishButton);
1378
1379        m_editCurrentButton = CmsToolBar.createButton(
1380            FontOpenCms.PEN,
1381            CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_EDIT_CONFIG_0));
1382        m_editCurrentButton.addClickListener(new ClickListener() {
1383
1384            /** Serial version id. */
1385            private static final long serialVersionUID = 1L;
1386
1387            @Override
1388            public void buttonClick(ClickEvent event) {
1389
1390                editListConfiguration(m_currentResource);
1391            }
1392        });
1393        uiContext.addToolbarButton(m_editCurrentButton);
1394
1395        m_infoButton = CmsToolBar.createButton(
1396            FontOpenCms.INFO,
1397            CmsVaadinUtils.getMessageText(org.opencms.ui.Messages.GUI_RESOURCE_INFO_0));
1398        m_infoButton.addClickListener(new ClickListener() {
1399
1400            /** Serial version id. */
1401            private static final long serialVersionUID = 1L;
1402
1403            @Override
1404            public void buttonClick(ClickEvent event) {
1405
1406                DialogContext context = new DialogContext(
1407                    CmsProjectManagerConfiguration.APP_ID,
1408                    ContextType.fileTable,
1409                    m_resultTable,
1410                    Collections.singletonList(m_currentResource));
1411                CmsResourceInfoAction action = new CmsResourceInfoAction();
1412                action.openDialog(context, CmsResourceStatusTabId.tabRelationsTo.name());
1413            }
1414        });
1415        uiContext.addToolbarButton(m_infoButton);
1416
1417        m_toggleSeriesButton = CmsToolBar.createButton(
1418            FontOpenCms.LIST,
1419            CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_TOGGLE_SERIES_BUTTON_0));
1420        m_toggleSeriesButton.addClickListener(new ClickListener() {
1421
1422            /** Serial version id. */
1423            private static final long serialVersionUID = 1L;
1424
1425            @Override
1426            public void buttonClick(ClickEvent event) {
1427
1428                toggleDateSeries();
1429            }
1430        });
1431        uiContext.addToolbarButton(m_toggleSeriesButton);
1432
1433        m_createNewButton = CmsToolBar.createButton(
1434            FontOpenCms.WAND,
1435            CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_CREATE_NEW_0));
1436        m_createNewButton.addClickListener(new ClickListener() {
1437
1438            /** Serial version id. */
1439            private static final long serialVersionUID = 1L;
1440
1441            @Override
1442            public void buttonClick(ClickEvent event) {
1443
1444                createNew();
1445            }
1446        });
1447        uiContext.addToolbarButton(m_createNewButton);
1448
1449        m_rootLayout.setMainHeightFull(true);
1450        m_resultLayout = new HorizontalSplitPanel();
1451        m_resultLayout.setSizeFull();
1452        m_resultFacets = new CmsResultFacets(this);
1453        m_resultFacets.setWidth("100%");
1454        m_resultLayout.setFirstComponent(m_resultFacets);
1455        LinkedHashMap<CmsResourceTableProperty, Integer> tableColumns = new LinkedHashMap<CmsResourceTableProperty, Integer>();
1456        // insert columns a specific positions
1457        for (Map.Entry<CmsResourceTableProperty, Integer> columnsEntry : CmsFileTable.DEFAULT_TABLE_PROPERTIES.entrySet()) {
1458            if (columnsEntry.getKey().equals(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME)) {
1459                tableColumns.put(INFO_PROPERTY_LABEL, Integer.valueOf(0));
1460            } else if (columnsEntry.getKey().equals(CmsResourceTableProperty.PROPERTY_RESOURCE_TYPE)) {
1461                tableColumns.put(INSTANCEDATE_PROPERTY, Integer.valueOf(0));
1462            }
1463            tableColumns.put(columnsEntry.getKey(), columnsEntry.getValue());
1464        }
1465        tableColumns.put(BLACKLISTED_PROPERTY, Integer.valueOf(CmsResourceTable.INVISIBLE));
1466        tableColumns.put(INFO_PROPERTY, Integer.valueOf(CmsResourceTable.INVISIBLE));
1467        m_resultTable = new CmsResultTable(null, tableColumns);
1468        m_resultTable.applyWorkplaceAppSettings();
1469        CmsResourceContextMenuBuilder menuBuilderOverView = new CmsResourceContextMenuBuilder();
1470        menuBuilderOverView.addMenuItemProvider(OpenCms.getWorkplaceAppManager().getMenuItemProvider());
1471        menuBuilderOverView.addMenuItemProvider(new I_CmsContextMenuItemProvider() {
1472
1473            @Override
1474            public List<I_CmsContextMenuItem> getMenuItems() {
1475
1476                return Arrays.<I_CmsContextMenuItem> asList(new CmsContextMenuActionItem(new CmsEditDialogAction() {
1477
1478                    @Override
1479                    public void executeAction(I_CmsDialogContext context) {
1480
1481                        editListConfiguration(context.getResources().get(0));
1482                    }
1483                }, null, 10, 1000));
1484            }
1485        });
1486        CmsResourceContextMenuBuilder menuBuilder = new CmsResourceContextMenuBuilder();
1487        menuBuilder.addMenuItemProvider(OpenCms.getWorkplaceAppManager().getMenuItemProvider());
1488        menuBuilder.addMenuItemProvider(new I_CmsContextMenuItemProvider() {
1489
1490            @Override
1491            public List<I_CmsContextMenuItem> getMenuItems() {
1492
1493                return Arrays.<I_CmsContextMenuItem> asList(new CmsContextMenuActionItem(new A_CmsWorkplaceAction() {
1494
1495                    @Override
1496                    public void executeAction(I_CmsDialogContext context) {
1497
1498                        CmsUUID structureId = context.getResources().get(0).getStructureId();
1499                        m_currentConfig.getBlacklist().add(structureId);
1500                        saveBlacklist(m_currentConfig);
1501                        context.finish(Collections.singletonList(structureId));
1502                    }
1503
1504                    @Override
1505                    public String getId() {
1506
1507                        return "hideresource";
1508                    }
1509
1510                    @Override
1511                    public String getTitleKey() {
1512
1513                        return Messages.GUI_LISTMANAGER_BLACKLIST_MENU_ENTRY_0;
1514                    }
1515
1516                    @Override
1517                    public CmsMenuItemVisibilityMode getVisibility(CmsObject cms, List<CmsResource> resources) {
1518
1519                        if ((m_currentConfig != null)
1520                            && (resources != null)
1521                            && (resources.size() == 1)
1522                            && !m_currentConfig.getBlacklist().contains(resources.get(0).getStructureId())) {
1523                            return CmsEditDialogAction.VISIBILITY.getVisibility(
1524                                cms,
1525                                Collections.singletonList(m_currentResource));
1526                        } else {
1527                            return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE;
1528                        }
1529                    }
1530
1531                }, null, 10, 0), new CmsContextMenuActionItem(new A_CmsWorkplaceAction() {
1532
1533                    @Override
1534                    public void executeAction(I_CmsDialogContext context) {
1535
1536                        CmsUUID structureId = context.getResources().get(0).getStructureId();
1537                        m_currentConfig.getBlacklist().remove(structureId);
1538                        saveBlacklist(m_currentConfig);
1539                        context.finish(Collections.singletonList(structureId));
1540                    }
1541
1542                    @Override
1543                    public String getId() {
1544
1545                        return "showresource";
1546                    }
1547
1548                    @Override
1549                    public String getTitleKey() {
1550
1551                        return Messages.GUI_LISTMANAGER_REMOVE_FROM_BLACKLIST_MENU_ENTRY_0;
1552                    }
1553
1554                    @Override
1555                    public CmsMenuItemVisibilityMode getVisibility(CmsObject cms, List<CmsResource> resources) {
1556
1557                        if ((m_currentConfig != null)
1558                            && (resources != null)
1559                            && (resources.size() == 1)
1560                            && m_currentConfig.getBlacklist().contains(resources.get(0).getStructureId())) {
1561                            return CmsEditDialogAction.VISIBILITY.getVisibility(
1562                                cms,
1563                                Collections.singletonList(m_currentResource));
1564                        } else {
1565                            return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE;
1566                        }
1567                    }
1568
1569                }, null, 10, 0),
1570                    new CmsContextMenuActionItem(new EditAction(), null, 10, 1000),
1571                    new CmsContextMenuActionItem(new DeleteAction(), null, 10, 1000));
1572            }
1573        });
1574        m_resultTable.setMenuBuilder(menuBuilder);
1575        m_resultTable.addAdditionalStyleGenerator(new CellStyleGenerator() {
1576
1577            private static final long serialVersionUID = 1L;
1578
1579            @Override
1580            public String getStyle(Table source, Object itemId, Object propertyId) {
1581
1582                String style = "";
1583                Item item = source.getItem(itemId);
1584                Boolean blacklisted = (Boolean)item.getItemProperty(BLACKLISTED_PROPERTY).getValue();
1585                if (blacklisted.booleanValue()) {
1586                    style += OpenCmsTheme.PROJECT_OTHER + " ";
1587                } else if (CmsResourceTableProperty.PROPERTY_TITLE.equals(propertyId)
1588                    && ((item.getItemProperty(CmsResourceTableProperty.PROPERTY_RELEASED_NOT_EXPIRED) == null)
1589                        || ((Boolean)item.getItemProperty(
1590                            CmsResourceTableProperty.PROPERTY_RELEASED_NOT_EXPIRED).getValue()).booleanValue())) {
1591                                style += OpenCmsTheme.IN_NAVIGATION + " ";
1592                            }
1593                if (INFO_PROPERTY_LABEL.equals(propertyId)) {
1594                    if (blacklisted.booleanValue()) {
1595                        style += OpenCmsTheme.TABLE_COLUMN_BOX_BLACK;
1596                    } else {
1597                        Object value = item.getItemProperty(INFO_PROPERTY).getValue();
1598                        if (value == null) {
1599                            style += OpenCmsTheme.TABLE_COLUMN_BOX_GRAY;
1600                        } else {
1601                            I_CmsSerialDateValue.DateType type = I_CmsSerialDateValue.DateType.valueOf((String)value);
1602                            switch (type) {
1603                                case SERIES:
1604                                    style += OpenCmsTheme.TABLE_COLUMN_BOX_BLUE_LIGHT;
1605                                    break;
1606                                case SINGLE:
1607                                    style += OpenCmsTheme.TABLE_COLUMN_BOX_GRAY;
1608                                    break;
1609                                case EXTRACTED:
1610                                    style += OpenCmsTheme.TABLE_COLUMN_BOX_ORANGE;
1611                                    break;
1612                                default:
1613                                    break;
1614                            }
1615                        }
1616                    }
1617                }
1618                return style;
1619            }
1620        });
1621        final ItemDescriptionGenerator defaultDescriptionGenerator = new CmsResourceTable.DefaultItemDescriptionGenerator();
1622        m_resultTable.setsetItemDescriptionGenerator(new ItemDescriptionGenerator() {
1623
1624            private static final long serialVersionUID = 1L;
1625
1626            public String generateDescription(Component source, Object itemId, Object propertyId) {
1627
1628                Item item = ((Table)source).getItem(itemId);
1629                if (INFO_PROPERTY_LABEL.equals(propertyId)
1630                    && ((Boolean)item.getItemProperty(BLACKLISTED_PROPERTY).getValue()).booleanValue()) {
1631                    return CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_COLUMN_BLACKLISTED_0);
1632                }
1633                return defaultDescriptionGenerator.generateDescription(source, itemId, propertyId);
1634            }
1635        });
1636        m_resultTable.setContextProvider(this);
1637        m_resultTable.addPropertyProvider(this);
1638        m_resultTable.setSizeFull();
1639        m_resultLayout.setSecondComponent(m_resultTable);
1640        m_overviewTable = new CmsFileTable(this);
1641        m_overviewTable.applyWorkplaceAppSettings();
1642        m_overviewTable.setMenuBuilder(menuBuilderOverView);
1643        m_overviewTable.setSizeFull();
1644
1645        m_tableFilter = new TextField();
1646        m_tableFilter.setIcon(FontOpenCms.FILTER);
1647        m_tableFilter.setInputPrompt(
1648            Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0));
1649        m_tableFilter.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
1650        m_tableFilter.setWidth("200px");
1651        m_tableFilter.addTextChangeListener(new TextChangeListener() {
1652
1653            private static final long serialVersionUID = 1L;
1654
1655            @Override
1656            public void textChange(TextChangeEvent event) {
1657
1658                filterTable(event.getText());
1659
1660            }
1661        });
1662        m_infoLayout.addComponent(m_tableFilter);
1663
1664        m_localeSelect = new ComboBox();
1665        m_localeSelect.setNullSelectionAllowed(false);
1666        m_localeSelect.setWidth("100px");
1667        m_localeSelect.addValueChangeListener(new ValueChangeListener() {
1668
1669            /** Serial version id. */
1670            private static final long serialVersionUID = 1L;
1671
1672            @Override
1673            public void valueChange(ValueChangeEvent event) {
1674
1675                changeContentLocale((Locale)event.getProperty().getValue());
1676            }
1677        });
1678        m_infoLayout.addComponent(m_localeSelect);
1679
1680        m_resultSorter = new ComboBox();
1681        m_resultSorter.setNullSelectionAllowed(false);
1682        m_resultSorter.setWidth("200px");
1683        for (int i = 0; i < SORT_OPTIONS[0].length; i++) {
1684            m_resultSorter.addItem(SORT_OPTIONS[0][i]);
1685            m_resultSorter.setItemCaption(SORT_OPTIONS[0][i], CmsVaadinUtils.getMessageText(SORT_OPTIONS[1][i]));
1686        }
1687        m_resultSorter.addValueChangeListener(new ValueChangeListener() {
1688
1689            /** Serial version id. */
1690            private static final long serialVersionUID = 1L;
1691
1692            @Override
1693            public void valueChange(ValueChangeEvent event) {
1694
1695                sortResult();
1696            }
1697        });
1698        m_infoLayout.addComponent(m_resultSorter);
1699
1700        m_textSearch = new TextField();
1701        m_textSearch.setIcon(FontOpenCms.SEARCH);
1702        m_textSearch.setInputPrompt(CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_SEARCH_0));
1703        m_textSearch.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
1704        m_textSearch.setWidth("200px");
1705        m_textSearch.addValueChangeListener(new ValueChangeListener() {
1706
1707            /** Serial version id. */
1708            private static final long serialVersionUID = 1L;
1709
1710            @Override
1711            public void valueChange(ValueChangeEvent event) {
1712
1713                search((String)event.getProperty().getValue());
1714            }
1715        });
1716        m_infoLayout.addComponent(m_textSearch);
1717        m_resultLayout.setSecondComponent(m_resultTable);
1718        m_resultLayout.setSplitPosition(CmsFileExplorer.LAYOUT_SPLIT_POSITION, Unit.PIXELS);
1719    }
1720
1721    /**
1722     * @see org.opencms.ui.apps.I_CmsCachableApp#isCachable()
1723     */
1724    public boolean isCachable() {
1725
1726        return true;
1727    }
1728
1729    /**
1730     * @see org.opencms.ui.apps.I_CmsCachableApp#onRestoreFromCache()
1731     */
1732    public void onRestoreFromCache() {
1733
1734        if (isOverView()) {
1735            CmsFileExplorerSettings state = m_overviewTable.getTableSettings();
1736            displayListConfigs();
1737            m_overviewTable.setTableState(state);
1738            m_overviewTable.updateSorting();
1739        } else {
1740            refreshResult();
1741        }
1742    }
1743
1744    /**
1745     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#onStateChange(java.lang.String)
1746     */
1747    @Override
1748    public void onStateChange(String state) {
1749
1750        if ((m_currentState == null) || !m_currentState.equals(state)) {
1751            m_currentState = state;
1752            super.onStateChange(state);
1753        }
1754    }
1755
1756    /**
1757     * @see org.opencms.ui.components.I_CmsWindowCloseListener#onWindowClose()
1758     */
1759    @Override
1760    public void onWindowClose() {
1761
1762        unlockCurrent();
1763    }
1764
1765    /**
1766     * Saves the blacklist from the bean in the current list configuration.<p>
1767     *
1768     * @param configBean the bean whose blacklist should be saved
1769     */
1770    public void saveBlacklist(ListConfigurationBean configBean) {
1771
1772        if (m_dialogWindow != null) {
1773            m_dialogWindow.close();
1774            m_dialogWindow = null;
1775        }
1776        CmsObject cms = A_CmsUI.getCmsObject();
1777
1778        try {
1779            m_lockAction = CmsLockUtil.ensureLock(cms, m_currentResource);
1780        } catch (CmsException e) {
1781            CmsErrorDialog.showErrorDialog(e);
1782            return;
1783        }
1784
1785        try {
1786            CmsFile configFile = cms.readFile(m_currentResource);
1787            CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, configFile);
1788            // list configurations are single locale contents
1789            Locale locale = CmsLocaleManager.MASTER_LOCALE;
1790            int count = 0;
1791            while (content.hasValue(N_BLACKLIST, locale)) {
1792                content.removeValue(N_BLACKLIST, locale, 0);
1793            }
1794            for (CmsUUID hiddenId : configBean.getBlacklist()) {
1795                CmsXmlVfsFileValue contentVal;
1796                contentVal = (CmsXmlVfsFileValue)content.addValue(cms, N_BLACKLIST, locale, count);
1797                contentVal.setIdValue(cms, hiddenId);
1798                count++;
1799            }
1800            configFile.setContents(content.marshal());
1801            cms.writeFile(configFile);
1802            if (m_lockAction.getChange().equals(LockChange.locked)) {
1803                CmsLockUtil.tryUnlock(cms, configFile);
1804            }
1805        } catch (CmsException e) {
1806            e.printStackTrace();
1807        }
1808        m_currentConfig = configBean;
1809    }
1810
1811    /**
1812     * Execute a search with the given search configuration parser.<p>
1813     *
1814     * @param configParser the search configuration parser
1815     * @param resource the current configuration resource
1816     */
1817    public void search(CmsSimpleSearchConfigurationParser configParser, CmsResource resource) {
1818
1819        m_currentResource = resource;
1820        m_currentConfigParser = configParser;
1821        resetContentLocale(configParser.getSearchLocale());
1822        m_resetting = true;
1823        m_resultSorter.setValue(m_currentConfig.getParameterValue(N_SORT_ORDER));
1824        m_resetting = false;
1825
1826        search(null, null, null);
1827    }
1828
1829    /**
1830     * Updates the search result.<p>
1831     *
1832     * @param fieldFacets the field facets
1833     * @param rangeFacets the range facets
1834     */
1835    public void search(Map<String, List<String>> fieldFacets, Map<String, List<String>> rangeFacets) {
1836
1837        search(fieldFacets, rangeFacets, null);
1838    }
1839
1840    /**
1841     * Updates the search result.<p>
1842     *
1843     * @param fieldFacets the field facets
1844     * @param rangeFacets the range facets
1845     * @param additionalQuery the additional query
1846     */
1847    public void search(
1848        Map<String, List<String>> fieldFacets,
1849        Map<String, List<String>> rangeFacets,
1850        String additionalQuery) {
1851
1852        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly((String)m_resultSorter.getValue())) {
1853            m_currentConfigParser.setSortOption((String)m_resultSorter.getValue());
1854        }
1855
1856        CmsSolrQuery query = m_currentConfigParser.getInitialQuery();
1857        CmsSearchController controller = new CmsSearchController(
1858            new CmsSearchConfiguration(m_currentConfigParser, A_CmsUI.getCmsObject()));
1859        controller.getPagination().getState().setCurrentPage(1);
1860        if (fieldFacets != null) {
1861            Map<String, I_CmsSearchControllerFacetField> fieldFacetControllers = controller.getFieldFacets().getFieldFacetController();
1862            for (Map.Entry<String, List<String>> facetEntry : fieldFacets.entrySet()) {
1863                I_CmsSearchStateFacet state = fieldFacetControllers.get(facetEntry.getKey()).getState();
1864                state.clearChecked();
1865                for (String check : facetEntry.getValue()) {
1866                    state.addChecked(check);
1867                }
1868            }
1869        }
1870        if (rangeFacets != null) {
1871            Map<String, I_CmsSearchControllerFacetRange> rangeFacetControllers = controller.getRangeFacets().getRangeFacetController();
1872            for (Map.Entry<String, List<String>> facetEntry : rangeFacets.entrySet()) {
1873                I_CmsSearchStateFacet state = rangeFacetControllers.get(facetEntry.getKey()).getState();
1874                state.clearChecked();
1875                for (String check : facetEntry.getValue()) {
1876                    state.addChecked(check);
1877                }
1878            }
1879        }
1880        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(additionalQuery)) {
1881            controller.getCommon().getState().setQuery(additionalQuery);
1882        } else {
1883            resetTextSearch();
1884        }
1885
1886        controller.addQueryParts(query, A_CmsUI.getCmsObject());
1887        executeSearch(controller, query);
1888    }
1889
1890    /**
1891     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String)
1892     */
1893    @Override
1894    protected LinkedHashMap<String, String> getBreadCrumbForState(String state) {
1895
1896        LinkedHashMap<String, String> crumbs = new LinkedHashMap<String, String>();
1897        if (CmsStringUtil.isEmptyOrWhitespaceOnly(state)) {
1898            crumbs.put("", CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_TITLE_0));
1899        } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(
1900            A_CmsWorkplaceApp.getParamFromState(state, CmsEditor.RESOURCE_ID_PREFIX))) {
1901                crumbs.put(
1902                    CmsListManagerConfiguration.APP_ID,
1903                    CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_TITLE_0));
1904                String title = "";
1905                try {
1906                    title = A_CmsUI.getCmsObject().readPropertyObject(
1907                        m_currentResource,
1908                        CmsPropertyDefinition.PROPERTY_TITLE,
1909                        false).getValue();
1910                } catch (Exception e) {
1911                    // ignore
1912                }
1913                if ((m_currentResource != null) && CmsStringUtil.isEmptyOrWhitespaceOnly(title)) {
1914                    title = m_currentResource.getName();
1915                }
1916                crumbs.put("", CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_VIEW_1, title));
1917            }
1918        return crumbs;
1919    }
1920
1921    /**
1922     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String)
1923     */
1924    @Override
1925    protected Component getComponentForState(String state) {
1926
1927        CmsObject cms = A_CmsUI.getCmsObject();
1928        boolean showOverview = true;
1929        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(
1930            A_CmsWorkplaceApp.getParamFromState(state, CmsEditor.RESOURCE_ID_PREFIX))) {
1931            try {
1932                CmsUUID id = new CmsUUID(A_CmsWorkplaceApp.getParamFromState(state, CmsEditor.RESOURCE_ID_PREFIX));
1933                CmsResource res = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1934                m_currentConfig = parseListConfiguration(A_CmsUI.getCmsObject(), res);
1935                String localeString = A_CmsWorkplaceApp.getParamFromState(state, PARAM_LOCALE);
1936                Locale locale;
1937                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(localeString)) {
1938                    locale = CmsLocaleManager.getLocale(localeString);
1939                } else {
1940                    locale = getContentLocale(m_currentConfig);
1941                }
1942                //SearchConfigParser configParser = new SearchConfigParser(m_currentConfig, m_collapseItemSeries, locale);
1943                CmsSimpleSearchConfigurationParser configParser = new CmsSimpleSearchConfigurationParser(
1944                    cms,
1945                    m_currentConfig,
1946                    null);
1947                setBackendSpecificOptions(configParser, locale);
1948                search(configParser, res);
1949                showOverview = false;
1950
1951            } catch (Exception e) {
1952                CmsErrorDialog.showErrorDialog(e);
1953                LOG.error(e.getLocalizedMessage(), e);
1954            }
1955        }
1956        if (showOverview) {
1957            unlockCurrent();
1958            m_lockAction = null;
1959            displayListConfigs();
1960        }
1961        enableOverviewMode(showOverview);
1962
1963        return showOverview ? m_overviewTable : m_resultLayout;
1964    }
1965
1966    /**
1967     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String)
1968     */
1969    @Override
1970    protected List<NavEntry> getSubNavEntries(String state) {
1971
1972        return null;
1973    }
1974
1975    /**
1976     * Changes the search content locale, reissuing a search.<p>
1977     *
1978     * @param contentLocale the content locale to set
1979     */
1980    void changeContentLocale(Locale contentLocale) {
1981
1982        if (!m_resetting) {
1983            m_currentConfigParser.setSearchLocale(contentLocale);
1984        }
1985        m_resultTable.setContentLocale(contentLocale);
1986        search(null, null, null);
1987    }
1988
1989    /**
1990     * Closes the edit dialog window.<p>
1991     */
1992    void closeEditDialog() {
1993
1994        if (m_dialogWindow != null) {
1995            m_dialogWindow.close();
1996            m_dialogWindow = null;
1997        }
1998        if (m_isOverView) {
1999            unlockCurrent();
2000            m_currentResource = null;
2001        }
2002    }
2003
2004    /**
2005     * Opens the create new dialog.<p>
2006     */
2007    void createNew() {
2008
2009        if (m_isOverView) {
2010            editListConfiguration(null);
2011        }
2012    }
2013
2014    /**
2015     * Displays the search result in the result table.<p>
2016     *
2017     * @param resultList the search result
2018     */
2019    void displayResult(CmsSolrResultList resultList) {
2020
2021        List<CmsResource> resources;
2022        evalSeries(resultList);
2023        if (m_hideSeriesInstances) {
2024            Set<CmsUUID> instanceIds = new HashSet<CmsUUID>();
2025            resources = new ArrayList<CmsResource>();
2026            for (CmsSearchResource res : resultList) {
2027                if (!instanceIds.contains(res.getStructureId())) {
2028                    instanceIds.add(res.getStructureId());
2029                    resources.add(res);
2030                }
2031            }
2032        } else {
2033            resources = new ArrayList<CmsResource>(resultList);
2034        }
2035        m_resultTable.fillTable(A_CmsUI.getCmsObject(), resources, true, false);
2036        String state = A_CmsWorkplaceApp.addParamToState(
2037            "",
2038            CmsEditor.RESOURCE_ID_PREFIX,
2039            m_currentResource.getStructureId().toString());
2040        state = A_CmsWorkplaceApp.addParamToState(
2041            state,
2042            PARAM_LOCALE,
2043            m_currentConfigParser.getSearchLocale().toString());
2044        m_currentState = state;
2045        CmsAppWorkplaceUi.get().changeCurrentAppState(state);
2046        if (m_isOverView) {
2047            enableOverviewMode(false);
2048            updateBreadCrumb(getBreadCrumbForState(state));
2049        }
2050    }
2051
2052    /**
2053     * Edits the given list configuration resource.<p>
2054     *
2055     * @param resource the configuration resource
2056     */
2057    void editListConfiguration(CmsResource resource) {
2058
2059        try {
2060            CmsObject cms = A_CmsUI.getCmsObject();
2061            String editState;
2062            if (resource == null) {
2063                editState = CmsEditor.getEditStateForNew(
2064                    cms,
2065                    OpenCms.getResourceManager().getResourceType(RES_TYPE_LIST_CONFIG),
2066                    "/",
2067                    null,
2068                    false,
2069                    UI.getCurrent().getPage().getLocation().toString());
2070            } else {
2071                editState = CmsEditor.getEditState(
2072                    resource.getStructureId(),
2073                    false,
2074                    UI.getCurrent().getPage().getLocation().toString());
2075            }
2076            View view = CmsAppWorkplaceUi.get().getCurrentView();
2077            if (view instanceof CmsAppView) {
2078                ((CmsAppView)view).setCacheStatus(CacheStatus.cacheOnce);
2079            }
2080            CmsAppWorkplaceUi.get().showApp(
2081                OpenCms.getWorkplaceAppManager().getAppConfiguration(CmsEditorConfiguration.APP_ID),
2082                editState);
2083
2084        } catch (CmsLoaderException e) {
2085            CmsErrorDialog.showErrorDialog(e);
2086        }
2087    }
2088
2089    /**
2090     * Enables the overview mode.<p>
2091     *
2092     * @param enabled <code>true</code> to enable the mode
2093     */
2094    void enableOverviewMode(boolean enabled) {
2095
2096        boolean isOffline = !A_CmsUI.getCmsObject().getRequestContext().getCurrentProject().isOnlineProject();
2097        m_publishButton.setVisible(!enabled);
2098        m_publishButton.setEnabled(isOffline);
2099        m_infoButton.setVisible(!enabled);
2100        m_tableFilter.setVisible(enabled);
2101        m_textSearch.setVisible(!enabled);
2102        m_editCurrentButton.setVisible(!enabled);
2103        m_editCurrentButton.setEnabled(isOffline);
2104
2105        m_toggleSeriesButton.setVisible(m_hasSeriesType && !enabled);
2106        m_resultSorter.setVisible(!enabled);
2107        m_localeSelect.setVisible(!enabled);
2108        m_isOverView = enabled;
2109        m_rootLayout.setMainContent(enabled ? m_overviewTable : m_resultLayout);
2110        m_createNewButton.setVisible(enabled);
2111        if (enabled) {
2112            if (!isOffline) {
2113                m_createNewButton.setEnabled(false);
2114                m_createNewButton.setDescription(
2115                    CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_NOT_CREATABLE_ONLINE_0));
2116            } else {
2117                CmsObject cms = A_CmsUI.getCmsObject();
2118                CmsADEConfigData data = OpenCms.getADEManager().lookupConfiguration(
2119                    cms,
2120                    cms.getRequestContext().getSiteRoot());
2121                CmsResourceTypeConfig typeConfig = data.getResourceType(RES_TYPE_LIST_CONFIG);
2122                try {
2123                    if ((typeConfig == null)
2124                        || !typeConfig.checkCreatable(cms, cms.getRequestContext().getSiteRoot())) {
2125                        m_createNewButton.setEnabled(false);
2126                        m_createNewButton.setDescription(
2127                            CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_NOT_CREATABLE_TYPE_0));
2128                    } else {
2129                        m_createNewButton.setEnabled(true);
2130                        m_createNewButton.setDescription(
2131                            CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_CREATE_NEW_0));
2132                    }
2133                } catch (CmsException e) {
2134                    m_createNewButton.setEnabled(false);
2135                    m_createNewButton.setDescription(
2136                        CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_NOT_CREATABLE_TYPE_0));
2137                }
2138            }
2139        }
2140    }
2141
2142    /**
2143     * Evaluates if date series types are present and if more than one instance of a series is in the search result.<p>
2144     *
2145     * @param resultList the search result list
2146     */
2147    void evalSeries(CmsSolrResultList resultList) {
2148
2149        m_hasSeriesType = false;
2150        m_hasSeriesInstances = false;
2151        Set<CmsUUID> instanceIds = new HashSet<CmsUUID>();
2152        for (CmsSearchResource res : resultList) {
2153            String seriesType = res.getField(CmsSearchField.FIELD_SERIESDATES_TYPE);
2154            m_hasSeriesType = m_hasSeriesType || CmsStringUtil.isNotEmptyOrWhitespaceOnly(seriesType);
2155            if (m_hasSeriesType && I_CmsSerialDateValue.DateType.SERIES.name().equals(seriesType)) {
2156                if (instanceIds.contains(res.getStructureId())) {
2157                    m_hasSeriesInstances = true;
2158                    break;
2159                } else {
2160                    instanceIds.add(res.getStructureId());
2161                }
2162            }
2163        }
2164        if (!m_hasSeriesInstances) {
2165            setsDateSeriesHiddenFlag(false);
2166        }
2167        m_toggleSeriesButton.setEnabled(m_hasSeriesInstances);
2168        m_toggleSeriesButton.setVisible(m_hasSeriesType);
2169
2170    }
2171
2172    /**
2173     * Filters the result table.<p>
2174     *
2175     * @param filter the filter string
2176     */
2177    void filterTable(String filter) {
2178
2179        if (!m_resetting) {
2180            m_overviewTable.filterTable(filter);
2181        }
2182    }
2183
2184    /**
2185     * Creates an element bean of the selected table item to be used with edit handlers.<p>
2186     *
2187     * @param context the dialog context
2188     *
2189     * @return the element bean
2190     */
2191    CmsContainerElementBean getElementForEditHandler(DialogContext context) {
2192
2193        List<Item> selected = context.getSelectedItems();
2194        if (selected.size() == 1) {
2195            Item item = selected.get(0);
2196            Date instanceDate = (Date)item.getItemProperty(INSTANCEDATE_PROPERTY).getValue();
2197            CmsResource resource = context.getResources().get(0);
2198            return new CmsContainerElementBean(
2199                resource.getStructureId(),
2200                null,
2201                Collections.singletonMap(
2202                    CmsDateSeriesEditHandler.PARAM_INSTANCEDATE,
2203                    String.valueOf(instanceDate.getTime())),
2204                false);
2205        }
2206        return null;
2207    }
2208
2209    /**
2210     * Returns the resources to publish for the current list.<p>
2211     *
2212     * @return the publish resources
2213     */
2214    List<CmsResource> getPublishResources() {
2215
2216        List<CmsResource> result = new ArrayList<CmsResource>();
2217        if (m_currentResource != null) {
2218            result.add(m_currentResource);
2219            CmsObject cms = A_CmsUI.getCmsObject();
2220            CmsSolrQuery query = m_currentConfigParser.getInitialQuery();
2221            CmsSearchController controller = new CmsSearchController(
2222                new CmsSearchConfiguration(m_currentConfigParser, A_CmsUI.getCmsObject()));
2223            controller.getPagination().getState().setCurrentPage(1);
2224            controller.addQueryParts(query, A_CmsUI.getCmsObject());
2225            I_CmsSearchConfigurationCommon commonConfig = controller.getCommon().getConfig();
2226            CmsSolrIndex index = OpenCms.getSearchManager().getIndexSolr(commonConfig.getSolrIndex());
2227            try {
2228                CmsSolrResultList solrResultList = index.search(
2229                    cms,
2230                    query,
2231                    true,
2232                    null,
2233                    false,
2234                    CmsResourceFilter.IGNORE_EXPIRATION,
2235                    commonConfig.getMaxReturnedResults());
2236                result.addAll(solrResultList);
2237            } catch (CmsSearchException e) {
2238                LOG.error("Error reading resources for publish.", e);
2239            }
2240        }
2241        return result;
2242    }
2243
2244    /**
2245     * Returns whether the overview mode is active.<p>
2246     *
2247     * @return <code>true</code> in case the overview mode is active
2248     */
2249    boolean isOverView() {
2250
2251        return m_isOverView;
2252    }
2253
2254    /**
2255     * Opens the publish dialog to publish all resources related to the current search configuration.<p>
2256     */
2257    void publish() {
2258
2259        I_CmsUpdateListener<String> updateListener = new I_CmsUpdateListener<String>() {
2260
2261            @Override
2262            public void onUpdate(List<String> updatedItems) {
2263
2264                updateItems(updatedItems);
2265            }
2266        };
2267        CmsAppWorkplaceUi.get().disableGlobalShortcuts();
2268        CmsGwtDialogExtension extension = new CmsGwtDialogExtension(A_CmsUI.get(), updateListener);
2269        extension.openPublishDialog(getPublishResources());
2270    }
2271
2272    /**
2273     * Refreshes the search result maintaining the current scroll position.<p>
2274     */
2275    void refreshResult() {
2276
2277        String itemId = m_resultTable.getCurrentPageFirstItemId();
2278        CmsFileExplorerSettings state = m_resultTable.getTableSettings();
2279        search(
2280            m_resultFacets.getSelectedFieldFacets(),
2281            m_resultFacets.getSelectedRangeFactes(),
2282            m_textSearch.getValue());
2283        m_resultTable.setTableState(state);
2284        m_resultTable.updateSorting();
2285        m_resultTable.setCurrentPageFirstItemId(itemId);
2286    }
2287
2288    /**
2289     * Searches within the current list.<p>
2290     *
2291     * @param query the query string
2292     */
2293    void search(String query) {
2294
2295        if (!m_resetting) {
2296            search(null, null, query);
2297        }
2298    }
2299
2300    /**
2301     * Sets the date series hidden flag.<p>
2302     *
2303     * @param hide the date series hidden flag
2304     */
2305    void setsDateSeriesHiddenFlag(boolean hide) {
2306
2307        m_hideSeriesInstances = hide;
2308        if (m_hideSeriesInstances) {
2309            m_toggleSeriesButton.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
2310        } else {
2311            m_toggleSeriesButton.removeStyleName(OpenCmsTheme.BUTTON_PRESSED);
2312        }
2313    }
2314
2315    /**
2316     * Sorts the search result.<p>
2317     */
2318    void sortResult() {
2319
2320        if (!m_resetting) {
2321            search(
2322                m_resultFacets.getSelectedFieldFacets(),
2323                m_resultFacets.getSelectedRangeFactes(),
2324                m_textSearch.getValue());
2325        }
2326    }
2327
2328    /**
2329     * Toggles the date series filter.<p>
2330     */
2331    void toggleDateSeries() {
2332
2333        setsDateSeriesHiddenFlag(!m_hideSeriesInstances);
2334        refreshResult();
2335    }
2336
2337    /**
2338     * Tries to unlocks the current resource if available.<p>
2339     */
2340    void tryUnlockCurrent() {
2341
2342        if ((m_lockAction != null) && m_lockAction.getChange().equals(CmsLockActionRecord.LockChange.locked)) {
2343            try {
2344                A_CmsUI.getCmsObject().unlockResource(m_currentResource);
2345            } catch (CmsException e) {
2346                e.printStackTrace();
2347            }
2348        }
2349    }
2350
2351    /**
2352     * Unlocks the current resource in case it has been locked by previous actions.<p>
2353     */
2354    void unlockCurrent() {
2355
2356        if (m_currentResource != null) {
2357            if ((m_lockAction != null) && m_lockAction.getChange().equals(LockChange.locked)) {
2358                CmsLockUtil.tryUnlock(A_CmsUI.getCmsObject(), m_currentResource);
2359            }
2360        }
2361        m_lockAction = null;
2362    }
2363
2364    /**
2365     * Updates the given items in the result table.<p>
2366     *
2367     * @param updatedItems the items to update
2368     */
2369    void updateItems(List<String> updatedItems) {
2370
2371        Set<CmsUUID> ids = new HashSet<CmsUUID>();
2372        for (String id : updatedItems) {
2373            ids.add(new CmsUUID(id));
2374        }
2375        m_resultTable.update(ids, false);
2376    }
2377
2378    /**
2379     * Displays the list config resources.<p>
2380     */
2381    private void displayListConfigs() {
2382
2383        CmsObject cms = A_CmsUI.getCmsObject();
2384        resetTableFilter();
2385        try {
2386            // display the search configuration overview
2387            List<CmsResource> resources = cms.readResources(
2388                "/",
2389                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(
2390                    OpenCms.getResourceManager().getResourceType(RES_TYPE_LIST_CONFIG)));
2391            m_overviewTable.fillTable(cms, resources);
2392        } catch (Exception e) {
2393            CmsErrorDialog.showErrorDialog(e);
2394            LOG.error(e.getLocalizedMessage(), e);
2395        }
2396    }
2397
2398    /**
2399     * Executes a search.<p>
2400     *
2401     * @param controller the search controller
2402     * @param query the SOLR query
2403     */
2404    private void executeSearch(CmsSearchController controller, CmsSolrQuery query) {
2405
2406        CmsObject cms = A_CmsUI.getCmsObject();
2407        I_CmsSearchConfigurationCommon commonConfig = controller.getCommon().getConfig();
2408        CmsSolrIndex index = OpenCms.getSearchManager().getIndexSolr(commonConfig.getSolrIndex());
2409        try {
2410            CmsSolrResultList solrResultList = index.search(
2411                cms,
2412                query,
2413                true,
2414                null,
2415                false,
2416                CmsResourceFilter.IGNORE_EXPIRATION,
2417                commonConfig.getMaxReturnedResults());
2418            displayResult(solrResultList);
2419            m_resultFacets.displayFacetResult(
2420                solrResultList,
2421                new CmsSearchResultWrapper(controller, solrResultList, query, cms, null));
2422        } catch (CmsSearchException e) {
2423            CmsErrorDialog.showErrorDialog(e);
2424
2425            LOG.error("Error executing search.", e);
2426        }
2427    }
2428
2429    /**
2430     * Returns the content locale configured for the first search root folder of the search configuration.<p>
2431     *
2432     * @param bean the search configuration data
2433     *
2434     * @return the locale
2435     */
2436    private Locale getContentLocale(ListConfigurationBean bean) {
2437
2438        CmsObject cms = A_CmsUI.getCmsObject();
2439        if (bean.getFolders().isEmpty()) {
2440            return OpenCms.getLocaleManager().getDefaultLocale(cms, "/");
2441        } else {
2442            return OpenCms.getLocaleManager().getDefaultLocale(
2443                cms,
2444                cms.getRequestContext().removeSiteRoot(m_currentConfig.getFolders().get(0)));
2445        }
2446    }
2447
2448    /**
2449     * Resets the locale select according to the current configuration data.<p>
2450     *
2451     * @param defaultLocale the default content locale
2452     */
2453    private void resetContentLocale(Locale defaultLocale) {
2454
2455        m_resetting = true;
2456        m_localeSelect.removeAllItems();
2457        if (m_currentConfig.getFolders().isEmpty()) {
2458            m_localeSelect.addItem(defaultLocale);
2459            m_localeSelect.setItemCaption(defaultLocale, defaultLocale.getDisplayLanguage(UI.getCurrent().getLocale()));
2460        } else {
2461            for (String folder : m_currentConfig.getFolders()) {
2462                for (Locale locale : OpenCms.getLocaleManager().getAvailableLocales(A_CmsUI.getCmsObject(), folder)) {
2463                    if (!m_localeSelect.containsId(locale)) {
2464                        m_localeSelect.addItem(locale);
2465                        m_localeSelect.setItemCaption(locale, locale.getDisplayLanguage(UI.getCurrent().getLocale()));
2466                    }
2467                }
2468            }
2469        }
2470        m_localeSelect.setValue(defaultLocale);
2471        m_localeSelect.setEnabled(m_localeSelect.getItemIds().size() > 1);
2472        m_resetting = false;
2473    }
2474
2475    /**
2476     * Resets the table filter.<p>
2477     */
2478    private void resetTableFilter() {
2479
2480        m_resetting = true;
2481        m_tableFilter.clear();
2482        m_resetting = false;
2483    }
2484
2485    /**
2486     * Resets the text search input.<p>
2487     */
2488    private void resetTextSearch() {
2489
2490        m_resetting = true;
2491        m_textSearch.clear();
2492        m_resetting = false;
2493    }
2494
2495    /**
2496     * Sets options which are specific to the backend list manager on the cnofiguration parser.<p>
2497     *
2498     * @param configParser the configuration parser
2499     * @param locale the search locale
2500     */
2501    private void setBackendSpecificOptions(CmsSimpleSearchConfigurationParser configParser, Locale locale) {
2502
2503        configParser.setSearchLocale(locale);
2504        configParser.setIgnoreBlacklist(true);
2505        configParser.setPagination(PAGINATION);
2506    }
2507}