Project

General

Profile

Download (12.8 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.vaadin.component.common;
10

    
11
import java.util.EnumSet;
12
import java.util.List;
13
import java.util.regex.Pattern;
14

    
15
import org.vaadin.teemu.switchui.Switch;
16
import org.vaadin.viritin.fields.LazyComboBox;
17

    
18
import com.vaadin.data.Validator.InvalidValueException;
19
import com.vaadin.data.fieldgroup.BeanFieldGroup;
20
import com.vaadin.data.fieldgroup.FieldGroup;
21
import com.vaadin.server.FontAwesome;
22
import com.vaadin.ui.Button;
23
import com.vaadin.ui.Component;
24
import com.vaadin.ui.CssLayout;
25
import com.vaadin.ui.Field;
26
import com.vaadin.ui.TextField;
27
import com.vaadin.ui.themes.ValoTheme;
28

    
29
import eu.etaxonomy.cdm.model.agent.Person;
30
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
31
import eu.etaxonomy.cdm.service.UserHelperAccess;
32
import eu.etaxonomy.cdm.vaadin.component.ButtonFactory;
33
import eu.etaxonomy.cdm.vaadin.component.TextFieldNFix;
34
import eu.etaxonomy.vaadin.component.CompositeCustomField;
35
import eu.etaxonomy.vaadin.component.SwitchButton;
36

    
37
/**
38
 * @author a.kohlbecker
39
 * @since May 11, 2017
40
 *
41
 */
42
public class PersonField extends CompositeCustomField<Person> {
43

    
44
    private static final long serialVersionUID = 8346575511284469356L;
45

    
46
    private static final String PRIMARY_STYLE = "v-person-field";
47

    
48
    private static final Pattern EMPTY_ENTITY_TITLE_CACHE_PATTERN = Pattern.compile("[a-zA-Z]+#[0-9]+<[a-f0-9\\-]+>");
49

    
50
    /**
51
     * do not allow entities which are having only <code>null</code> values in all fields
52
     * {@link #getValue()} would return <code>null</code> in this case.
53
     */
54
    boolean allowNewEmptyEntity = true;
55

    
56
    private LazyComboBox<Person> personSelect = new LazyComboBox<Person>(Person.class);
57

    
58
    private Button newPersonButton = ButtonFactory.CREATE_NEW.createButton();
59

    
60
    private BeanFieldGroup<Person> fieldGroup = new BeanFieldGroup<>(Person.class);
61

    
62
    enum Mode {
63
        CACHE_MODE, DETAILS_MODE;
64

    
65
        public String toCssClass() {
66
            return name().toLowerCase().replace("_", "-");
67
        }
68
    }
69

    
70
    private Mode currentMode = null;
71

    
72
    private float baseWidth = 100 / 9;
73

    
74
    private CssLayout root = new CssLayout();
75
    private CssLayout selectOrNewContainer = new CssLayout();
76

    
77
    private TextField titleCacheField = new TextFieldNFix();
78
    private TextField nomenclaturalTitleField = new TextFieldNFix();
79
    private Button nomenclaturalTitleButton = new Button();
80
    private CssLayout detailsContainer = new CssLayout();
81
    private TextField initialsField = new TextFieldNFix();
82
    private TextField givenNameField = new TextFieldNFix();
83
    private TextField familyNameField = new TextFieldNFix();
84
    private TextField prefixField = new TextFieldNFix();
85
    private TextField suffixField = new TextFieldNFix();
86
    private SwitchButton unlockSwitch = new SwitchButton();
87

    
88

    
89
    /**
90
     * @param caption
91
     */
92
    public PersonField(String caption) {
93

    
94
        this();
95
        setCaption(caption);
96
    }
97

    
98
    /**
99
     * @param caption
100
     */
101
    public PersonField() {
102

    
103
        root.setPrimaryStyleName(PRIMARY_STYLE);
104

    
105
        // select existing or create new person
106
        addStyledComponents(personSelect, newPersonButton);
107
        personSelect.addValueChangeListener(e -> {
108
            if(personSelect.getValue() != null){
109
                setValue(personSelect.getValue());
110
                personSelect.clear();
111
            }
112
        });
113

    
114
        selectOrNewContainer.addComponents(personSelect, newPersonButton);
115
        newPersonButton.addClickListener(e -> createNewPerson());
116

    
117
        // edit person
118
        addStyledComponent(titleCacheField);
119
        addStyledComponents(initialsField);
120
        addStyledComponent(givenNameField);
121
        addStyledComponent(familyNameField);
122
        addStyledComponent(prefixField);
123
        addStyledComponent(suffixField);
124
        addStyledComponent(unlockSwitch);
125
        addStyledComponent(nomenclaturalTitleField);
126
        addStyledComponent(nomenclaturalTitleButton);
127

    
128
        addSizedComponent(root);
129
    }
130

    
131
    /**
132
     *
133
     */
134
    private void checkUserPermissions(Person newValue) {
135
        boolean userCanEdit = newValue == null || !newValue.isPersited() || UserHelperAccess.userHelper().userHasPermission(newValue, "DELETE", "UPDATE");
136
        setEnabled(userCanEdit);
137
    }
138

    
139
    private void setMode(Mode mode){
140
        if(mode.equals(currentMode)){
141
            return;
142
        }
143
        if(currentMode != null){
144
            String removeMode = currentMode.toCssClass();
145
            root.removeStyleName(removeMode);
146
        }
147
        String newMode = mode.toCssClass();
148
        root.addStyleName(newMode);
149
        currentMode = mode;
150
    }
151

    
152

    
153
    /**
154
     * {@inheritDoc}
155
     */
156
    @Override
157
    protected Component initContent() {
158

    
159
        selectOrNewContainer.setWidth(100, Unit.PERCENTAGE);
160
        personSelect.setWidthUndefined();
161

    
162
        root.addComponent(titleCacheField);
163
        root.addComponent(unlockSwitch);
164
        root.addComponent(selectOrNewContainer);
165

    
166
        titleCacheField.setWidth(100, Unit.PERCENTAGE);
167

    
168
        prefixField.setWidth(baseWidth, Unit.PERCENTAGE);
169
        prefixField.setInputPrompt("Prefix");
170

    
171
        initialsField.setWidth(baseWidth, Unit.PERCENTAGE);
172
        initialsField.setInputPrompt("Initials");
173

    
174
        givenNameField.setWidth(baseWidth * 3, Unit.PERCENTAGE);
175
        givenNameField.setInputPrompt("Other/given names");
176

    
177
        familyNameField.setWidth(baseWidth * 3, Unit.PERCENTAGE);
178
        familyNameField.setInputPrompt("Family name");
179

    
180
        suffixField.setWidth(baseWidth, Unit.PERCENTAGE);
181
        suffixField.setInputPrompt("Suffix");
182

    
183
        detailsContainer.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
184
        detailsContainer.addComponent(prefixField);
185
        detailsContainer.addComponent(initialsField);
186
        detailsContainer.addComponent(givenNameField);
187
        detailsContainer.addComponent(familyNameField);
188
        detailsContainer.addComponent(suffixField);
189
        root.addComponent(detailsContainer);
190

    
191
        nomenclaturalTitleButton.setHeight(22, Unit.PIXELS);
192
        nomenclaturalTitleButton.setDescription("Show the nomenclatural title cache.");
193
        nomenclaturalTitleButton.addClickListener( e -> {
194
            nomenclaturalTitleField.setVisible(!nomenclaturalTitleField.isVisible());
195
            nomenclaturalTitleButtonChooseIcon();
196
            if(nomenclaturalTitleField.isVisible()){
197
                nomenclaturalTitleField.focus();
198
            }
199
        });
200
        // nomenclaturalTitleField.setCaption("Nomenclatural title");
201
        nomenclaturalTitleField.setWidth(100, Unit.PERCENTAGE);
202
//        nomenclaturalTitleField.addValueChangeListener( e -> {
203
//            if(e.getProperty().getValue() != null && ((String)e.getProperty().getValue()).isEmpty()){
204
//
205
//            }
206
//        });
207

    
208
        root.addComponent(nomenclaturalTitleField);
209
        root.addComponent(nomenclaturalTitleButton);
210

    
211
        unlockSwitch.addValueChangeListener(e -> {
212
            if(refreshMode()){
213
                switch (currentMode) {
214
                    case CACHE_MODE:
215
                        titleCacheField.focus();
216
                        break;
217
                    case DETAILS_MODE:
218
                        givenNameField.focus();
219
                        break;
220
                    default:
221
                        break;
222

    
223
                }
224
            }
225
        });
226
        unlockSwitch.setValueSetLister(e -> {
227
            refreshMode();
228
        });
229

    
230
        addDefaultStyles();
231
        setMode(Mode.DETAILS_MODE);
232

    
233
        fieldGroup.bind(titleCacheField, "titleCache");
234
        fieldGroup.bind(prefixField, "prefix");
235
        fieldGroup.bind(initialsField, "initials");
236
        fieldGroup.bind(givenNameField, "givenName");
237
        fieldGroup.bind(familyNameField, "familyName");
238
        fieldGroup.bind(suffixField, "suffix");
239
        fieldGroup.bind(unlockSwitch, "protectedTitleCache");
240
        fieldGroup.bind(nomenclaturalTitleField, "nomenclaturalTitle");
241
        fieldGroup.setBuffered(false);
242

    
243
        updateVisibilities(getValue());
244

    
245
        return root;
246
    }
247

    
248
    /**
249
     *
250
     */
251
    protected void nomenclaturalTitleButtonChooseIcon() {
252
        nomenclaturalTitleButton.setIcon(nomenclaturalTitleField.isVisible() ? FontAwesome.ANGLE_UP : FontAwesome.ELLIPSIS_H);
253
    }
254

    
255
    /**
256
     *
257
     * @return true if the mode has changed
258
     */
259
    protected boolean refreshMode() {
260
        Mode lastMode = currentMode;
261
        setMode(unlockSwitch.getValue() ? Mode.CACHE_MODE: Mode.DETAILS_MODE);
262
        return !lastMode.equals(currentMode);
263
    }
264

    
265
    /**
266
     * {@inheritDoc}
267
     */
268
    @Override
269
    public Class<? extends Person> getType() {
270
        return Person.class;
271
    }
272

    
273
    private void createNewPerson(){
274
        Person p = Person.NewInstance();
275
        setValue(p);
276
    }
277

    
278
    @Override
279
    public void setValue(Person person){
280
        super.setValue(person);
281
        if(person != null && person.getId() != 0){
282
            personSelect.setValue(person);
283
        }
284
    }
285

    
286
    /**
287
     * {@inheritDoc}
288
     */
289
    @Override
290
    protected void setInternalValue(Person newValue) {
291

    
292
        super.setInternalValue(newValue);
293
        fieldGroup.setItemDataSource(newValue);
294
        checkUserPermissions(newValue);
295
        updateVisibilities(newValue);
296
    }
297

    
298
    /**
299
     *
300
     */
301
    private void updateVisibilities(Person person) {
302

    
303
        selectOrNewContainer.setVisible(person == null);
304

    
305
        detailsContainer.setVisible(person != null);
306
        unlockSwitch.setVisible(person != null);
307
        titleCacheField.setVisible(person != null);
308
        String nomTitle = nomenclaturalTitleField.getValue();
309
        boolean isEmptyItemTitle = nomTitle == null || EMPTY_ENTITY_TITLE_CACHE_PATTERN.matcher(nomTitle).matches();
310
        boolean nomTitleEqualsTitleCache = nomTitle != null && nomTitle.equals(titleCacheField.getValue());
311
        nomenclaturalTitleField.setVisible( !isEmptyItemTitle && !nomTitleEqualsTitleCache);
312
        nomenclaturalTitleButtonChooseIcon();
313

    
314
    }
315

    
316
    @Override
317
    protected void addDefaultStyles(){
318
        titleCacheField.addStyleName("cache-field");
319
        detailsContainer.addStyleName("details-fields");
320
        unlockSwitch.addStyleName(Switch.DOM_STYLE);
321
        nomenclaturalTitleButton.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED + " center-h");
322
    }
323

    
324
    /**
325
     * {@inheritDoc}
326
     */
327
    @Override
328
    public FieldGroup getFieldGroup() {
329
        return fieldGroup;
330
    }
331

    
332

    
333
    /**
334
     * {@inheritDoc}
335
     */
336
    @Override
337
    protected List<Field> nullValueCheckIgnoreFields() {
338

    
339
        List<Field>ignoreFields = super.nullValueCheckIgnoreFields();
340
        ignoreFields.add(unlockSwitch);
341

    
342
        if(unlockSwitch.getValue().booleanValue() == false){
343
            Person value = getValue();
344
            if(value != null && value.getId() == 0){
345
                // only if the entity is unsaved!
346
                ignoreFields.add(titleCacheField);
347
                titleCacheField.setValue(null);
348
            }
349
        }
350
        return ignoreFields;
351
    }
352

    
353
    /**
354
     * {@inheritDoc}
355
     */
356
    @Override
357
    public void commit() throws SourceException, InvalidValueException {
358

    
359
        super.commit();
360

    
361
        Person bean =  getValue();
362

    
363
        if(bean != null){
364
            String nomTitle = nomenclaturalTitleField.getValue();
365
            if(nomTitle != null && nomTitle.equals(titleCacheField.getValue())){
366
                // no point having a nomenclaturalTitle if it is equal to the titleCache
367
                bean.setNomenclaturalTitle(null);
368
            }
369
            boolean isUnsaved = bean.getId() == 0;
370
            if(isUnsaved && !(hasNullContent() && !allowNewEmptyEntity)){
371
                UserHelperAccess.userHelper().createAuthorityForCurrentUser(bean, EnumSet.of(CRUD.UPDATE, CRUD.DELETE), null);
372
            }
373
        }
374
    }
375

    
376
    /**
377
     * {@inheritDoc}
378
     *
379
     * @return returns <code>null</code> in case the edited entity is unsaved and if
380
     * it only has null values.
381
     */
382
    @Override
383
    public Person getValue() {
384
        Person bean = super.getValue();
385
        if(bean == null){
386
            return null;
387
        }
388
        return bean;
389
    }
390

    
391
    /**
392
     * @return the personSelect
393
     */
394
    public LazyComboBox<Person> getPersonSelect() {
395
        return personSelect;
396
    }
397

    
398
    /**
399
     * @param personSelect the personSelect to set
400
     */
401
    public void setPersonSelect(LazyComboBox<Person> personSelect) {
402
        this.personSelect = personSelect;
403
    }
404

    
405
    /**
406
     * @return the allowNewEmptyEntity
407
     */
408
    public boolean isAllowNewEmptyEntity() {
409
        return allowNewEmptyEntity;
410
    }
411

    
412
    /**
413
     * @param allowNewEmptyEntity the allowNewEmptyEntity to set
414
     */
415
    public void setAllowNewEmptyEntity(boolean allowNewEmptyEntity) {
416
        this.allowNewEmptyEntity = allowNewEmptyEntity;
417
    }
418

    
419

    
420

    
421
}
(5-5/8)