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.file.CmsUser;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.security.CmsAccessControlEntry;
037import org.opencms.security.CmsOrganizationalUnit;
038import org.opencms.security.CmsPrincipal;
039import org.opencms.security.CmsRole;
040import org.opencms.security.CmsRoleViolationException;
041import org.opencms.security.I_CmsPrincipal;
042import org.opencms.ui.A_CmsUI;
043import org.opencms.ui.CmsCssIcon;
044import org.opencms.ui.CmsUserIconHelper;
045import org.opencms.ui.CmsVaadinUtils;
046import org.opencms.ui.FontOpenCms;
047import org.opencms.ui.apps.A_CmsWorkplaceApp;
048import org.opencms.ui.apps.CmsAppWorkplaceUi;
049import org.opencms.ui.apps.CmsFileExplorer;
050import org.opencms.ui.apps.I_CmsAppUIContext;
051import org.opencms.ui.apps.Messages;
052import org.opencms.ui.apps.user.CmsGroupTable.TableProperty;
053import org.opencms.ui.components.CmsBasicDialog;
054import org.opencms.ui.components.CmsBasicDialog.DialogWidth;
055import org.opencms.ui.components.CmsInfoButton;
056import org.opencms.ui.components.CmsResourceInfo;
057import org.opencms.ui.components.CmsToolBar;
058import org.opencms.ui.components.OpenCmsTheme;
059import org.opencms.ui.dialogs.permissions.CmsPrincipalSelect.WidgetType;
060import org.opencms.ui.dialogs.permissions.CmsPrincipalSelectDialog;
061import org.opencms.ui.dialogs.permissions.I_CmsPrincipalSelect;
062import org.opencms.util.CmsStringUtil;
063import org.opencms.util.CmsUUID;
064
065import java.util.ArrayList;
066import java.util.Collections;
067import java.util.LinkedHashMap;
068import java.util.List;
069import java.util.Map;
070import java.util.Set;
071import java.util.function.Function;
072
073import org.apache.commons.logging.Log;
074
075import com.vaadin.server.ExternalResource;
076import com.vaadin.server.FontAwesome;
077import com.vaadin.server.Sizeable.Unit;
078import com.vaadin.ui.Button;
079import com.vaadin.ui.Button.ClickEvent;
080import com.vaadin.ui.Button.ClickListener;
081import com.vaadin.ui.Component;
082import com.vaadin.ui.HorizontalSplitPanel;
083import com.vaadin.ui.UI;
084import com.vaadin.ui.Window;
085import com.vaadin.ui.themes.ValoTheme;
086import com.vaadin.v7.data.Item;
087import com.vaadin.v7.data.Property.ValueChangeEvent;
088import com.vaadin.v7.data.Property.ValueChangeListener;
089import com.vaadin.v7.data.util.IndexedContainer;
090import com.vaadin.v7.event.FieldEvents.TextChangeEvent;
091import com.vaadin.v7.event.FieldEvents.TextChangeListener;
092import com.vaadin.v7.ui.ComboBox;
093import com.vaadin.v7.ui.Label;
094import com.vaadin.v7.ui.Table;
095import com.vaadin.v7.ui.TextField;
096import com.vaadin.v7.ui.VerticalLayout;
097
098/**
099 * App for the OU Management.<p>
100 */
101public class CmsAccountsApp extends A_CmsWorkplaceApp implements I_CmsPrincipalSelect {
102
103    /**
104     * Bean for the state of the app.<p>
105     */
106    class CmsStateBean {
107
108        /**the filter for tables. */
109        private String m_filter;
110
111        /**Group id to be opended (or null). */
112        private CmsUUID m_groupID;
113
114        /**ou path. */
115        private String m_path = "";
116
117        /**type of element to be openend. */
118        private I_CmsOuTreeType m_type;
119
120        /**
121         * public constructor.<p>
122         *
123         * @param path ou path
124         * @param type type to be opened
125         * @param groupID groupid
126         * @param filter filter string
127         */
128        public CmsStateBean(String path, I_CmsOuTreeType type, CmsUUID groupID, String filter) {
129
130            m_path = path.equals("/") ? "" : path;
131            m_type = type;
132            m_groupID = groupID;
133            m_filter = filter;
134        }
135
136        /**
137         * Gets group id.<p>
138         *
139         * @return group id
140         */
141        public CmsUUID getGroupID() {
142
143            return m_groupID;
144        }
145
146        /**
147         * Gets the ou path.<p>
148         *
149         * @return ou path
150         */
151        public String getPath() {
152
153            return m_path;
154        }
155
156        /**
157         * Gets the state string of the current bean.<p>
158         *
159         * @return state string
160         */
161        public String getState() {
162
163            String typeString = m_type.getId();
164            String groupString = "";
165            if (m_groupID != null) {
166                groupString = m_groupID.getStringValue();
167            }
168            return typeString + STATE_SEPERATOR + m_path + STATE_SEPERATOR + groupString + STATE_SEPERATOR + m_filter;
169
170        }
171
172        /**
173         * Gets the filter string for the table.<p>
174         *
175         * @return the table filter
176         */
177        public String getTableFilter() {
178
179            return m_filter;
180        }
181
182        /**
183         * Gets type of element to open.<p>
184         *
185         * @return type of element
186         */
187        public I_CmsOuTreeType getType() {
188
189            return m_type;
190        }
191    }
192
193    /**State seperator. */
194    public static String STATE_SEPERATOR = "!!";
195
196    /** Default tree type provider. */
197    private static final CmsDefaultTreeTypeProvider DEFAULT_TREETYPES = new CmsDefaultTreeTypeProvider();
198
199    /** The log object for this class. */
200    private static final Log LOG = CmsLog.getLog(CmsAccountsApp.class);
201
202    /**Button to add an element. */
203    protected Button m_addElementButton;
204
205    /**CmsObject. */
206    protected CmsObject m_cms;
207
208    /**vaadin component. */
209    protected CmsInfoButton m_infoButton;
210
211    /**vaadin component.*/
212    protected Button m_newButton;
213
214    /**vaadin component.*/
215    protected Button m_toggleButtonGroups;
216
217    /**vaadin component.*/
218    protected Button m_toggleButtonRole;
219
220    /**vaadin component.*/
221    protected Button m_toggleButtonUser;
222
223    /**Don't handle change event flag.*/
224    boolean m_doNotChange;
225
226    /**State bean. */
227    CmsStateBean m_stateBean;
228
229    /**Base ou. */
230    private String m_baseOU = "";
231
232    /**vaadin component.*/
233    private ComboBox m_filter;
234
235    /** The file table filter input. */
236    private TextField m_filterTable;
237
238    /**Class to handle visible and managable ous. */
239    private CmsOUHandler m_ouHandler;
240
241    /** The folder tree. */
242    private CmsOuTree m_ouTree;
243
244    /**vaadin component.*/
245    private HorizontalSplitPanel m_splitScreen;
246
247    /**vaadin component.*/
248    private I_CmsFilterableTable m_table;
249
250    /**
251     * constructor.<p>
252     */
253    public CmsAccountsApp() {
254
255        super();
256        try {
257            m_cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
258            m_cms.getRequestContext().setSiteRoot("");
259            m_ouHandler = new CmsOUHandler(m_cms);
260            m_baseOU = m_ouHandler.getBaseOU();
261
262        } catch (
263
264        CmsException e) {
265            //}
266        }
267        m_rootLayout.setMainHeightFull(true);
268        m_splitScreen = new HorizontalSplitPanel();
269        m_splitScreen.setSizeFull();
270        m_splitScreen.setSplitPosition(CmsFileExplorer.LAYOUT_SPLIT_POSITION, Unit.PIXELS);
271        m_rootLayout.setMainContent(m_splitScreen);
272        m_ouTree = new CmsOuTree(m_cms, this, m_baseOU);
273        m_splitScreen.setFirstComponent(m_ouTree);
274
275    }
276
277    /**
278     * Creates info panel for OUs.<p>
279     *
280     *
281     * @param ou to get panel for
282     * @return CmsResourceInfo
283     */
284    public static CmsResourceInfo getOUInfo(CmsOrganizationalUnit ou) {
285
286        String style = OpenCmsTheme.ICON_OU;
287        if (ou.hasFlagWebuser()) {
288            style = OpenCmsTheme.ICON_OU_WEB;
289        }
290        CmsCssIcon image = new CmsCssIcon(style);
291        return new CmsResourceInfo(
292            ou.getDisplayName(A_CmsUI.get().getLocale()),
293            ou.getDescription(A_CmsUI.get().getLocale()),
294            image);
295    }
296
297    /**
298     * Creates info panel for principals.<p>
299     *
300     * @param principal to get info panel for
301     * @return CmsResourceInfo
302     */
303    public static CmsResourceInfo getPrincipalInfo(I_CmsPrincipal principal) {
304
305        if (principal == null) {
306            return null;
307        }
308        if (principal instanceof CmsUser) {
309            CmsUser user = (CmsUser)principal;
310            CmsUserIconHelper helper = OpenCms.getWorkplaceAppManager().getUserIconHelper();
311            return new CmsResourceInfo(
312                user.getName(),
313                user.getEmail(),
314                new ExternalResource(helper.getTinyIconPath(A_CmsUI.getCmsObject(), user)));
315        }
316        if (principal.getId().equals(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID)) {
317            return new CmsResourceInfo(
318                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_LABEL_ALLOTHERS_0),
319                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_DESCRIPTION_ALLOTHERS_0),
320                new CmsCssIcon(OpenCmsTheme.ICON_PRINCIPAL_ALL));
321        }
322        if (principal.getId().equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID)) {
323            return new CmsResourceInfo(
324                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_LABEL_OVERWRITEALL_0),
325                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_DESCRIPTION_OVERWRITEALL_0),
326                new CmsCssIcon(OpenCmsTheme.ICON_PRINCIPAL_OVERWRITE));
327        }
328        CmsRole role = CmsRole.valueOfId(principal.getId());
329        if (role != null) {
330            return new CmsResourceInfo(
331                role.getName(A_CmsUI.get().getLocale()),
332                role.getDescription(A_CmsUI.get().getLocale()),
333                new CmsCssIcon(OpenCmsTheme.ICON_ROLE));
334        }
335        return new CmsResourceInfo(
336            principal.getName(),
337            principal.getDescription(A_CmsUI.get().getLocale()),
338            new CmsCssIcon(OpenCmsTheme.ICON_GROUP));
339    }
340
341    /**
342     * Adds additional properties for groups to a container.
343     *
344     * @param container the container to update
345     */
346    public void addGroupContainerProperties(IndexedContainer container) {
347
348        // do nothing
349
350    }
351
352    /**
353     * Adds additional properties for users to a container.
354     *
355     * @param container the container to update
356     */
357    public void addUserContainerProperties(IndexedContainer container) {
358
359        // do nothing
360
361    }
362
363    /**
364     * Checks if the given user is editable.<p>
365     *
366     * @param id the id of the user
367     * @return true if the user is editable
368     */
369    public boolean canEditUser(CmsUUID id) {
370
371        return true;
372    }
373
374    /**
375     * Checks if group members can be removed from the given OU.<p>
376     *
377     * @param group the group name
378     * @return true if group members can be removed from the given OU
379     */
380    public boolean canRemoveGroupMemebers(String group) {
381
382        return true;
383    }
384
385    /**
386     * Checks if a set of groups can be added to a user.<p>
387     *
388     * @param principal the user
389     * @param data the set of names of groups to check
390     *
391     * @return true if the groups can be added to the user
392     */
393    public boolean checkAddGroup(CmsUser principal, Set<String> data) {
394
395        return true;
396    }
397
398    /**
399     * Checks if a user can be removed from a set of groups.<p>
400     *
401     * @param principal the user
402     * @param items the names of groups to check
403     *
404     * @return true if the user can be removed from  the group
405     */
406    public boolean checkRemoveGroups(CmsUser principal, Set<String> items) {
407
408        return true;
409    }
410
411    /**
412     * Fills the container item representing a group.<p>
413     *
414     * @param item the item
415     * @param group the group
416     * @param indirects the indirect groups
417     */
418    public void fillGroupItem(Item item, CmsGroup group, List<CmsGroup> indirects) {
419
420        item.getItemProperty(TableProperty.Name).setValue(group.getName());
421        item.getItemProperty(TableProperty.Description).setValue(group.getDescription(A_CmsUI.get().getLocale()));
422        item.getItemProperty(TableProperty.OU).setValue(group.getOuFqn());
423        if (indirects.contains(group)) {
424            item.getItemProperty(TableProperty.INDIRECT).setValue(Boolean.TRUE);
425        }
426    }
427
428    /**
429    * Gets the app id.<p>
430    *
431    * @return the app id
432    */
433    public String getAppId() {
434
435        return CmsAccountsAppConfiguration.APP_ID;
436    }
437
438    /**
439     * Gets a data container for the groups available to be added to a user, excluding some groups.<p>
440     *
441     * @param cms the current CMS context
442     * @param ouFqn the OU for which to get the groups
443     * @param propCaption the property for the caption
444     * @param propIcon the property for the icon
445     * @param propOu the property for the OU
446     * @param groupsOfUser the groups to exclude
447     * @param iconProvider the icon provider
448     *
449     * @return the container with the group data
450     */
451    public IndexedContainer getAvailableGroupsContainerWithout(
452        CmsObject cms,
453        String ouFqn,
454        String propCaption,
455        String propIcon,
456        String propOu,
457        List<CmsGroup> groupsOfUser,
458        Function<CmsGroup, CmsCssIcon> iconProvider) {
459
460        // TODO Auto-generated method stub
461        return CmsVaadinUtils.getAvailableGroupsContainerWithout(
462            cms,
463            ouFqn,
464            propCaption,
465            propIcon,
466            propOu,
467            groupsOfUser,
468            iconProvider);
469    }
470
471    /**
472     * Gets the group edit parameters for a given group.<p>
473     *
474     * @param group a group
475     *
476     * @return the group edit parameters for the group
477     */
478    public CmsGroupEditParameters getGroupEditParameters(CmsGroup group) {
479
480        CmsGroupEditParameters params = new CmsGroupEditParameters();
481        return params;
482    }
483
484    /**
485     * Gets the icon for a group.<p>
486     *
487     * @param group the group
488     * @return the icon for the group
489     */
490    public CmsCssIcon getGroupIcon(CmsGroup group) {
491
492        return new CmsCssIcon("oc-icon-24-group");
493    }
494
495    /**
496     * Gets the user edit parameters.<p>
497     *
498     * @param user the user
499     * @return the user edit parameters
500     */
501    public CmsUserEditParameters getUserEditParameters(CmsUser user) {
502
503        CmsUserEditParameters params = new CmsUserEditParameters();
504        params.setEditEnabled(true);
505        params.setPasswordChangeEnabled(true);
506        return params;
507    }
508
509    /**
510     * Gets the container for the groups of an user for the purpose of editing them.<p>
511     *
512     * @param user the user
513     * @param propName the property for the name
514     * @param propIcon the property for the icon
515     * @param propStatus the property for the status
516     *
517     * @return the container with the user groups
518     */
519    public IndexedContainer getUserGroupsEditorContainer(
520        CmsUser user,
521        String propName,
522        String propIcon,
523        String propStatus) {
524
525        IndexedContainer container = new IndexedContainer();
526        container.addContainerProperty(propName, String.class, "");
527        container.addContainerProperty(CmsUserEditGroupsDialog.ID_OU, String.class, "");
528        container.addContainerProperty(propStatus, Boolean.class, new Boolean(true));
529        container.addContainerProperty(propIcon, CmsCssIcon.class, new CmsCssIcon("oc-icon-group-24"));
530        try {
531            for (CmsGroup group : m_cms.getGroupsOfUser(user.getName(), true)) {
532                Item item = container.addItem(group);
533                item.getItemProperty(propName).setValue(group.getSimpleName());
534                item.getItemProperty(CmsUserEditGroupsDialog.ID_OU).setValue(group.getOuFqn());
535                item.getItemProperty(propIcon).setValue(getGroupIcon(group));
536            }
537        } catch (CmsException e) {
538            LOG.error("Unable to read groups from user", e);
539        }
540        return container;
541    }
542
543    /**
544     * Gets list of users for organizational unit.<p>
545     *
546     * @param cms the CMS context
547     * @param ou the OU path
548     * @param recursive true if users from other OUs should be retrieved
549     *
550     * @return the list of users, without their additional info
551     *
552     * @throws CmsException if something goes wrong
553     */
554    public List<CmsUser> getUsersWithoutAdditionalInfo(
555        CmsObject cms,
556        I_CmsOuTreeType type,
557        String ou,
558        boolean recursive)
559    throws CmsException {
560
561        return CmsPrincipal.filterCoreUsers(
562            OpenCms.getOrgUnitManager().getUsersWithoutAdditionalInfo(cms, ou, recursive));
563    }
564
565    /**
566     * @see org.opencms.ui.dialogs.permissions.I_CmsPrincipalSelect#handlePrincipal(org.opencms.security.I_CmsPrincipal)
567     */
568    public void handlePrincipal(I_CmsPrincipal principal) {
569
570        if (m_stateBean.getType().isGroup()) {
571            try {
572                CmsGroup group = m_cms.readGroup(m_stateBean.getGroupID());
573                m_cms.addUserToGroup(principal.getName(), group.getName());
574
575            } catch (CmsException e) {
576                return;
577            }
578        }
579        if (m_stateBean.getType().isRole()) {
580            try {
581                OpenCms.getRoleManager().addUserToRole(
582                    m_cms,
583                    CmsRole.valueOfId(m_stateBean.getGroupID()).forOrgUnit(m_stateBean.getPath()),
584                    principal.getName());
585            } catch (CmsException e) {
586                return;
587            }
588        }
589        A_CmsUI.get().reload();
590    }
591
592    /**
593     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext)
594     */
595    @Override
596    public void initUI(I_CmsAppUIContext context) {
597
598        context.addPublishButton(changed -> {/* do nothing*/});
599        super.initUI(context);
600    }
601
602    /**
603     * Checks if the given OU is manageable.<p>
604     *
605     * @param ou to check
606     * @return true if user is allowed to manage ou
607     */
608    public boolean isOUManagable(String ou) {
609
610        return m_ouHandler.isOUManagable(ou);
611    }
612
613    /**
614     * Checks if given ou is parent of a managable ou.<p>
615     *
616     * @param name to check
617     * @return boolean
618     */
619    public boolean isParentOfManagableOU(String name) {
620
621        return m_ouHandler.isParentOfManagableOU(name);
622    }
623
624    /**
625     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#openSubView(java.lang.String, boolean)
626     */
627    @Override
628    public void openSubView(String state, boolean updateState) {
629
630        if (updateState) {
631            CmsAppWorkplaceUi.get().changeCurrentAppState(state);
632        }
633
634        Component comp = getComponentForState(state);
635
636        updateInfoButton();
637        if (comp != null) {
638            VerticalLayout layout = new VerticalLayout();
639            layout.setSizeFull();
640            comp.setSizeFull();
641            layout.addComponent(m_table.getEmptyLayout());
642            layout.addComponent(m_table);
643            handleSetTable(m_table);
644            m_splitScreen.setSecondComponent(layout);
645        } else {
646            m_splitScreen.setSecondComponent(new Label("Malformed path, tool not available for path: " + state));
647            handleSetTable(null);
648        }
649        m_splitScreen.setSizeFull();
650        updateSubNav(getSubNavEntries(state));
651        updateBreadCrumb(getBreadCrumbForState(state));
652    }
653
654    /**
655     * Parses a given state string to state bean.<p>
656     *
657     * @param state to be read
658     * @param baseOU baseOu
659     * @return CmsStateBean
660     */
661    public CmsStateBean parseState(String state, String baseOU) {
662
663        String path = baseOU;
664        String filter = "";
665        I_CmsOuTreeType type = CmsOuTreeType.OU;
666        CmsUUID groupId = null;
667        List<String> fields = CmsStringUtil.splitAsList(state, STATE_SEPERATOR);
668        if (!fields.isEmpty()) {
669            if (fields.size() > 1) {
670                path = fields.get(1);
671                //Make sure to only show OUs which are under baseOU
672                if (path.equals("") | !path.startsWith(baseOU)) {
673                    path = baseOU;
674                }
675            }
676            for (I_CmsOuTreeType ty : getTreeTypeProvider().getTreeTypes()) {
677                if (fields.get(0).equals(ty.getId())) {
678                    type = ty;
679                }
680            }
681            if (fields.size() > 2) {
682                if (!CmsStringUtil.isEmptyOrWhitespaceOnly(fields.get(2))) {
683                    groupId = new CmsUUID(fields.get(2));
684                }
685            }
686            if (fields.size() > 3) {
687                filter = fields.get(3);
688            }
689        }
690        return new CmsStateBean(path, type, groupId, filter);
691    }
692
693    /**
694     * Reads the list of groups for an organizational unit.<p>
695     *
696     * @param cms the CMS context
697     * @param ou the OU path
698     * @param type the tree type
699     * @param subOus true if groups for sub-OUs should be read
700     * @return the list of groups for the OU
701     *
702     * @throws CmsException if something goes wrong
703     */
704    public List<CmsGroup> readGroupsForOu(CmsObject cms, String ou, I_CmsOuTreeType type, boolean subOus)
705    throws CmsException {
706
707        return CmsPrincipal.filterCoreGroups(OpenCms.getOrgUnitManager().getGroups(m_cms, ou, subOus));
708    }
709
710    /**
711     * Reloads the app with current state.<p>
712     */
713    public void reload() {
714
715        update(m_stateBean.getPath(), m_stateBean.getType(), m_stateBean.getGroupID());
716    }
717
718    /**
719     * @see org.opencms.ui.dialogs.permissions.I_CmsPrincipalSelect#setType(java.lang.String)
720     */
721    public void setType(String type) {
722
723        // is never called
724
725    }
726
727    /**
728     * Updates the app state.<p>
729     *
730     * @param ou to be opened
731     * @param type to be opened
732     * @param groupID to be openend(may be null)
733     */
734    public void update(String ou, I_CmsOuTreeType type, CmsUUID groupID) {
735
736        update(ou, type, groupID, m_filterTable.getValue());
737
738    }
739
740    /**
741     * Updates the app state.<p>
742     *
743     * @param ou to be opened
744     * @param type to be opened
745     * @param roleOrGroupID to be openend(may be null)
746     * @param filter filter string
747     */
748    public void update(String ou, I_CmsOuTreeType type, CmsUUID roleOrGroupID, String filter) {
749
750        CmsStateBean stateBean = new CmsStateBean(ou, type, roleOrGroupID, filter);
751        openSubView(stateBean.getState(), true);
752
753    }
754
755    /**
756     * Creates a table for displaying groups.<p>
757     *
758     * @param path the path
759     * @param cmsAccountsApp the app instance
760     * @param type the tree type
761     * @param toggle the value of the 'sub-OU' toggle
762     *
763     * @return the table
764     */
765    protected I_CmsFilterableTable createGroupTable(
766        String path,
767        CmsAccountsApp cmsAccountsApp,
768        I_CmsOuTreeType type,
769        boolean toggle) {
770
771        return new CmsGroupTable(path, cmsAccountsApp, type, toggle);
772    }
773
774    /**
775     * Creates the overview table for the given OU.<p>
776     *
777     * @param ou the OU path
778     * @return the overview table for the given OU
779     */
780    protected I_CmsFilterableTable createOUTable(String ou) {
781
782        return new CmsOUTable(ou, this);
783    }
784
785    /**
786     * Creates the role table for  the given OU.<p>
787     *
788     * @param ou the OU path
789     * @return the role table for the given OU
790     */
791    protected I_CmsFilterableTable createRoleTable(String ou) {
792
793        return new CmsRoleTable(this, ou);
794    }
795
796    /**
797     * Creates user table for a specific group or role.<p>
798     *
799     * @param ou the OU path
800     * @param groupID the group id
801     * @param type the tree type
802     * @param showAll true if all users should be shown
803     * @param cmsAccountsApp the app instance
804     *
805     * @return the user table
806     */
807    protected I_CmsFilterableTable createUserTable(
808        String ou,
809        CmsUUID groupID,
810        I_CmsOuTreeType type,
811        boolean showAll,
812        CmsAccountsApp cmsAccountsApp) {
813
814        return new CmsUserTable(ou, groupID, type, showAll, cmsAccountsApp);
815    }
816
817    /**
818     * Creates the user table for an OU.<p>
819     *
820     * @param ou the OU path
821     * @param type the tree type
822     * @param cmsAccountsApp the app instance
823     * @param buttonPressed true if toggle button for users is active
824    
825     * @return the user table
826     */
827    protected I_CmsFilterableTable createUserTable(
828        String ou,
829        I_CmsOuTreeType type,
830        CmsAccountsApp cmsAccountsApp,
831        boolean buttonPressed) {
832
833        return new CmsUserTable(ou, type, cmsAccountsApp, buttonPressed);
834    }
835
836    /**
837     * Filters table.<p>
838     *"
839     * @param text for filter
840     */
841    protected void filterTable(String text) {
842
843        if (m_table != null) {
844            m_table.filter(text);
845        }
846    }
847
848    /**
849     * Gets the additional buttons to display.<p>
850     *
851     * @return the additional buttons to display
852     */
853    protected List<Button> getAdditionalButtons() {
854
855        return new ArrayList<>();
856    }
857
858    /**
859     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String)
860     */
861    @Override
862    protected LinkedHashMap<String, String> getBreadCrumbForState(String state) {
863
864        try {
865            CmsStateBean bean = parseState(state, m_baseOU);
866            String[] ouPath = bean.getPath().split("/");
867            LinkedHashMap<String, String> crumbs = new LinkedHashMap<String, String>();
868
869            if ((bean.getPath().equals(m_baseOU))
870                && (CmsOuTreeType.OU.equals(bean.getType()) | (bean.getType() == null))) {
871                crumbs.put(
872                    "",
873                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_TOOL_NAME_0)
874                        + " ("
875                        + OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, m_baseOU).getDisplayName(
876                            A_CmsUI.get().getLocale())
877                        + ")");
878                return crumbs;
879            }
880            CmsStateBean beanCr = new CmsStateBean(m_baseOU, CmsOuTreeType.OU, null, "");
881            crumbs.put(
882                getAppId() + "/" + beanCr.getState(),
883                CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_TOOL_NAME_0)
884                    + " ("
885                    + OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, m_baseOU).getDisplayName(
886                        A_CmsUI.get().getLocale())
887                    + ")");
888            String base = "";
889            String pathOfLastElement = "";
890            for (String oP : ouPath) {
891                if (!oP.isEmpty()) {
892                    if ((oP + base).length() > m_baseOU.length()) {
893                        if (oP.equals(ouPath[ouPath.length - 1])) {
894                            CmsStateBean beanCrumb = new CmsStateBean(base + oP, CmsOuTreeType.OU, null, "");
895                            pathOfLastElement = getAppId() + "/" + beanCrumb.getState();
896                            crumbs.put("", oP);
897                        } else {
898                            CmsStateBean beanCrumb = new CmsStateBean(base + oP, CmsOuTreeType.OU, null, "");
899                            crumbs.put(getAppId() + "/" + beanCrumb.getState(), oP);
900                        }
901                    }
902                    base += oP + "/";
903                }
904            }
905            if (bean.getType() != null) {
906                if (!bean.getType().equals(CmsOuTreeType.OU)) {
907                    if (!pathOfLastElement.isEmpty()) {
908                        crumbs.put(pathOfLastElement, crumbs.get(""));
909                        crumbs.remove("");
910                    }
911                    if (bean.getGroupID() == null) {
912                        crumbs.put("", bean.getType().getName());
913                    } else {
914                        CmsStateBean beanCrumb = new CmsStateBean(bean.getPath(), bean.getType(), null, "");
915                        crumbs.put(getAppId() + "/" + beanCrumb.getState(), beanCrumb.getType().getName());
916                        if (bean.getType().equals(CmsOuTreeType.ROLE)) {
917                            crumbs.put("", CmsRole.valueOfId(bean.getGroupID()).getName(A_CmsUI.get().getLocale()));
918                        } else {
919                            crumbs.put("", m_cms.readGroup(bean.getGroupID()).getSimpleName());
920                        }
921                    }
922                }
923            }
924            return crumbs;
925        } catch (CmsException e) {
926            return null;
927        }
928    }
929
930    /**
931     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String)
932     */
933    @Override
934    protected Component getComponentForState(String state) {
935
936        m_stateBean = parseState(state, m_baseOU);
937
938        if (m_filter == null) {
939            iniButtons();
940        }
941
942        m_doNotChange = true;
943
944        m_filter.setValue(m_stateBean.getPath());
945        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_stateBean.getTableFilter())) {
946            m_filterTable.setValue(m_stateBean.getTableFilter());
947        } else {
948            m_filterTable.setValue("");
949        }
950
951        m_newButton.setVisible((m_stateBean.getGroupID() == null) & isOUManagable(m_stateBean.getPath()));
952        m_toggleButtonRole.setVisible(m_stateBean.getType().isRole() && (m_stateBean.getGroupID() != null));
953        m_toggleButtonUser.setVisible(m_stateBean.getType().isUser());
954
955        m_toggleButtonGroups.setVisible(m_stateBean.getType().isGroup() && (m_stateBean.getGroupID() == null));
956        m_infoButton.setVisible(
957            m_stateBean.getType().isUser()
958                || (m_stateBean.getType().isRole() && (m_stateBean.getGroupID() != null))
959                || (m_stateBean.getType().isGroup() && (m_stateBean.getGroupID() != null)));
960        m_addElementButton.setVisible(
961            (m_stateBean.getType().isGroup() || m_stateBean.getType().isRole()) & (m_stateBean.getGroupID() != null));
962        m_ouTree.openPath(m_stateBean.getPath(), m_stateBean.getType(), m_stateBean.getGroupID());
963
964        m_doNotChange = false;
965        I_CmsFilterableTable table = null;
966        if (m_stateBean.getType().equals(CmsOuTreeType.OU)) {
967            m_table = createOUTable(m_stateBean.getPath());
968            table = m_table;
969        }
970        if (m_stateBean.getType().isUser()) {
971            m_table = createUserTable(
972                m_stateBean.getPath(),
973                m_stateBean.getType(),
974                this,
975                CmsVaadinUtils.isButtonPressed(m_toggleButtonUser));
976            table = m_table;
977        }
978        if (m_stateBean.getType().isGroup()) {
979            if (m_stateBean.getGroupID() == null) {
980                m_table = createGroupTable(
981                    m_stateBean.getPath(),
982                    this,
983                    m_stateBean.getType(),
984                    CmsVaadinUtils.isButtonPressed(m_toggleButtonGroups));
985                table = m_table;
986            } else {
987                m_table = createUserTable(
988                    m_stateBean.getPath(),
989                    m_stateBean.getGroupID(),
990                    m_stateBean.getType(),
991                    false,
992                    this);
993                table = m_table;
994            }
995        }
996        if (m_stateBean.getType().isRole()) {
997            if (m_stateBean.getGroupID() == null) {
998                m_table = createRoleTable(m_stateBean.getPath());
999                table = m_table;
1000            } else {
1001                m_table = createUserTable(
1002                    m_stateBean.getPath(),
1003                    m_stateBean.getGroupID(),
1004                    m_stateBean.getType(),
1005                    CmsVaadinUtils.isButtonPressed(m_toggleButtonRole),
1006                    this);
1007                table = m_table;
1008            }
1009        }
1010        if ((table != null) && !CmsStringUtil.isEmptyOrWhitespaceOnly(m_filterTable.getValue())) {
1011            table.filter(m_filterTable.getValue());
1012        }
1013        return table;
1014    }
1015
1016    /**
1017     * Gets the group-, role-, or ou name.<p>
1018     *
1019     * @param stateBean to be read out
1020     * @return Name
1021     */
1022    protected String getElementName(CmsStateBean stateBean) {
1023
1024        if (stateBean.getType().equals(CmsOuTreeType.USER)) {
1025            try {
1026                return OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, stateBean.getPath()).getDisplayName(
1027                    A_CmsUI.get().getLocale());
1028            } catch (CmsException e) {
1029                LOG.error("Unable to read OU", e);
1030            }
1031        }
1032        if (stateBean.getType().equals(CmsOuTreeType.ROLE)) {
1033            return CmsRole.valueOfId(stateBean.getGroupID()).getName(A_CmsUI.get().getLocale());
1034        } else {
1035            try {
1036                return m_cms.readGroup(stateBean.getGroupID()).getSimpleName();
1037            } catch (CmsException e) {
1038                LOG.error("Unable to read group", e);
1039            }
1040        }
1041        return "";
1042    }
1043
1044    /**
1045     * Gets the full user List including additionInfos.<p>
1046     *
1047     * @param users user list
1048     * @return List of user
1049     */
1050    protected List<CmsUser> getFullUser(List<CmsUser> users) {
1051
1052        List<CmsUser> res = new ArrayList<CmsUser>();
1053        for (CmsUser user : users) {
1054            try {
1055                res.add(m_cms.readUser(user.getId()));
1056            } catch (CmsException e) {
1057                LOG.error("Unable to read user", e);
1058            }
1059        }
1060        return res;
1061    }
1062
1063    /**
1064     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String)
1065     */
1066    @Override
1067    protected List<NavEntry> getSubNavEntries(String state) {
1068
1069        return null;
1070    }
1071
1072    /**
1073     * Get the current toggle button.<p>
1074     *
1075     * @param stateBean to be read out
1076     * @return Button
1077     */
1078    protected Button getToggleButton(CmsStateBean stateBean) {
1079
1080        if (stateBean.getType().equals(CmsOuTreeType.USER)) {
1081            return m_toggleButtonUser;
1082        }
1083        if (stateBean.getType().equals(CmsOuTreeType.ROLE)) {
1084            return m_toggleButtonRole;
1085        } else {
1086            return m_toggleButtonGroups;
1087        }
1088    }
1089
1090    /**
1091     * Gets the tree type provider.<p>
1092     *
1093     * @return the tree type provider
1094     */
1095    protected I_CmsTreeTypeProvider getTreeTypeProvider() {
1096
1097        return DEFAULT_TREETYPES;
1098    }
1099
1100    /**
1101     * Gets all currently visible user.<p>
1102     *
1103     * @return List of CmsUser
1104     */
1105    protected List<CmsUser> getVisibleUser() {
1106
1107        if (m_table instanceof CmsUserTable) {
1108            return ((CmsUserTable)m_table).getVisibleUser();
1109        }
1110        return null;
1111    }
1112
1113    /**
1114     * Called when new table is shown.<p>
1115     *
1116     * @param component the table that is displayed
1117     */
1118    protected void handleSetTable(Component component) {
1119        // do nothing
1120    }
1121
1122    /**
1123     * Opens a dialog for a new item (ou, group or user).<p>
1124     */
1125    protected void openNewDialog() {
1126
1127        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
1128        CmsBasicDialog dialog = new CmsNewElementDialog(m_cms, m_stateBean.getPath(), window, this);
1129        window.setContent(dialog);
1130        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_ELEMENT_0));
1131        A_CmsUI.get().addWindow(window);
1132    }
1133
1134    /**
1135     * opens a principle select dialog.<p>
1136     */
1137    void openAddUserDialog() {
1138
1139        CmsPrincipalSelectDialog dialog;
1140
1141        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.max);
1142
1143        dialog = new CmsPrincipalSelectDialog(
1144            this,
1145            m_stateBean.getPath(),
1146            window,
1147            WidgetType.userwidget,
1148            true,
1149            WidgetType.userwidget);
1150
1151        try {
1152            dialog.setOuComboBoxEnabled(
1153                !OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, m_stateBean.getPath()).hasFlagWebuser()
1154                    | m_stateBean.getType().equals(CmsOuTreeType.ROLE));
1155        } catch (CmsException e) {
1156            LOG.error("Can not read OU.", e);
1157        }
1158        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_USER_TO_GROUP_0));
1159        window.setContent(dialog);
1160        A_CmsUI.get().addWindow(window);
1161
1162    }
1163
1164    /**
1165     * Toggles the table.<p>
1166     *
1167     * @param toggleButton the toggle button state
1168     */
1169    void toggleTable(Button toggleButton) {
1170
1171        I_CmsToggleTable table = (I_CmsToggleTable)m_table;
1172        table.toggle(!CmsVaadinUtils.isButtonPressed(toggleButton));
1173        CmsVaadinUtils.toggleButton(toggleButton);
1174        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_filterTable.getValue())) {
1175            filterTable(m_filterTable.getValue());
1176        }
1177        updateInfoButton();
1178    }
1179
1180    /**
1181     * Initializes the toolbar buttons.<p>
1182     */
1183    private void iniButtons() {
1184
1185        m_newButton = CmsToolBar.createButton(
1186            FontOpenCms.WAND,
1187            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_ELEMENT_0));
1188        m_newButton.addClickListener(new ClickListener() {
1189
1190            private static final long serialVersionUID = 1L;
1191
1192            public void buttonClick(ClickEvent event) {
1193
1194                openNewDialog();
1195            }
1196        });
1197        m_infoButton = new CmsInfoButton();
1198        Button csvButton = new Button(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_EXPORT_ONLY_USER_0));
1199        csvButton.addClickListener(new ClickListener() {
1200
1201            private static final long serialVersionUID = 5472430305539438757L;
1202
1203            public void buttonClick(ClickEvent event) {
1204
1205                boolean includeTechnicalFields = false;
1206                try {
1207                    OpenCms.getRoleManager().checkRole(m_cms, CmsRole.ADMINISTRATOR);
1208                    includeTechnicalFields = true;
1209                } catch (CmsRoleViolationException e) {
1210                    // ok
1211                }
1212                Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
1213                CmsUserCsvExportDialog dialog = new CmsUserCsvExportDialog(
1214                    getFullUser(getVisibleUser()),
1215                    m_stateBean.getPath(),
1216                    m_stateBean.getType(),
1217                    getElementName(m_stateBean),
1218                    CmsVaadinUtils.isButtonPressed(getToggleButton(m_stateBean)),
1219                    window,
1220                    includeTechnicalFields);
1221                window.setContent(dialog);
1222                A_CmsUI.get().addWindow(window);
1223
1224            }
1225
1226        });
1227        m_infoButton.setAdditionalButton(csvButton);
1228
1229        m_addElementButton = CmsToolBar.createButton(
1230            FontAwesome.PLUS,
1231            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_USER_TO_GROUP_0));
1232        m_addElementButton.addClickListener(new ClickListener() {
1233
1234            private static final long serialVersionUID = 1859694635385726953L;
1235
1236            public void buttonClick(ClickEvent event) {
1237
1238                openAddUserDialog();
1239
1240            }
1241        });
1242
1243        m_toggleButtonRole = CmsToolBar.createButton(
1244            FontOpenCms.USERS,
1245            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ROLES_TOGGLE_0));
1246        m_toggleButtonRole.addClickListener(new ClickListener() {
1247
1248            private static final long serialVersionUID = 8265075332953321274L;
1249
1250            public void buttonClick(ClickEvent event) {
1251
1252                toggleTable(m_toggleButtonRole);
1253
1254            }
1255
1256        });
1257
1258        m_toggleButtonUser = CmsToolBar.createButton(
1259            FontOpenCms.USERS,
1260            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_USER_TOGGLE_0));
1261        m_toggleButtonUser.addClickListener(new ClickListener() {
1262
1263            private static final long serialVersionUID = 8265075332953321274L;
1264
1265            public void buttonClick(ClickEvent event) {
1266
1267                toggleTable(m_toggleButtonUser);
1268
1269            }
1270
1271        });
1272
1273        m_toggleButtonGroups = CmsToolBar.createButton(
1274            FontOpenCms.USERS,
1275            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUPS_TOGGLE_0));
1276        m_toggleButtonGroups.addClickListener(new ClickListener() {
1277
1278            private static final long serialVersionUID = 8265075332953321274L;
1279
1280            public void buttonClick(ClickEvent event) {
1281
1282                toggleTable(m_toggleButtonGroups);
1283
1284            }
1285
1286        });
1287
1288        m_uiContext.addToolbarButton(m_newButton);
1289
1290        m_uiContext.addToolbarButton(m_addElementButton);
1291        m_uiContext.addToolbarButton(m_infoButton);
1292        m_uiContext.addToolbarButton(m_toggleButtonRole);
1293        m_uiContext.addToolbarButton(m_toggleButtonUser);
1294        m_uiContext.addToolbarButton(m_toggleButtonGroups);
1295
1296        for (Button button : getAdditionalButtons()) {
1297            m_uiContext.addToolbarButton(button);
1298        }
1299        m_filter = CmsVaadinUtils.getOUComboBox(m_cms, m_baseOU, LOG);
1300        m_filter.setWidth("379px");
1301        m_infoLayout.addComponent(m_filter, 0);
1302
1303        m_filterTable = new TextField();
1304        m_filterTable.setIcon(FontOpenCms.FILTER);
1305        m_filterTable.setInputPrompt(
1306            Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0));
1307        m_filterTable.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
1308        //            m_filterTable.setWidth("200px");
1309        m_filterTable.addTextChangeListener(new TextChangeListener() {
1310
1311            private static final long serialVersionUID = 1L;
1312
1313            public void textChange(TextChangeEvent event) {
1314
1315                filterTable(event.getText());
1316            }
1317        });
1318        m_filterTable.setWidth("200px");
1319        m_infoLayout.addComponent(m_filterTable);
1320        m_infoLayout.addStyleName("o-many-elements");
1321        m_filter.addValueChangeListener(new ValueChangeListener() {
1322
1323            private static final long serialVersionUID = 1L;
1324
1325            public void valueChange(ValueChangeEvent event) {
1326
1327                if ((m_stateBean.getType() != null) & !m_doNotChange) {
1328                    update((String)event.getProperty().getValue(), CmsOuTreeType.OU, null);
1329                } else {
1330                    //
1331                }
1332            }
1333        });
1334        if (!m_ouHandler.isOUManagable(m_stateBean.getPath())) {
1335            boolean change = m_doNotChange;
1336            m_doNotChange = false;
1337            m_filter.select(m_filter.getItemIds().iterator().next());
1338            m_doNotChange = change;
1339        }
1340    }
1341
1342    /**
1343     * Updates the info button.<p>
1344     */
1345    private void updateInfoButton() {
1346
1347        if (m_stateBean.getType().isUser()) {
1348            Map<String, String> dataMap = new LinkedHashMap<String, String>();
1349            dataMap.put(
1350                CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_COUNT_0),
1351                String.valueOf(((Table)m_table).size()));
1352            try {
1353                int count = getUsersWithoutAdditionalInfo(
1354                    m_cms,
1355                    m_stateBean.getType(),
1356                    m_stateBean.getPath(),
1357                    true).size();
1358                if (count > ((Table)m_table).size()) {
1359                    dataMap.put(
1360                        CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_TOT_COUNT_0),
1361                        String.valueOf(count));
1362                }
1363            } catch (CmsException e) {
1364                //;
1365            }
1366            m_infoButton.replaceData(dataMap);
1367        } else {
1368            int size = ((Table)m_table).size();
1369            if (m_table instanceof CmsUserTable) {
1370                size = ((CmsUserTable)m_table).getVisibleUser().size();
1371            }
1372            m_infoButton.replaceData(
1373                Collections.singletonMap(
1374                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_COUNT_0),
1375                    String.valueOf(size)));
1376        }
1377    }
1378
1379}