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.components;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsUser;
032import org.opencms.i18n.CmsMessages;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsIllegalArgumentException;
035import org.opencms.main.CmsLog;
036import org.opencms.main.OpenCms;
037import org.opencms.ui.CmsVaadinUtils;
038import org.opencms.ui.util.CmsNullToEmptyConverter;
039import org.opencms.util.CmsStringUtil;
040import org.opencms.workplace.CmsAccountInfo;
041import org.opencms.workplace.CmsAccountInfo.Field;
042
043import java.lang.reflect.InvocationTargetException;
044
045import org.apache.commons.beanutils.PropertyUtilsBean;
046import org.apache.commons.logging.Log;
047
048import com.vaadin.ui.Component;
049import com.vaadin.ui.FormLayout;
050import com.vaadin.ui.UI;
051import com.vaadin.v7.data.fieldgroup.FieldGroup;
052import com.vaadin.v7.data.fieldgroup.FieldGroup.CommitException;
053import com.vaadin.v7.data.util.ObjectProperty;
054import com.vaadin.v7.data.util.PropertysetItem;
055import com.vaadin.v7.data.validator.AbstractStringValidator;
056import com.vaadin.v7.ui.TextField;
057
058/**
059 * Form Layout for user data.<p>
060 */
061public class CmsUserDataFormLayout extends FormLayout {
062
063    public enum EditLevel {
064        all, configured, none;
065    }
066
067    /**
068     * Validator employing the configured OpenCms validation handler.<p>
069     */
070    private static class FieldValidator extends AbstractStringValidator {
071
072        /** The serial version id. */
073        private static final long serialVersionUID = 4432834072807177046L;
074
075        /** The field to validate. */
076        private Field m_field;
077
078        /**
079         * Constructor.<p>
080         *
081         * @param field the field to validate
082         */
083        public FieldValidator(Field field) {
084
085            super(null);
086            m_field = field;
087        }
088
089        /**
090         * @see com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object)
091         */
092        @SuppressWarnings("incomplete-switch")
093        @Override
094        protected boolean isValidValue(String value) {
095
096            boolean result = true;
097
098            try {
099                switch (m_field) {
100                    case email:
101                        OpenCms.getValidationHandler().checkEmail(value);
102                        break;
103                    case firstname:
104                        OpenCms.getValidationHandler().checkFirstname(value);
105                        break;
106                    case lastname:
107                        OpenCms.getValidationHandler().checkLastname(value);
108                        break;
109                    case zipcode:
110                        OpenCms.getValidationHandler().checkZipCode(value);
111                        break;
112
113                }
114            } catch (CmsIllegalArgumentException e) {
115                result = false;
116                setErrorMessage(e.getLocalizedMessage(UI.getCurrent().getLocale()));
117            }
118
119            return result;
120        }
121    }
122
123    /** Logger instance for this class. */
124    private static final Log LOG = CmsLog.getLog(CmsUserDataFormLayout.class);
125
126    /**Vaadin serial id.*/
127    private static final long serialVersionUID = 4893705558720239863L;
128
129    /** The field binder. */
130    private FieldGroup m_binder;
131
132    private EditLevel m_editLevel;
133
134    /** The property item. */
135    private PropertysetItem m_infos;
136
137    /**
138     * empty constructor.<p>
139     */
140    public CmsUserDataFormLayout() {
141
142    }
143
144    /**
145     * Initializes available fields for given user.<p>
146     *
147     * @param user CmsUser to display fields for
148     */
149    public void initFields(CmsUser user) {
150
151        initFields(user, EditLevel.configured);
152    }
153
154    public void initFields(CmsUser user, EditLevel editLevel) {
155
156        m_editLevel = editLevel;
157        m_infos = new PropertysetItem();
158        for (CmsAccountInfo info : OpenCms.getWorkplaceManager().getAccountInfos()) {
159            String value = "";
160            if (user != null) {
161                value = info.getValue(user);
162                if (value == null) {
163                    value = "";
164                }
165            }
166            m_infos.addItemProperty(info, new ObjectProperty<String>(value));
167        }
168
169        m_binder = new FieldGroup(m_infos);
170        for (CmsAccountInfo info : OpenCms.getWorkplaceManager().getAccountInfos()) {
171            addComponent(buildField(getLabel(info), info));
172        }
173    }
174
175    /**
176     * Returns whether the form fields are valid.<p>
177     *
178     * @return <code>true</code> if the form fields are valid
179     */
180    public boolean isValid() {
181
182        boolean valid = true;
183        for (Component comp : this) {
184            if (comp instanceof TextField) {
185                valid = valid && ((TextField)comp).isValid();
186            }
187        }
188        return valid;
189    }
190
191    /**
192     * Store fields to given user.<p>
193     *
194     * @param user User to write information to
195     * @param cms CmsObject
196     * @param afterWrite runnable which gets called after writing user
197     */
198    public void submit(CmsUser user, CmsObject cms, Runnable afterWrite) {
199
200        submit(user, cms, afterWrite, false);
201    }
202
203    /**
204     * Store fields to given user.<p>
205     *
206     * @param user User to write information to
207     * @param cms CmsObject
208     * @param afterWrite runnable which gets called after writing user
209     * @param force force write even if data are not valid
210     */
211    public void submit(CmsUser user, CmsObject cms, Runnable afterWrite, boolean force) {
212
213        try {
214            if (isValid() | force) {
215                if (force) {
216                    removeValidators();
217                }
218                m_binder.commit();
219                PropertyUtilsBean propUtils = new PropertyUtilsBean();
220                for (CmsAccountInfo info : OpenCms.getWorkplaceManager().getAccountInfos()) {
221                    boolean editable = (m_editLevel == EditLevel.all)
222                        || ((m_editLevel == EditLevel.configured) && info.isEditable());
223                    if (editable) {
224                        if (info.isAdditionalInfo()) {
225                            user.setAdditionalInfo(info.getAddInfoKey(), m_infos.getItemProperty(info).getValue());
226                        } else {
227                            String valueToSet = (String)m_infos.getItemProperty(info).getValue();
228                            if (CmsStringUtil.isEmptyOrWhitespaceOnly(valueToSet)) {
229                                valueToSet = null;
230                            }
231                            propUtils.setProperty(user, info.getField().name(), valueToSet);
232                        }
233                    }
234                }
235                cms.writeUser(user);
236                afterWrite.run();
237            }
238        } catch (CmsException | CommitException | IllegalAccessException | InvocationTargetException
239        | NoSuchMethodException e) {
240            LOG.error("Unable to commit changes to user..", e);
241        }
242    }
243
244    /**
245     * Builds the text field for the given property.<p>
246     *
247     * @param label the field label
248     * @param info the property name
249     *
250     * @return the field
251     */
252    private TextField buildField(String label, CmsAccountInfo info) {
253
254        TextField field = (TextField)m_binder.buildAndBind(label, info);
255        field.setConverter(new CmsNullToEmptyConverter());
256        field.setWidth("100%");
257        boolean editable = (m_editLevel == EditLevel.all)
258            || (info.isEditable() && (m_editLevel == EditLevel.configured));
259        field.setEnabled(editable);
260        if (editable) {
261            field.addValidator(new FieldValidator(info.getField()));
262        }
263        field.setImmediate(true);
264        return field;
265    }
266
267    /**
268     * Returns the field label.<p>
269     *
270     * @param info the info
271     *
272     * @return the label
273     */
274    private String getLabel(CmsAccountInfo info) {
275
276        if (info.isAdditionalInfo()) {
277            String label = CmsVaadinUtils.getMessageText("GUI_USER_DATA_" + info.getAddInfoKey().toUpperCase() + "_0");
278            if (CmsMessages.isUnknownKey(label)) {
279                return info.getAddInfoKey();
280            } else {
281                return label;
282            }
283        } else {
284            return CmsVaadinUtils.getMessageText("GUI_USER_DATA_" + info.getField().name().toUpperCase() + "_0");
285        }
286    }
287
288    /**
289     * Removes all validators.<p>
290     */
291    private void removeValidators() {
292
293        for (Component comp : this) {
294            ((TextField)comp).removeAllValidators();
295        }
296    }
297
298}