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