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.user;
029
030import org.opencms.file.CmsGroup;
031import org.opencms.file.CmsObject;
032import org.opencms.main.CmsException;
033import org.opencms.main.CmsLog;
034import org.opencms.main.OpenCms;
035import org.opencms.security.CmsRole;
036import org.opencms.security.CmsRoleViolationException;
037import org.opencms.ui.A_CmsUI;
038import org.opencms.ui.CmsCssIcon;
039import org.opencms.ui.CmsVaadinUtils;
040import org.opencms.ui.apps.Messages;
041import org.opencms.ui.components.CmsBasicDialog;
042import org.opencms.ui.components.CmsBasicDialog.DialogWidth;
043import org.opencms.ui.components.OpenCmsTheme;
044import org.opencms.ui.contextmenu.CmsContextMenu;
045import org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode;
046import org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry;
047import org.opencms.util.CmsStringUtil;
048import org.opencms.util.CmsUUID;
049
050import java.util.ArrayList;
051import java.util.HashSet;
052import java.util.List;
053import java.util.Locale;
054import java.util.Set;
055
056import org.apache.commons.logging.Log;
057
058import com.vaadin.server.Resource;
059import com.vaadin.shared.MouseEventDetails.MouseButton;
060import com.vaadin.ui.Window;
061import com.vaadin.ui.themes.ValoTheme;
062import com.vaadin.v7.data.Item;
063import com.vaadin.v7.data.util.IndexedContainer;
064import com.vaadin.v7.data.util.filter.Or;
065import com.vaadin.v7.data.util.filter.SimpleStringFilter;
066import com.vaadin.v7.event.ItemClickEvent;
067import com.vaadin.v7.event.ItemClickEvent.ItemClickListener;
068import com.vaadin.v7.ui.Table;
069import com.vaadin.v7.ui.VerticalLayout;
070
071/**
072 * Class for the table containing groups of a ou.<p>
073 */
074public class CmsGroupTable extends Table implements I_CmsFilterableTable, I_CmsToggleTable {
075
076    /**Table properties.<p>*/
077    public enum TableProperty {
078        /**Desription column. */
079        Description(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUP_DESCRIPTION_0), String.class, ""),
080        /**Icon column.*/
081        Icon(null, Resource.class, new CmsCssIcon(OpenCmsTheme.ICON_GROUP)),
082        /**IsIndirect?. */
083        INDIRECT("", Boolean.class, Boolean.valueOf(false)),
084        /**Name column. */
085        Name(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUP_NAME_0), String.class, ""),
086        /**OU column. */
087        OU(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUP_OU_0), String.class, "");
088
089        /**Default value for column.*/
090        private Object m_defaultValue;
091
092        /**Header Message key.*/
093        private String m_headerMessage;
094
095        /**Type of column property.*/
096        private Class<?> m_type;
097
098        /**
099         * constructor.<p>
100         *
101         * @param name Name
102         * @param type type
103         * @param defaultValue value
104         */
105        TableProperty(String name, Class<?> type, Object defaultValue) {
106
107            m_headerMessage = name;
108            m_type = type;
109            m_defaultValue = defaultValue;
110        }
111
112        /**
113         * The default value.<p>
114         *
115         * @return the default value object
116         */
117        Object getDefault() {
118
119            return m_defaultValue;
120        }
121
122        /**
123         * Gets the name of the property.<p>
124         *
125         * @return a name
126         */
127        String getName() {
128
129            return m_headerMessage;
130
131        }
132
133        /**
134         * Gets the type of property.<p>
135         *
136         * @return the type
137         */
138        Class<?> getType() {
139
140            return m_type;
141        }
142
143    }
144
145    /**
146     * Delete context menu entry.<p>
147     */
148    class EntryDelete implements I_CmsSimpleContextMenuEntry<Set<String>> {
149
150        /**
151         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
152         */
153        public void executeAction(final Set<String> context) {
154
155            Window window = CmsBasicDialog.prepareWindow();
156            CmsDeleteMultiplePrincipalDialog dialog = new CmsDeleteMultiplePrincipalDialog(
157                m_cms,
158                context,
159                window,
160                m_app);
161            window.setContent(dialog);
162            window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUP_DELETE_0));
163            A_CmsUI.get().addWindow(window);
164        }
165
166        /**
167         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
168         */
169        public String getTitle(Locale locale) {
170
171            return CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUP_DELETE_0);
172        }
173
174        /**
175         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
176         */
177        public CmsMenuItemVisibilityMode getVisibility(Set<String> context) {
178
179            boolean ok = canDelete(context);
180            return ok ? CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE : CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE;
181        }
182
183    }
184
185    /**
186     * Edit context menu entry.<p>
187     */
188    class EntryEdit implements I_CmsSimpleContextMenuEntry<Set<String>> {
189
190        /**
191         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
192         */
193        public void executeAction(Set<String> context) {
194
195            Window window = CmsBasicDialog.prepareWindow();
196            window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_EDIT_GROUP_0));
197            window.setContent(new CmsGroupEditDialog(m_cms, new CmsUUID(context.iterator().next()), window, m_app));
198
199            A_CmsUI.get().addWindow(window);
200        }
201
202        /**
203         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
204         */
205        public String getTitle(Locale locale) {
206
207            return CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_EDIT_GROUP_0);
208        }
209
210        /**
211         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
212         */
213        public CmsMenuItemVisibilityMode getVisibility(Set<String> context) {
214
215            if (context.size() > 1) {
216                return CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE;
217            }
218            return CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE;
219        }
220
221    }
222
223    /**
224     * Open entry for context menu.<p>
225     */
226    class EntryOpen implements I_CmsSimpleContextMenuEntry<Set<String>>, I_CmsSimpleContextMenuEntry.I_HasCssStyles {
227
228        /**
229         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
230         */
231        public void executeAction(Set<String> context) {
232
233            updateApp(context.iterator().next());
234        }
235
236        /**
237         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry.I_HasCssStyles#getStyles()
238         */
239        public String getStyles() {
240
241            return ValoTheme.LABEL_BOLD;
242        }
243
244        /**
245         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
246         */
247        public String getTitle(Locale locale) {
248
249            return CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_OPEN_0);
250        }
251
252        /**
253         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
254         */
255        public CmsMenuItemVisibilityMode getVisibility(Set<String> context) {
256
257            if (context.size() > 1) {
258                return CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE;
259            }
260            if (m_app != null) {
261                return CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE;
262            } else {
263                return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE;
264            }
265        }
266
267    }
268
269    /**
270     * Show resources context menu entry.<p>
271     */
272    class EntryShowResources implements I_CmsSimpleContextMenuEntry<Set<String>> {
273
274        /**
275         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
276         */
277        public void executeAction(Set<String> context) {
278
279            Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
280            window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_SHOW_RESOURCES_0));
281            window.setContent(new CmsShowResourcesDialog(context.iterator().next(), window));
282
283            A_CmsUI.get().addWindow(window);
284        }
285
286        /**
287         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
288         */
289        public String getTitle(Locale locale) {
290
291            return CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_SHOW_RESOURCES_0);
292        }
293
294        /**
295         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
296         */
297        public CmsMenuItemVisibilityMode getVisibility(Set<String> context) {
298
299            if (context.size() > 1) {
300                return CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE;
301            }
302            return CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE;
303        }
304
305    }
306
307    /**
308     * Show resources context menu entry.<p>
309     */
310    class ImExport implements I_CmsSimpleContextMenuEntry<Set<String>> {
311
312        /**
313         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object)
314         */
315        public void executeAction(Set<String> context) {
316
317            boolean includeTechnicalFields = false;
318            try {
319                OpenCms.getRoleManager().checkRole(m_cms, CmsRole.ADMINISTRATOR);
320                includeTechnicalFields = true;
321            } catch (CmsRoleViolationException e) {
322                // ok
323            }
324            Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
325            window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_USER_IMEXPORT_DIALOGNAME_0));
326            window.setContent(
327                CmsImportExportUserDialog.getExportUserDialogForGroup(
328                    new CmsUUID(context.iterator().next()),
329                    m_ou,
330                    window,
331                    includeTechnicalFields));
332
333            A_CmsUI.get().addWindow(window);
334        }
335
336        /**
337         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale)
338         */
339        public String getTitle(Locale locale) {
340
341            return CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_USER_IMEXPORT_CONTEXTMENUNAME_0);
342        }
343
344        /**
345         * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object)
346         */
347        public CmsMenuItemVisibilityMode getVisibility(Set<String> context) {
348
349            return CmsMenuItemVisibilityMode.activeInactive(canImportData(context));
350
351        }
352
353    }
354
355    /** Log instance for this class. */
356    private static final Log LOG = CmsLog.getLog(CmsGroupTable.class);
357
358    /**vaadin serial id. */
359    private static final long serialVersionUID = -6511159488669996003L;
360
361    /**Calling app. */
362    protected CmsAccountsApp m_app;
363
364    /**The ou. */
365    protected String m_ou;
366
367    /**CmsObject. */
368    CmsObject m_cms;
369
370    /**List of groups. */
371    List<CmsGroup> m_groups;
372
373    /**List of indirect groups. */
374    List<CmsGroup> m_indirects;
375
376    /** The context menu. */
377    CmsContextMenu m_menu;
378
379    /**Indexed container. */
380    private IndexedContainer m_container;
381
382    /**Vaadin component. */
383    private VerticalLayout m_emptyLayout;
384
385    /**flag indicates if all indirect items (for sub OUs) are loaded. */
386    private boolean m_fullLoaded;
387
388    /** The available menu entries. */
389    private List<I_CmsSimpleContextMenuEntry<Set<String>>> m_menuEntries;
390
391    /** The tree type. */
392    private I_CmsOuTreeType m_type;
393
394    /**
395     * public constructor.<p>
396     *
397     * @param ou ou name
398     * @param app calling app.
399     * @param type the tree type
400     * @param showAll if all groups should be shown
401     */
402    public CmsGroupTable(String ou, CmsAccountsApp app, I_CmsOuTreeType type, boolean showAll) {
403
404        m_app = app;
405        m_ou = ou;
406        m_type = type;
407        m_indirects = new ArrayList<CmsGroup>();
408        List<CmsGroup> directs;
409        try {
410            m_cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
411            m_cms.getRequestContext().setSiteRoot("");
412        } catch (CmsException e) {
413            m_cms = A_CmsUI.getCmsObject();
414        }
415        try {
416            directs = m_app.readGroupsForOu(m_cms, ou, m_type, false);
417            m_fullLoaded = false;
418            if (showAll) {
419                setAllGroups(directs);
420            } else {
421                m_groups = directs;
422            }
423        } catch (CmsException e) {
424            // TODO Auto-generated catch block
425            e.printStackTrace();
426        }
427        init(ou);
428
429    }
430
431    /**
432     * Fills the container item representing a group.<p>
433     *
434     * @param item the item
435     * @param group the group
436     * @param indirects the indirect groups
437     */
438    public void fillGroupItem(Item item, CmsGroup group, List<CmsGroup> indirects) {
439
440        item.getItemProperty(TableProperty.Name).setValue(group.getName());
441        item.getItemProperty(TableProperty.Description).setValue(group.getDescription(A_CmsUI.get().getLocale()));
442        item.getItemProperty(TableProperty.OU).setValue(group.getOuFqn());
443        if (indirects.contains(group)) {
444            item.getItemProperty(TableProperty.INDIRECT).setValue(Boolean.TRUE);
445        }
446    }
447
448    /**
449     * Filters the table.<p>
450     *
451     * @see org.opencms.ui.apps.user.I_CmsFilterableTable#filter(java.lang.String)
452     */
453    public void filter(String data) {
454
455        m_container.removeAllContainerFilters();
456        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(data)) {
457            m_container.addContainerFilter(
458                new Or(
459                    new SimpleStringFilter(TableProperty.Name, data, true, false),
460                    new SimpleStringFilter(TableProperty.Description, data, true, false)));
461        }
462
463    }
464
465    /**
466     * @see org.opencms.ui.apps.user.I_CmsToggleTable#getCurrentSize()
467     */
468    public int getCurrentSize() {
469
470        return size();
471    }
472
473    /**
474     * @see org.opencms.ui.apps.user.I_CmsFilterableTable#getEmptyLayout()
475     */
476    public VerticalLayout getEmptyLayout() {
477
478        m_emptyLayout = CmsVaadinUtils.getInfoLayout(CmsOuTreeType.GROUP.getEmptyMessageKey());
479        setVisible(size() > 0);
480        m_emptyLayout.setVisible(size() == 0);
481        return m_emptyLayout;
482    }
483
484    /**
485     * @see org.opencms.ui.apps.user.I_CmsToggleTable#toggle(boolean)
486     */
487    public void toggle(boolean pressed) {
488
489        try {
490            if (pressed && !m_fullLoaded) {
491                setAllGroups(m_groups);
492            }
493        } catch (CmsException e) {
494            LOG.error("Error loading groups", e);
495        }
496        fillContainer(pressed);
497    }
498
499    /**
500     * Returns true if the given group can be deleted.<p>
501     *
502     * @param groupIds the set of groups
503     * @return true if the set of groups can be deleted
504     */
505    protected boolean canDelete(Set<String> groupIds) {
506
507        return true;
508    }
509
510    /**
511     * Return true if the CSV import should be enabled for a set of groups
512     *
513     * @param groupIds the set of group ids
514     *
515     * @return true if the CSV import should be enabled
516     */
517    protected boolean canImportData(Set<String> groupIds) {
518
519        return groupIds.size() == 1;
520    }
521
522    /**
523     * Fills the container.<p>
524     *
525     * @param showIndirect true-> show all user, false -> only direct user
526     */
527    protected void fillContainer(boolean showIndirect) {
528
529        m_container.removeAllContainerFilters();
530        m_container.removeAllItems();
531        for (CmsGroup group : m_groups) {
532            if (!m_indirects.contains(group)) {
533                Item item = m_container.addItem(group);
534                m_app.fillGroupItem(item, group, m_indirects);
535            }
536        }
537        if (showIndirect) {
538            for (CmsGroup group : m_indirects) {
539                Item item = m_container.addItem(group);
540                m_app.fillGroupItem(item, group, m_indirects);
541            }
542        }
543    }
544
545    /**
546     * Initializes the table.<p>
547     *
548     * @param ou name
549     */
550    protected void init(String ou) {
551
552        m_menu = new CmsContextMenu();
553        m_menu.setAsTableContextMenu(this);
554
555        m_container = new IndexedContainer();
556
557        for (TableProperty prop : TableProperty.values()) {
558            m_container.addContainerProperty(prop, prop.getType(), prop.getDefault());
559            setColumnHeader(prop, prop.getName());
560        }
561        m_app.addGroupContainerProperties(m_container);
562        setContainerDataSource(m_container);
563        setItemIconPropertyId(TableProperty.Icon);
564        setRowHeaderMode(RowHeaderMode.ICON_ONLY);
565
566        setColumnWidth(null, 40);
567        setSelectable(true);
568        setMultiSelect(true);
569
570        for (CmsGroup group : m_groups) {
571            Item item = m_container.addItem(group);
572            m_app.fillGroupItem(item, group, m_indirects);
573        }
574
575        addItemClickListener(new ItemClickListener() {
576
577            private static final long serialVersionUID = 4807195510202231174L;
578
579            @SuppressWarnings("unchecked")
580            public void itemClick(ItemClickEvent event) {
581
582                changeValueIfNotMultiSelect(event.getItemId());
583
584                if (event.getButton().equals(MouseButton.RIGHT) || (event.getPropertyId() == null)) {
585                    Set<String> groupIds = new HashSet<String>();
586                    for (CmsGroup group : (Set<CmsGroup>)getValue()) {
587                        groupIds.add(group.getId().getStringValue());
588                    }
589                    m_menu.setEntries(getMenuEntries(), groupIds);
590                    m_menu.openForTable(event, event.getItemId(), event.getPropertyId(), CmsGroupTable.this);
591                    return;
592                }
593                if (event.getButton().equals(MouseButton.LEFT) && event.getPropertyId().equals(TableProperty.Name)) {
594                    updateApp((((Set<CmsGroup>)getValue()).iterator().next()).getId().getStringValue());
595                }
596            }
597
598        });
599        setCellStyleGenerator(new CellStyleGenerator() {
600
601            private static final long serialVersionUID = 1L;
602
603            public String getStyle(Table source, Object itemId, Object propertyId) {
604
605                String css = "";
606                if (((Boolean)source.getItem(itemId).getItemProperty(
607                    TableProperty.INDIRECT).getValue()).booleanValue()) {
608                    css += " " + OpenCmsTheme.TABLE_CELL_DISABLED + " " + OpenCmsTheme.EXPIRED;
609                }
610                if (TableProperty.Name.equals(propertyId)) {
611                    css += " " + OpenCmsTheme.HOVER_COLUMN;
612                }
613
614                return css;
615            }
616        });
617        setVisibleColumns(TableProperty.Name, TableProperty.Description, TableProperty.OU);
618    }
619
620    /**
621     * Updates the app.<p>
622     *
623     * @param uuid of current group
624     */
625    protected void updateApp(String uuid) {
626
627        try {
628            CmsGroup group = m_cms.readGroup(new CmsUUID(uuid));
629            m_app.update(group.getOuFqn(), m_type, group.getId(), "");
630        } catch (CmsException e) {
631            LOG.error("unable to read group.", e);
632        }
633    }
634
635    /**
636     * Checks value of table and sets it new if needed:<p>
637     * if multiselect: new itemId is in current Value? -> no change of value<p>
638     * no multiselect and multiselect, but new item not selected before: set value to new item<p>
639     *
640     * @param itemId if of clicked item
641     */
642    void changeValueIfNotMultiSelect(Object itemId) {
643
644        @SuppressWarnings("unchecked")
645        Set<String> value = (Set<String>)getValue();
646        if (value == null) {
647            select(itemId);
648        } else if (!value.contains(itemId)) {
649            setValue(null);
650            select(itemId);
651        }
652    }
653
654    /**
655     * Returns the available menu entries.<p>
656     *
657     * @return the menu entries
658     */
659    List<I_CmsSimpleContextMenuEntry<Set<String>>> getMenuEntries() {
660
661        if (m_menuEntries == null) {
662            m_menuEntries = new ArrayList<I_CmsSimpleContextMenuEntry<Set<String>>>();
663            m_menuEntries.add(new EntryOpen());
664            m_menuEntries.add(new EntryEdit());
665            m_menuEntries.add(new EntryShowResources());
666            m_menuEntries.add(new ImExport());
667            m_menuEntries.add(new EntryDelete());
668
669        }
670        return m_menuEntries;
671    }
672
673    /**
674     * Sets all groups.<p>
675     *
676     * @param directs the direct groups
677     *
678     * @throws CmsException if something goes wrong
679     */
680    private void setAllGroups(List<CmsGroup> directs) throws CmsException {
681
682        m_fullLoaded = true;
683        m_groups = m_app.readGroupsForOu(m_cms, m_ou, m_type, true);
684        m_indirects.clear();
685        for (CmsGroup group : m_groups) {
686            if (!directs.contains(group)) {
687                m_indirects.add(group);
688            }
689        }
690
691    }
692
693}