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.searchindex;
029
030import org.opencms.search.I_CmsSearchIndex;
031import org.opencms.ui.A_CmsUI;
032import org.opencms.ui.CmsCssIcon;
033import org.opencms.ui.CmsVaadinUtils;
034import org.opencms.ui.apps.Messages;
035import org.opencms.ui.components.CmsBasicDialog;
036import org.opencms.ui.components.CmsBasicDialog.DialogWidth;
037import org.opencms.ui.components.OpenCmsTheme;
038import org.opencms.ui.contextmenu.CmsContextMenu;
039import org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode;
040import org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry;
041
042import java.util.ArrayList;
043import java.util.HashSet;
044import java.util.List;
045import java.util.Locale;
046import java.util.Set;
047
048import com.vaadin.event.MouseEvents;
049import com.vaadin.server.Resource;
050import com.vaadin.shared.MouseEventDetails.MouseButton;
051import com.vaadin.ui.Button;
052import com.vaadin.ui.Button.ClickEvent;
053import com.vaadin.ui.Button.ClickListener;
054import com.vaadin.ui.UI;
055import com.vaadin.ui.Window;
056import com.vaadin.ui.themes.ValoTheme;
057import com.vaadin.v7.data.Item;
058import com.vaadin.v7.data.util.IndexedContainer;
059import com.vaadin.v7.event.ItemClickEvent;
060import com.vaadin.v7.event.ItemClickEvent.ItemClickListener;
061import com.vaadin.v7.ui.Table;
062
063/**
064 * Class for the vaadin table to show the indexes.<p>
065 */
066public class CmsSearchIndexTable extends Table {
067
068    /**
069     * The edit project context menu entry.<p>
070     */
071    class EntryRebuild implements I_CmsSimpleContextMenuEntry<Set<String>> {
072
073        /**
074         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
075         */
076        public void executeAction(Set<String> data) {
077
078            final Window window = CmsBasicDialog.prepareWindow(DialogWidth.max);
079            CmsBasicDialog dialog = new CmsBasicDialog();
080
081            dialog.setContent(new CmsSearchindexRebuild(m_manager, data));
082            Button closeButton = new Button(CmsVaadinUtils.messageClose());
083            closeButton.addClickListener(new ClickListener() {
084
085                private static final long serialVersionUID = -1043776488459785433L;
086
087                public void buttonClick(ClickEvent event) {
088
089                    window.close();
090
091                }
092
093            });
094            dialog.addButton(closeButton, true);
095            window.setContent(dialog);
096
097            window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_SEARCHINDEX_ADMIN_TOOL_NAME_SHORT_0));
098            A_CmsUI.get().addWindow(window);
099            window.center();
100        }
101
102        /**
103         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
104         */
105        public String getTitle(Locale locale) {
106
107            return CmsVaadinUtils.getMessageText(Messages.GUI_SEARCHINDEX_REBUILD_0);
108        }
109
110        /**
111         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
112         */
113        public CmsMenuItemVisibilityMode getVisibility(Set<String> data) {
114
115            return CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE;
116        }
117    }
118
119    /**
120     * Menu entry for show variations option.<p>
121     */
122    class EntrySources implements I_CmsSimpleContextMenuEntry<Set<String>>, I_CmsSimpleContextMenuEntry.I_HasCssStyles {
123
124        /**
125         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
126         */
127        public void executeAction(Set<String> data) {
128
129            String resource = data.iterator().next();
130            showSourcesWindow(resource);
131        }
132
133        /**
134         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry.I_HasCssStyles#getStyles()
135         */
136        public String getStyles() {
137
138            return ValoTheme.LABEL_BOLD;
139        }
140
141        /**
142         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
143         */
144        public String getTitle(Locale locale) {
145
146            return CmsVaadinUtils.getMessageText(Messages.GUI_SEARCHINDEX_INDEXSOURCE_SHOW_0);
147        }
148
149        /**
150         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
151         */
152        public CmsMenuItemVisibilityMode getVisibility(Set<String> data) {
153
154            return (data != null) && (data.size() == 1)
155            ? CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE
156            : CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE;
157        }
158    }
159
160    /**
161     * All table properties.<p>
162     */
163    enum TableProperty {
164
165        /**Field configuration column. */
166        FieldConfig(Messages.GUI_SEARCHINDEX_COL_CONFIGURATION_0, String.class, "", false),
167
168        /**Icon column.*/
169        Icon(null, Resource.class, new CmsCssIcon(OpenCmsTheme.ICON_DATABASE), false),
170
171        /**Locale column. */
172        Locale(Messages.GUI_SEARCHINDEX_COL_LOCALE_0, String.class, "", false),
173
174        /**name column. */
175        Name(Messages.GUI_SEARCHINDEX_COL_NAME_0, String.class, "", false),
176
177        /**Project column.*/
178        Project(Messages.GUI_SEARCHINDEX_COL_PROJECT_0, String.class, "", false),
179
180        /**Rebuild column.*/
181        Rebuild(Messages.GUI_SEARCHINDEX_COL_REBUILDMODE_0, String.class, "", false);
182
183        /**Indicates if column is collapsable.*/
184        private boolean m_collapsable;
185
186        /**Default value for column.*/
187        private Object m_defaultValue;
188
189        /**Header Message key.*/
190        private String m_headerMessage;
191
192        /**Type of column property.*/
193        private Class<?> m_type;
194
195        /**
196         * constructor.
197         *
198         * @param headerMessage key
199         * @param type to property
200         * @param defaultValue of column
201         * @param collapsable should this column be collapsable?
202         */
203        TableProperty(String headerMessage, Class<?> type, Object defaultValue, boolean collapsable) {
204
205            m_headerMessage = headerMessage;
206            m_type = type;
207            m_defaultValue = defaultValue;
208            m_collapsable = collapsable;
209        }
210
211        /**
212         * Returns list of all properties with non-empty header.<p>
213         *
214         * @return list of properties
215         */
216        static List<TableProperty> withHeader() {
217
218            List<TableProperty> props = new ArrayList<TableProperty>();
219
220            for (TableProperty prop : TableProperty.values()) {
221                if (prop.m_headerMessage != null) {
222                    props.add(prop);
223                }
224            }
225            return props;
226        }
227
228        /**
229         * Returns the default value of property.<p>
230         *
231         * @return object
232         */
233        Object getDefaultValue() {
234
235            return m_defaultValue;
236        }
237
238        /**
239         * Returns localized header.<p>
240         *
241         * @return string for header
242         */
243        String getLocalizedMessage() {
244
245            if (m_headerMessage == null) {
246                return "";
247            }
248            return CmsVaadinUtils.getMessageText(m_headerMessage);
249        }
250
251        /**
252         * Returns tye of value for given property.<p>
253         *
254         * @return type
255         */
256        Class<?> getType() {
257
258            return m_type;
259        }
260
261        /**
262         * Indicates if column is collapsable.<p>
263         *
264         * @return boolean, true = is collapsable
265         */
266        boolean isCollapsable() {
267
268            return m_collapsable;
269        }
270
271    }
272
273    /**vaadin serial id.*/
274    private static final long serialVersionUID = 5764331446498958798L;
275
276    /**the calling instance.*/
277    protected CmsSearchindexApp m_manager;
278
279    /**Indexed container. */
280    private IndexedContainer m_container;
281
282    /** The context menu. */
283    private CmsContextMenu m_menu;
284
285    /** The available menu entries. */
286    private List<I_CmsSimpleContextMenuEntry<Set<String>>> m_menuEntries;
287
288    /**
289     * Constructor.<p>
290     *
291     * @param manager instance of the calling app
292     */
293    public CmsSearchIndexTable(CmsSearchindexApp manager) {
294
295        m_manager = manager;
296        m_container = new IndexedContainer();
297
298        setContainerDataSource(m_container);
299
300        for (TableProperty prop : TableProperty.values()) {
301            m_container.addContainerProperty(prop, prop.getType(), prop.getDefaultValue());
302            setColumnHeader(prop, prop.getLocalizedMessage());
303        }
304
305        m_menu = new CmsContextMenu();
306        m_menu.setAsTableContextMenu(this);
307        setVisibleColumns(
308            TableProperty.Name,
309            TableProperty.FieldConfig,
310            TableProperty.Rebuild,
311            TableProperty.Project,
312            TableProperty.Locale);
313        setItemIconPropertyId(TableProperty.Icon);
314        setRowHeaderMode(RowHeaderMode.ICON_ONLY);
315        setColumnWidth(null, 40);
316
317        addItemClickListener(new ItemClickListener() {
318
319            /**vaadin serial id.*/
320            private static final long serialVersionUID = -3595150969741628374L;
321
322            public void itemClick(ItemClickEvent event) {
323
324                onItemClick(event, event.getItemId(), event.getPropertyId());
325            }
326
327        });
328
329        setSelectable(true);
330        setMultiSelect(true);
331
332        setCellStyleGenerator(new CellStyleGenerator() {
333
334            private static final long serialVersionUID = 1L;
335
336            public String getStyle(Table source, Object itemId, Object propertyId) {
337
338                if (TableProperty.Name.equals(propertyId)) {
339                    return " " + OpenCmsTheme.HOVER_COLUMN;
340                }
341                return null;
342            }
343        });
344
345    }
346
347    /**
348     * (Re)loads the table.<p>
349     */
350    public void loadTable() {
351
352        m_container.removeAllItems();
353        List<I_CmsSearchIndex> indexes = m_manager.getAllElements();
354
355        for (I_CmsSearchIndex index : indexes) {
356            if (index.isEnabled()) {
357                Item item = m_container.addItem(index);
358                item.getItemProperty(TableProperty.Name).setValue(index.getName());
359                item.getItemProperty(TableProperty.FieldConfig).setValue(index.getFieldConfiguration().getName());
360                item.getItemProperty(TableProperty.Locale).setValue(index.getLocale().getDisplayName());
361                item.getItemProperty(TableProperty.Project).setValue(index.getProject());
362                item.getItemProperty(TableProperty.Rebuild).setValue(index.getRebuildMode());
363            }
364        }
365    }
366
367    /**
368     * Returns the available menu entries.<p>
369     *
370     * @return the menu entries
371     */
372    List<I_CmsSimpleContextMenuEntry<Set<String>>> getMenuEntries() {
373
374        if (m_menuEntries == null) {
375            m_menuEntries = new ArrayList<I_CmsSimpleContextMenuEntry<Set<String>>>();
376            m_menuEntries.add(new EntrySources()); //Option for show Sources of index
377            m_menuEntries.add(new EntryRebuild());
378        }
379        return m_menuEntries;
380    }
381
382    /**
383    * Handles the table item clicks, including clicks on images inside of a table item.<p>
384    *
385    * @param event the click event
386    * @param itemId of the clicked row
387    * @param propertyId column id
388    */
389    void onItemClick(MouseEvents.ClickEvent event, Object itemId, Object propertyId) {
390
391        if (!event.isCtrlKey() && !event.isShiftKey()) {
392
393            changeValueIfNotMultiSelect(itemId);
394
395            // don't interfere with multi-selection using control key
396            if (event.getButton().equals(MouseButton.RIGHT) || (propertyId == null)) {
397                m_menu.setEntries(getMenuEntries(), getSearchIndexNames());
398                m_menu.openForTable(event, itemId, propertyId, this);
399            } else if (event.getButton().equals(MouseButton.LEFT) && TableProperty.Name.equals(propertyId)) {
400                showSourcesWindow(((I_CmsSearchIndex)((Set<?>)getValue()).iterator().next()).getName());
401            }
402        }
403    }
404
405    /**
406     * Shows dialog for variations of given resource.<p>
407     *
408     * @param resource to show variations for
409     */
410    void showSourcesWindow(String resource) {
411
412        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
413        CmsSourceDialog sourceDialog = new CmsSourceDialog(m_manager, new Runnable() {
414
415            public void run() {
416
417                window.close();
418            }
419        });
420        sourceDialog.setSource(resource);
421        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_SEARCHINDEX_INDEXSOURCE_SHOW_1, resource));
422        window.setContent(sourceDialog);
423        UI.getCurrent().addWindow(window);
424    }
425
426    /**
427     * Checks value of table and sets it new if needed:<p>
428     * if multiselect: new itemId is in current Value? -> no change of value<p>
429     * no multiselect and multiselect, but new item not selected before: set value to new item<p>
430     *
431     * @param itemId if of clicked item
432     */
433    private void changeValueIfNotMultiSelect(Object itemId) {
434
435        @SuppressWarnings("unchecked")
436        Set<String> value = (Set<String>)getValue();
437        if (value == null) {
438            select(itemId);
439        } else if (!value.contains(itemId)) {
440            setValue(null);
441            select(itemId);
442        }
443    }
444
445    /**
446     * Returns a list with the names of all searchindexes.<p>
447     *
448     * @return List of search index names
449     */
450    private Set<String> getSearchIndexNames() {
451
452        Set<String> names = new HashSet<String>();
453        @SuppressWarnings("unchecked")
454        Set<I_CmsSearchIndex> indexes = (Set<I_CmsSearchIndex>)getValue();
455        for (I_CmsSearchIndex index : indexes) {
456            names.add(index.getName());
457        }
458        return names;
459    }
460}