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.datesearch;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.file.CmsResourceFilter;
033import org.opencms.file.types.I_CmsResourceType;
034import org.opencms.jsp.search.config.parser.simplesearch.daterestrictions.CmsDateRangeRestriction;
035import org.opencms.loader.CmsLoaderException;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.search.CmsSearchException;
040import org.opencms.search.CmsSearchResource;
041import org.opencms.search.fields.CmsSearchField;
042import org.opencms.search.solr.CmsSolrIndex;
043import org.opencms.search.solr.CmsSolrQuery;
044import org.opencms.search.solr.CmsSolrResultList;
045import org.opencms.ui.A_CmsUI;
046import org.opencms.ui.CmsVaadinUtils;
047import org.opencms.ui.I_CmsDialogContext;
048import org.opencms.ui.I_CmsDialogContext.ContextType;
049import org.opencms.ui.apps.CmsAppWorkplaceUi;
050import org.opencms.ui.apps.I_CmsContextProvider;
051import org.opencms.ui.apps.Messages;
052import org.opencms.ui.apps.lists.CmsListManager;
053import org.opencms.ui.apps.lists.CmsResultTable;
054import org.opencms.ui.components.CmsAvailabilitySelector;
055import org.opencms.ui.components.CmsComponentState;
056import org.opencms.ui.components.CmsDateField;
057import org.opencms.ui.components.CmsErrorDialog;
058import org.opencms.ui.components.CmsFileTable;
059import org.opencms.ui.components.CmsFileTableDialogContext;
060import org.opencms.ui.components.CmsFolderSelector;
061import org.opencms.ui.components.CmsResourceTable.I_ResourcePropertyProvider;
062import org.opencms.ui.components.CmsResourceTableProperty;
063import org.opencms.ui.components.CmsResultFacets;
064import org.opencms.ui.components.CmsResultFilterComponent;
065import org.opencms.ui.components.CmsSiteSelector;
066import org.opencms.ui.components.CmsTypeSelector;
067import org.opencms.ui.components.I_CmsResultFacetsManager;
068import org.opencms.ui.components.OpenCmsTheme;
069import org.opencms.ui.contextmenu.CmsResourceContextMenuBuilder;
070import org.opencms.util.CmsStringUtil;
071import org.opencms.util.CmsUUID;
072import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
073import org.opencms.workplace.explorer.CmsResourceUtil;
074
075import java.time.LocalDateTime;
076import java.util.ArrayList;
077import java.util.Collection;
078import java.util.Date;
079import java.util.HashMap;
080import java.util.LinkedHashMap;
081import java.util.List;
082import java.util.Locale;
083import java.util.Map;
084import java.util.Set;
085
086import org.apache.commons.logging.Log;
087import org.apache.solr.client.solrj.SolrQuery.ORDER;
088import org.apache.solr.client.solrj.response.FacetField.Count;
089import org.apache.solr.client.solrj.util.ClientUtils;
090
091import com.vaadin.shared.ui.datefield.DateTimeResolution;
092import com.vaadin.ui.Component;
093import com.vaadin.ui.FormLayout;
094import com.vaadin.ui.TextField;
095import com.vaadin.v7.data.Item;
096import com.vaadin.v7.data.Property.ValueChangeEvent;
097import com.vaadin.v7.data.Property.ValueChangeListener;
098import com.vaadin.v7.data.util.filter.Or;
099import com.vaadin.v7.data.util.filter.SimpleStringFilter;
100import com.vaadin.v7.event.FieldEvents.TextChangeEvent;
101import com.vaadin.v7.event.FieldEvents.TextChangeListener;
102import com.vaadin.v7.ui.Table;
103import com.vaadin.v7.ui.Table.CellStyleGenerator;
104import com.vaadin.v7.ui.VerticalLayout;
105
106/**
107 * Component that realizes a content finder.
108 */
109@SuppressWarnings("deprecation")
110public class CmsDateSearchComposite implements I_ResourcePropertyProvider, I_CmsResultFacetsManager {
111
112    /**
113     * The filter component of the content finder.
114     */
115    @SuppressWarnings("serial")
116    private class FilterComponent extends VerticalLayout {
117
118        /** The site selector. */
119        CmsSiteSelector m_siteSelector;
120
121        /** The folder selector. */
122        CmsFolderSelector m_folderSelector;
123
124        /** The type selector. */
125        CmsTypeSelector m_typeSelector;
126
127        /** The date from selector. */
128        CmsDateField m_dateFrom;
129
130        /** The date to selector. */
131        CmsDateField m_dateTo;
132
133        /** The availability selector. */
134        CmsAvailabilitySelector m_availabilitySelector;
135
136        /** The result facets component. */
137        CmsResultFacets m_resultFacets;
138
139        /** The form layout. */
140        FormLayout m_formLayout;
141
142        /** The text search. */
143        TextField m_textSearchField;
144
145        /**
146         * Creates a new filter component.
147         */
148        FilterComponent() {
149
150            setMargin(true);
151            setSpacing(true);
152            m_formLayout = new FormLayout();
153            m_formLayout.setMargin(true);
154            m_formLayout.setSpacing(true);
155            m_formLayout.addStyleName("o-formlayout-narrow");
156            initSiteSelector();
157            initFolderSelector();
158            initTypeSelector();
159            initDateFrom();
160            initDateTo();
161            initTextSearchField();
162            initExpiredSelector();
163            initResultFacets();
164            m_formLayout.addComponent(new VerticalLayout()); // fix layout bug
165            addComponent(m_formLayout);
166        }
167
168        /**
169         * Returns the selected category.
170         * @return the selected category
171         */
172        String getSelectedCategory() {
173
174            List<String> categories = m_resultFacets.getSelectedFieldFacets().get(CmsSearchField.FIELD_CATEGORY_EXACT);
175            if ((categories != null) && !categories.isEmpty()) {
176                return categories.get(0);
177            }
178            return null;
179        }
180
181        /**
182         * Updates the type selector.
183         */
184        void updateTypeSelector() {
185
186            m_typeSelector.updateTypes(getAvailableTypes());
187        }
188
189        /**
190         * Initializes the date from selector.
191         */
192        private void initDateFrom() {
193
194            m_dateFrom = new CmsDateField();
195            m_dateFrom.setWidthFull();
196            String caption = CmsVaadinUtils.getMessageText(Messages.GUI_DATE_SEARCH_DATE_FROM_0);
197            m_dateFrom.setCaption(caption);
198            m_dateFrom.setResolution(DateTimeResolution.DAY);
199            m_dateFrom.addValueChangeListener(new com.vaadin.data.HasValue.ValueChangeListener<LocalDateTime>() {
200
201                public void valueChange(com.vaadin.data.HasValue.ValueChangeEvent<LocalDateTime> event) {
202
203                    search(true, true);
204                }
205            });
206            m_formLayout.addComponent(m_dateFrom);
207        }
208
209        /**
210         * Initializes the date to selector.
211         */
212        private void initDateTo() {
213
214            m_dateTo = new CmsDateField();
215            m_dateTo.setWidthFull();
216            String caption = CmsVaadinUtils.getMessageText(Messages.GUI_DATE_SEARCH_DATE_TO_0);
217            m_dateTo.setCaption(caption);
218            m_dateTo.setResolution(DateTimeResolution.DAY);
219            m_dateTo.addValueChangeListener(new com.vaadin.data.HasValue.ValueChangeListener<LocalDateTime>() {
220
221                public void valueChange(com.vaadin.data.HasValue.ValueChangeEvent<LocalDateTime> event) {
222
223                    search(true, true);
224                }
225            });
226            m_formLayout.addComponent(m_dateTo);
227        }
228
229        /**
230         * Initializes the expired resources selector.
231         */
232        private void initExpiredSelector() {
233
234            m_availabilitySelector = new CmsAvailabilitySelector();
235            m_availabilitySelector.addValueChangeListener(event -> {
236                search(true, true);
237            });
238            m_formLayout.addComponent(m_availabilitySelector);
239        }
240
241        /**
242         * Initializes the folder selector.
243         */
244        private void initFolderSelector() {
245
246            m_folderSelector = new CmsFolderSelector();
247            m_folderSelector.addValueChangeListener(new ValueChangeListener() {
248
249                public void valueChange(ValueChangeEvent event) {
250
251                    search(true, true);
252                }
253            });
254            m_formLayout.addComponent(m_folderSelector);
255        }
256
257        /**
258         * Initializes the result facets component.
259         */
260        private void initResultFacets() {
261
262            m_resultFacets = new CmsResultFacets(CmsDateSearchComposite.this);
263            m_resultFacets.setWidthFull();
264            m_resultFacets.setMargin(false);
265            m_resultFacets.setSpacing(true);
266            m_formLayout.addComponent(m_resultFacets);
267        }
268
269        /**
270         * Initializes the site selector.
271         */
272        private void initSiteSelector() {
273
274            m_siteSelector = new CmsSiteSelector();
275            m_siteSelector.setWidthFull();
276            m_siteSelector.addValueChangeListener(event -> {
277                search(true, true);
278            });
279            m_formLayout.addComponent(m_siteSelector);
280        }
281
282        /**
283         * Initializes the text search field.
284         */
285        private void initTextSearchField() {
286
287            m_textSearchField = new TextField();
288            m_textSearchField.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_LISTMANAGER_SEARCH_0));
289            m_textSearchField.setWidthFull();
290            m_textSearchField.addValueChangeListener(event -> {
291                search(true, true);
292            });
293            m_formLayout.addComponent(m_textSearchField);
294        }
295
296        /**
297         * Initializes the type selector.
298         */
299        private void initTypeSelector() {
300
301            m_typeSelector = new CmsTypeSelector();
302            m_typeSelector.addValueChangeListener(event -> {
303                search(true, true);
304            });
305            m_formLayout.addComponent(m_typeSelector);
306        }
307    }
308
309    /**
310     * The result component of the content finder.
311     */
312    @SuppressWarnings("serial")
313    private class ResultComponent extends VerticalLayout {
314
315        /** Layout showing empty type message. */
316        VerticalLayout m_infoEmptyType;
317
318        /** Layout showing empty result message. */
319        VerticalLayout m_infoEmptyResult;
320
321        /** The file table. */
322        CmsResultTable m_resultTable;
323
324        /**
325         * Creates a new result component.
326         */
327        ResultComponent() {
328
329            setSizeFull();
330            initInfoEmptyType();
331            initInfoEmptyResult();
332            initResultTable();
333        }
334
335        /**
336         * Shows the empty result info layout.
337         */
338        void showInfoEmptyResult() {
339
340            m_resultTable.setVisible(false);
341            m_infoEmptyType.setVisible(false);
342            m_infoEmptyResult.setVisible(true);
343        }
344
345        /**
346         * Shows the empty type info layout.
347         */
348        void showInfoEmptyType() {
349
350            m_infoEmptyResult.setVisible(false);
351            m_resultTable.setVisible(false);
352            m_infoEmptyType.setVisible(true);
353        }
354
355        /**
356         * Updates the result table for given resources.
357         * @param resources the resources
358         */
359        void updateResultTable(List<CmsResource> resources) {
360
361            m_infoEmptyType.setVisible(false);
362            m_infoEmptyResult.setVisible(false);
363            m_resultTable.fillTable(getCmsObject(), resources, true, false, true);
364            m_resultTable.setVisible(true);
365        }
366
367        /**
368         * Initializes the empty result info layout.
369         */
370        private void initInfoEmptyResult() {
371
372            m_infoEmptyResult = CmsVaadinUtils.getInfoLayout(Messages.GUI_DATE_SEARCH_EMPTY_RESULT_0);
373            m_infoEmptyResult.setVisible(false);
374            addComponent(m_infoEmptyResult);
375        }
376
377        /**
378         * Initializes the empty type info layout.
379         */
380        private void initInfoEmptyType() {
381
382            m_infoEmptyType = CmsVaadinUtils.getInfoLayout(Messages.GUI_DATE_SEARCH_EMPTY_TYPE_0);
383            m_infoEmptyType.setVisible(false);
384            addComponent(m_infoEmptyType);
385        }
386
387        /**
388         * Initializes the result table.
389         */
390        private void initResultTable() {
391
392            LinkedHashMap<CmsResourceTableProperty, Integer> tableColumns = new LinkedHashMap<CmsResourceTableProperty, Integer>();
393            for (Map.Entry<CmsResourceTableProperty, Integer> columnsEntry : CmsFileTable.DEFAULT_TABLE_PROPERTIES.entrySet()) {
394                if (columnsEntry.getKey().equals(CmsResourceTableProperty.PROPERTY_RESOURCE_TYPE)) {
395                    tableColumns.put(CmsListManager.INSTANCEDATE_PROPERTY, Integer.valueOf(0));
396                }
397                tableColumns.put(columnsEntry.getKey(), columnsEntry.getValue());
398            }
399            m_resultTable = new CmsResultTable(null, tableColumns) {
400
401                /**
402                 * Path, title, and type columns shall be visible and not collapsed.
403                 * @see org.opencms.ui.components.CmsFileTable#applyWorkplaceAppSettings()
404                 */
405                @Override
406                public void applyWorkplaceAppSettings() {
407
408                    super.applyWorkplaceAppSettings();
409                    m_fileTable.setColumnCollapsed(CmsResourceTableProperty.PROPERTY_SIZE, true);
410                    m_fileTable.setColumnCollapsed(CmsResourceTableProperty.PROPERTY_DATE_MODIFIED, true);
411                    m_fileTable.setColumnCollapsed(CmsListManager.INSTANCEDATE_PROPERTY, false);
412                }
413
414                /**
415                 * Filter by path, title.
416                 * @see org.opencms.ui.components.CmsFileTable#filterTable(java.lang.String)
417                 */
418                @Override
419                public void filterTable(String search) {
420
421                    m_container.removeAllContainerFilters();
422                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(search)) {
423                        m_container.addContainerFilter(
424                            new Or(
425                                new SimpleStringFilter(
426                                    CmsResourceTableProperty.PROPERTY_SITE_PATH,
427                                    search,
428                                    true,
429                                    false),
430                                new SimpleStringFilter(CmsResourceTableProperty.PROPERTY_TITLE, search, true, false)));
431                    }
432                    if ((m_fileTable.getValue() != null) & !((Set<?>)m_fileTable.getValue()).isEmpty()) {
433                        m_fileTable.setCurrentPageFirstItemId(((Set<?>)m_fileTable.getValue()).iterator().next());
434                    }
435                }
436            };
437            m_resultTable.applyWorkplaceAppSettings();
438            m_resultTable.addPropertyProvider(CmsDateSearchComposite.this);
439            m_resultTable.setContextProvider(new I_CmsContextProvider() {
440
441                /**
442                 * @see org.opencms.ui.apps.I_CmsContextProvider#getDialogContext()
443                 */
444                public I_CmsDialogContext getDialogContext() {
445
446                    CmsFileTableDialogContext context = new CmsFileTableDialogContext(
447                        CmsDateSearchConfiguration.APP_ID,
448                        ContextType.fileTable,
449                        m_resultTable,
450                        m_resultTable.getSelectedResources()) {
451
452                        /**
453                         * @see org.opencms.ui.components.CmsFileTableDialogContext#finish(java.util.Collection)
454                         */
455                        @Override
456                        public void finish(Collection<CmsUUID> ids) {
457
458                            if (m_resultTable.getSelectedItems() == null) {
459                                super.finish(ids);
460                            } else {
461                                String itemId = m_resultTable.getCurrentPageFirstItemId();
462                                search(false, false);
463                                m_resultTable.setCurrentPageFirstItemId(itemId);
464                                closeWindow();
465                            }
466                        }
467                    };
468                    return context;
469                }
470            });
471            m_resultTable.addAdditionalStyleGenerator(new CellStyleGenerator() {
472
473                public String getStyle(Table source, Object itemId, Object propertyId) {
474
475                    String style = "";
476                    Item item = source.getItem(itemId);
477                    if (CmsResourceTableProperty.PROPERTY_TITLE.equals(propertyId)
478                        && ((item.getItemProperty(CmsResourceTableProperty.PROPERTY_RELEASED_NOT_EXPIRED) == null)
479                            || ((Boolean)item.getItemProperty(
480                                CmsResourceTableProperty.PROPERTY_RELEASED_NOT_EXPIRED).getValue()).booleanValue())) {
481                        style += OpenCmsTheme.IN_NAVIGATION + " ";
482                    }
483                    return style;
484                }
485
486            });
487            m_resultTable.setSizeFull();
488            m_resultTable.setMenuBuilder(new CmsResourceContextMenuBuilder());
489            m_resultTable.setVisible(false);
490            addComponent(m_resultTable);
491        }
492    }
493
494    /**
495     * The search component of the content finder.
496     */
497    @SuppressWarnings("serial")
498    private class ResultFilterComponent extends CmsResultFilterComponent {
499
500        /**
501         * Creates a new search component.
502         */
503        ResultFilterComponent() {
504
505            super();
506            addTextChangeListener(new TextChangeListener() {
507
508                public void textChange(TextChangeEvent event) {
509
510                    m_resultComponent.m_resultTable.filterTable(event.getText());
511
512                }
513            });
514        }
515    }
516
517    /** The log object for this class. */
518    static final Log LOG = CmsLog.getLog(CmsDateSearchComposite.class);
519
520    /** The maximum number of results. */
521    static final int MAX_RESULTS = 5000;
522
523    /** The filter component for this content finder. */
524    FilterComponent m_filterComponent;
525
526    /** The result component for this content finder. */
527    ResultComponent m_resultComponent;
528
529    /** The search component for this content finder. */
530    CmsResultFilterComponent m_resultFilterComponent;
531
532    /**
533     * Creates a new content finder component.
534     */
535    public CmsDateSearchComposite() {
536
537        m_filterComponent = new FilterComponent();
538        m_filterComponent.updateTypeSelector();
539        m_resultComponent = new ResultComponent();
540        m_resultFilterComponent = new ResultFilterComponent();
541        connectComponents();
542        m_resultComponent.showInfoEmptyType();
543    }
544
545    /**
546     * @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)
547     */
548    @SuppressWarnings("javadoc")
549    public void addItemProperties(Item resourceItem, CmsObject cms, CmsResource resource, Locale locale) {
550
551        if (resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TITLE) != null) {
552            CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource);
553            String title = resUtil.getGalleryTitle(locale);
554            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(title)) {
555                resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TITLE).setValue(title);
556            }
557        }
558        if ((resource instanceof CmsSearchResource)
559            && (resourceItem.getItemProperty(CmsListManager.INSTANCEDATE_PROPERTY) != null)) {
560            List<String> contentLocales = ((CmsSearchResource)resource).getDocument().getMultivaluedFieldAsStringList(
561                CmsSearchField.FIELD_CONTENT_LOCALES);
562            if (contentLocales != null) {
563                for (String contentLocale : contentLocales) {
564                    String dateFieldKey = CmsSearchField.FIELD_INSTANCEDATE + "_" + contentLocale + "_dt";
565                    Date date = ((CmsSearchResource)resource).getDateField(dateFieldKey);
566                    if (date != null) {
567                        resourceItem.getItemProperty(CmsListManager.INSTANCEDATE_PROPERTY).setValue(date);
568                    }
569                }
570            }
571        }
572    }
573
574    /**
575     * Returns the filter component of this content finder.
576     * @return the filter component of this content finder
577     */
578    public Component getFilterComponent() {
579
580        return m_filterComponent;
581    }
582
583    /**
584     * Returns the result component of this content finder.
585     * @return the result component of this content finder
586     */
587    public Component getResultComponent() {
588
589        return m_resultComponent;
590    }
591
592    /**
593     * Returns the result filter component of this content finder.
594     * @return the result filter component of this content finder
595     */
596    public Component getResultFilterComponent() {
597
598        return m_resultFilterComponent;
599    }
600
601    /**
602     * Executes the search.
603     * @param updateState whether to update the app state
604     * @param resetSelectedFacets whether to reset the selected facets
605     */
606    public void search(boolean updateState, boolean resetSelectedFacets) {
607
608        if (resetSelectedFacets) {
609            m_filterComponent.m_resultFacets.resetFacets();
610            m_filterComponent.m_resultFacets.setVisible(false);
611        }
612        if (updateState) {
613            CmsComponentState componentState = new CmsComponentState();
614            componentState.setSite((String)m_filterComponent.m_siteSelector.getValue());
615            componentState.setFolder(m_filterComponent.m_folderSelector.getValue());
616            componentState.setResourceType((I_CmsResourceType)m_filterComponent.m_typeSelector.getValue());
617            componentState.setDateFrom(m_filterComponent.m_dateFrom.getDate());
618            componentState.setDateTo(m_filterComponent.m_dateTo.getDate());
619            componentState.setAvailability(m_filterComponent.m_availabilitySelector.getValue().getFirst());
620            componentState.setQuery(m_filterComponent.m_textSearchField.getValue());
621            componentState.setCategory(m_filterComponent.getSelectedCategory());
622            CmsAppWorkplaceUi.get().changeCurrentAppState(componentState.generateStateString());
623        }
624        if (m_filterComponent.m_typeSelector.getValue() == null) {
625            m_resultComponent.showInfoEmptyType();
626        } else {
627            CmsSolrResultList solrResultList = search(null);
628            List<CmsResource> results = new ArrayList<CmsResource>(solrResultList);
629            if (results.isEmpty()) {
630                m_resultComponent.showInfoEmptyResult();
631            } else {
632                m_resultComponent.updateResultTable(results);
633                Map<String, Boolean> checkedCategoryFacets = new HashMap<String, Boolean>();
634                if (!m_filterComponent.m_resultFacets.getSelectedFieldFacets().isEmpty()) {
635                    checkedCategoryFacets.put(
636                        m_filterComponent.m_resultFacets.getSelectedFieldFacets().get(
637                            CmsSearchField.FIELD_CATEGORY_EXACT).get(0),
638                        Boolean.TRUE);
639                }
640                m_filterComponent.m_resultFacets.displayFacetResult(
641                    solrResultList,
642                    checkedCategoryFacets,
643                    null,
644                    null,
645                    getCmsObject());
646                m_filterComponent.m_resultFacets.setVisible(true);
647            }
648        }
649    }
650
651    /**
652     * @see org.opencms.ui.components.I_CmsResultFacetsManager#search(java.util.Map, java.util.Map)
653     */
654    public void search(Map<String, List<String>> fieldFacets, Map<String, List<String>> rangeFacets) {
655
656        search(true, false);
657    }
658
659    /**
660     * Sets a component state.
661     * @param componentState the component state
662     */
663    public void setState(CmsComponentState componentState) {
664
665        m_filterComponent.m_siteSelector.setValue(componentState.getSite());
666        m_filterComponent.m_folderSelector.setValue(componentState.getFolder());
667        m_filterComponent.m_typeSelector.setValue(componentState.getResourceType());
668        m_filterComponent.m_dateFrom.setDate(componentState.getDateFrom());
669        m_filterComponent.m_dateTo.setDate(componentState.getDateTo());
670        m_filterComponent.m_availabilitySelector.setValue(
671            m_filterComponent.m_availabilitySelector.getOption(componentState.getAvailability()));
672        if (componentState.getCategory() != null) {
673            m_filterComponent.m_resultFacets.selectFieldFacet(
674                CmsSearchField.FIELD_CATEGORY_EXACT,
675                componentState.getCategory());
676        }
677        m_filterComponent.m_textSearchField.setValue(componentState.getQuery());
678    }
679
680    /**
681     * Returns the list of XML content types relevant for the content finder.
682     * @return the list of XML content types relevant for the content finder
683     */
684    List<I_CmsResourceType> getAvailableTypes() {
685
686        CmsSolrResultList solrResultList = search(Integer.valueOf(0));
687        List<I_CmsResourceType> result = new ArrayList<>();
688        for (Count count : solrResultList.getFacetField(CmsSearchField.FIELD_TYPE).getValues()) {
689            String typeName = count.getName();
690            CmsExplorerTypeSettings typeSetting = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName);
691            if (typeSetting == null) {
692                continue;
693            }
694            try {
695                I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(typeName);
696                result.add(resourceType);
697            } catch (CmsLoaderException e) {
698                LOG.error(e.getLocalizedMessage(), e);
699            }
700        }
701        return result;
702    }
703
704    /**
705     * Returns the current CMS context of this content finder.
706     * @return the current CMS context of this content finder
707     */
708    CmsObject getCmsObject() {
709
710        if ((m_filterComponent == null) || (m_filterComponent.m_folderSelector == null)) {
711            return A_CmsUI.getCmsObject();
712        }
713        CmsObject folderSelectorCms = m_filterComponent.m_folderSelector.getCmsObject();
714        return folderSelectorCms == null ? A_CmsUI.getCmsObject() : folderSelectorCms;
715    }
716
717    /**
718     * Builds the Solr query.
719     * @return the Solr query
720     */
721    private CmsSolrQuery buildQuery() {
722
723        CmsSolrQuery query = new CmsSolrQuery(getCmsObject(), null);
724        query.setSort(CmsSearchField.FIELD_PATH, ORDER.asc);
725        query.addFacetField(CmsSearchField.FIELD_TYPE);
726        query.addFacetField(CmsSearchField.FIELD_CONTENT_LOCALES);
727        query.addFacetField("{!ex=ce}" + CmsSearchField.FIELD_CATEGORY_EXACT);
728        query.setFacetMinCount(1);
729        List<String> filterQueries = new ArrayList<String>();
730        filterQueries.add(CmsSearchField.FIELD_CONTENT_LOCALES + ":*");
731        String site = (String)m_filterComponent.m_siteSelector.getValue();
732        String folder = m_filterComponent.m_folderSelector.getValue();
733        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(folder)) {
734            String path = CmsStringUtil.joinPaths(site, folder);
735            filterQueries.add(CmsSearchField.FIELD_PARENT_FOLDERS + ":\"" + path + "\"");
736        } else {
737            if (site != null) {
738                site = site.endsWith("/") ? site : site + "/";
739            }
740            filterQueries.add(CmsSearchField.FIELD_PARENT_FOLDERS + ":\"" + site + "\"");
741        }
742        I_CmsResourceType type = (I_CmsResourceType)m_filterComponent.m_typeSelector.getValue();
743        if (type != null) {
744            filterQueries.add(CmsSearchField.FIELD_TYPE + ":" + type.getTypeName());
745        }
746        Date dateFrom = m_filterComponent.m_dateFrom.getDate();
747        Date dateTo = m_filterComponent.m_dateTo.getDate();
748        String dateRangeQuery = null;
749        if ((dateFrom != null) || (dateTo != null)) {
750            List<String> dateRangeQueries = new ArrayList<String>();
751            List<Locale> availableLocales = OpenCms.getLocaleManager().getAvailableLocales(getCmsObject(), folder);
752            for (Locale locale : availableLocales) {
753                CmsDateRangeRestriction restriction = new CmsDateRangeRestriction(dateFrom, dateTo);
754                dateRangeQueries.add(
755                    CmsSearchField.FIELD_INSTANCEDATE_CURRENT_TILL
756                        + "_"
757                        + locale
758                        + CmsSearchField.FIELD_POSTFIX_DATE
759                        + ":"
760                        + restriction.getRange());
761            }
762            dateRangeQuery = "(" + String.join(" OR ", dateRangeQueries) + ")";
763            filterQueries.add(dateRangeQuery);
764        }
765        if (!filterQueries.isEmpty()) {
766            if (m_filterComponent.m_availabilitySelector.isOptionWithout()) {
767                query.setFilterQueries(String.join(" AND ", filterQueries));
768            } else if (m_filterComponent.m_availabilitySelector.isOptionOnly()) {
769                Date now = new Date();
770                CmsDateRangeRestriction releasedRestriction = new CmsDateRangeRestriction(now, null);
771                CmsDateRangeRestriction expiredRestriction = new CmsDateRangeRestriction(null, now);
772                String releasedQuery = "released:" + releasedRestriction.getRange();
773                String expiredQuery = "expired:" + expiredRestriction.getRange();
774                String releasedOrExpiredQuery = releasedQuery + " OR " + expiredQuery;
775                String expiredOrReleasedQuery = expiredQuery + " OR " + releasedQuery; // fix to avoid rewrite of query
776                query.setFilterQueries(
777                    String.join(" AND ", filterQueries),
778                    releasedOrExpiredQuery,
779                    expiredOrReleasedQuery);
780            } else {
781                String releasedQuery = "released:[* TO *]";
782                String expiredQuery = "expired:[* TO *]";
783                query.setFilterQueries(String.join(" AND ", filterQueries), releasedQuery, expiredQuery);
784            }
785        }
786        List<String> checkedCategories = m_filterComponent.m_resultFacets.getSelectedFieldFacets().get(
787            "category_exact");
788        if ((checkedCategories != null) && !checkedCategories.isEmpty()) {
789            query.addFilterQuery(
790                "{!tag=ce}" + CmsSearchField.FIELD_CATEGORY_EXACT + ":\"" + checkedCategories.get(0) + "\"");
791        }
792        String textSearch = m_resultFilterComponent == null ? null : m_filterComponent.m_textSearchField.getValue();
793        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(textSearch)) {
794            query.setQuery(ClientUtils.escapeQueryChars(textSearch));
795        }
796        return query;
797    }
798
799    /**
800     * Connects all filter, search, and result components.
801     */
802    @SuppressWarnings("serial")
803    private void connectComponents() {
804
805        // update the folder selector and locale selector when the site selector changes
806        m_filterComponent.m_siteSelector.addValueChangeListener(new ValueChangeListener() {
807
808            public void valueChange(ValueChangeEvent arg0) {
809
810                try {
811                    CmsObject newCms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
812                    newCms.getRequestContext().setSiteRoot((String)m_filterComponent.m_siteSelector.getValue());
813                    m_filterComponent.m_folderSelector.setCmsObject(newCms);
814                    m_filterComponent.m_folderSelector.setValue("/");
815                    m_filterComponent.updateTypeSelector();
816                    m_filterComponent.m_dateFrom.setValue(null);
817                    m_filterComponent.m_dateTo.setValue(null);
818                    m_filterComponent.m_availabilitySelector.reset();
819                } catch (CmsException e) {
820                    LOG.error(e.getLocalizedMessage(), e);
821                }
822            }
823        });
824        // update the locale selector when the folder selector changes
825        m_filterComponent.m_folderSelector.addValueChangeListener(new ValueChangeListener() {
826
827            public void valueChange(ValueChangeEvent event) {
828
829                m_filterComponent.updateTypeSelector();
830                m_filterComponent.m_dateFrom.setValue(null);
831                m_filterComponent.m_dateTo.setValue(null);
832                m_filterComponent.m_availabilitySelector.reset();
833            }
834        });
835    }
836
837    /**
838     * Executes the search and returns the results.
839     * @param rows the number of rows to return
840     * @return the results
841     */
842    private CmsSolrResultList search(Integer rows) {
843
844        CmsSolrQuery query = buildQuery();
845        boolean online = getCmsObject().getRequestContext().getCurrentProject().isOnlineProject();
846        String indexName = online ? CmsSolrIndex.DEFAULT_INDEX_NAME_ONLINE : CmsSolrIndex.DEFAULT_INDEX_NAME_OFFLINE;
847        CmsSolrIndex index = OpenCms.getSearchManager().getIndexSolr(indexName);
848        query.setRows(rows == null ? Integer.valueOf(MAX_RESULTS) : rows);
849        try {
850            return index.search(getCmsObject(), query, true, null, true, CmsResourceFilter.ALL, MAX_RESULTS);
851        } catch (CmsSearchException e) {
852            CmsErrorDialog.showErrorDialog(e);
853            LOG.error(e.getLocalizedMessage(), e);
854            return null;
855        }
856    }
857}