Project

General

Profile

Download (8.69 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.vaadin.component;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.List;
15

    
16
import com.vaadin.data.fieldgroup.FieldGroup;
17
import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
18
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
19
import com.vaadin.data.fieldgroup.FieldGroup.CommitHandler;
20
import com.vaadin.ui.AbstractField;
21
import com.vaadin.ui.Button;
22
import com.vaadin.ui.Component;
23
import com.vaadin.ui.CustomField;
24
import com.vaadin.ui.Field;
25
import com.vaadin.ui.HasComponents;
26

    
27
import eu.etaxonomy.cdm.vaadin.event.NestedButtonStateUpdater;
28

    
29
/**
30
 * TODO implement height methods for full component size support
31
 *
32
 * @author a.kohlbecker
33
 * @since May 12, 2017
34
 *
35
 * IMPORTANT see also {@link CompositeStyledComponent} which has almost the same functionality.
36
 *
37
 */
38
@SuppressWarnings("serial")
39
public abstract class CompositeCustomField<T> extends CustomField<T> implements NestedFieldGroup {
40

    
41
    protected static final String READ_ONLY_CAPTION_SUFFIX = " (read only)";
42

    
43
    private List<Component> styledComponents = new ArrayList<>();
44

    
45
    private List<Component> sizedComponents = new ArrayList<>();
46

    
47
    private CommitHandler commitHandler = new CommitHandler() {
48

    
49
        @Override
50
        public void preCommit(CommitEvent commitEvent) throws CommitException {
51
            // commit the nested bean(s) first
52
            if(getFieldGroup() != null){
53
                getFieldGroup().commit();
54
            }
55
        }
56

    
57
        @Override
58
        public void postCommit(CommitEvent commitEvent) throws CommitException {
59
            // noting to do
60
        }};
61

    
62
    protected List<Component> getStyledComponents() {
63
        if(styledComponents == null){
64
            styledComponents = new ArrayList<>();
65
        }
66
        return styledComponents;
67
    }
68

    
69
    /**
70
     * Implementations preferably call this method in the constructor
71
     *
72
     * @param component
73
     * @return
74
     */
75
    protected boolean addStyledComponent(Component component){
76
        applyCurrentStyleNames(component);
77
        return styledComponents.add(component);
78
    }
79

    
80
    /**
81
     * Implementations preferably call this method in the constructor
82
     *
83
     * @param component
84
     * @return
85
     */
86
    protected boolean addStyledComponents(Component ... component){
87
        List<Component> componentList = Arrays.asList(component);
88
        componentList.forEach(c -> applyCurrentStyleNames(c));
89
        return styledComponents.addAll(componentList);
90
    }
91

    
92
    protected List<Component> getSizedComponents() {
93
        if(sizedComponents == null){
94
            sizedComponents = new ArrayList<>();
95
        }
96
        return sizedComponents;
97
    }
98

    
99
    /**
100
     * Implementations preferably call this method in the constructor
101
     *
102
     * @param component
103
     * @return
104
     */
105
    protected boolean addSizedComponent(Component component){
106
        applyCurrentSize(component);
107
        return sizedComponents.add(component);
108
    }
109

    
110
    /**
111
     * Implementations preferably call this method in the constructor
112
     *
113
     * @param component
114
     * @return
115
     */
116
    protected boolean addSizedComponents(Component ... component){
117
        List<Component> componentList = Arrays.asList(component);
118
        componentList.forEach(c -> applyCurrentSize(c));
119
        return sizedComponents.addAll(componentList);
120
    }
121

    
122
    @Override
123
    public void setWidth(String width) {
124
        super.setWidth(width);
125
        getSizedComponents().forEach(c -> {if(c != null) {c.setWidth(width);}});
126
    }
127

    
128
    @Override
129
    public void setWidth(float width, Unit unit){
130
        super.setWidth(width, unit);
131
        getSizedComponents().forEach(c -> {if(c != null) {c.setWidth(width, unit);}});
132
    }
133

    
134
    @Override
135
    public void setWidthUndefined() {
136
        super.setWidthUndefined();
137
        getSizedComponents().forEach(c -> {if(c != null) {c.setWidthUndefined();}});
138
    }
139

    
140
    @Override
141
    public void setStyleName(String style) {
142
        super.setStyleName(style);
143
        getStyledComponents().forEach(c -> c.setStyleName(style));
144
        addDefaultStyles();
145
    }
146

    
147
    @Override
148
    public void addStyleName(String style) {
149
        super.addStyleName(style);
150
        getStyledComponents().forEach(c -> c.addStyleName(style));
151
    }
152

    
153
    protected void applyCurrentStyleNames(Component newSubComponent){
154
        newSubComponent.setStyleName(getStyleName());
155
    }
156

    
157
    protected void applyCurrentSize(Component newSubComponent){
158
        newSubComponent.setWidth(this.getWidth(), this.getWidthUnits());
159
    }
160

    
161
    /**
162
     * Implementations can may apply default styles to components added to <code>StyledComponents</code>
163
     * to prevent these styles from being overwritten when setStyleName() id called on the composite field.
164
     */
165
    protected abstract void addDefaultStyles();
166

    
167
    /**
168
     * Implementations return the local fieldGroup
169
     *
170
     * @return
171
     */
172
    @Override
173
    public abstract FieldGroup getFieldGroup();
174

    
175
    /**
176
     * @return true if all fields having the value <code>null</code>
177
     */
178
    @SuppressWarnings("rawtypes")
179
    public boolean hasNullContent() {
180
        Collection<Field> nullValueCheckIgnore = nullValueCheckIgnoreFields();
181
        return getFieldGroup().getFields().stream()
182
                .filter(
183
                        f -> !nullValueCheckIgnore.contains(f)
184
                )
185
                //.peek( f -> System.out.println("###> " + f.getCaption() + ": " + f.getValue()))
186
                .allMatch(
187
                        f -> {
188
                            if(f instanceof CompositeCustomField){
189
                                return ((CompositeCustomField)f).hasNullContent();
190
                            } else {
191
                                if(f.getValue() == null) {
192
                                    return true;
193
                                } else {
194
                                    return false;
195
                                }
196
                            }
197
                        }
198
                );
199
    }
200

    
201
    /**
202
     * @return
203
     */
204
    protected List<Field> nullValueCheckIgnoreFields() {
205
        // TODO Auto-generated method stub
206
        return new ArrayList<Field>(0);
207
    }
208

    
209
    @Override
210
    public void registerParentFieldGroup(FieldGroup parent) {
211
        parent.addCommitHandler(commitHandler);
212
    }
213

    
214
    @Override
215
    public void unregisterParentFieldGroup(FieldGroup parent) {
216
        parent.removeCommitHandler(commitHandler);
217
    }
218

    
219
    /**
220
     * @param readOnly
221
     */
222
    protected void setDeepReadOnly(boolean readOnly, Component component, Collection<Component> ignore) {
223

    
224
        if(ignore != null && ignore.contains(component)){
225
            return;
226
        }
227

    
228
        applyReadOnlyState(component, readOnly);
229
        if(HasComponents.class.isAssignableFrom(component.getClass())){
230
            for(Component nestedComponent : ((HasComponents)component)){
231
                setDeepReadOnly(readOnly, nestedComponent, ignore);
232
            }
233
        }
234
    }
235

    
236
    /**
237
     * Sets the readonly state for the component but treats Buttons differently.
238
     * For nested Buttons the readonly state is projected to enabled state to
239
     * make them inactive. Finally NestedButtonStateUpdaters are triggered to
240
     * allow to disable buttons accordingly to user permissions.
241
     *
242
     * @param readOnly
243
     * @param component
244
     */
245
    protected void applyReadOnlyState(Component component, boolean readOnly) {
246
        component.setReadOnly(readOnly);
247
        if(Button.class.isAssignableFrom(component.getClass())){
248
            component.setEnabled(!readOnly);
249
        }
250
        triggerNestedButtonStateUpdaters();
251
    }
252

    
253
    /**
254
     *
255
     */
256
    protected void triggerNestedButtonStateUpdaters() {
257
        for(Object l : getListeners(AbstractField.ValueChangeEvent.class)){
258
           if(NestedButtonStateUpdater.class.isAssignableFrom(l.getClass())){
259
               // trigger a fake ValueChangeEvent to let the ToOneRelatedEntityButtonUpdater fix the states
260
               // of nested buttons
261
               ((NestedButtonStateUpdater)l).valueChange(new AbstractField.ValueChangeEvent(this));
262
           }
263
        }
264

    
265
    }
266

    
267
    @Override
268
    public String toString(){
269
        return this.getClass().getSimpleName() + ": " +
270
                ( getValue() != null ? getValue() : "null");
271
    }
272

    
273
    protected void updateCaptionReadonlyNotice(boolean readOnly) {
274
        if(readOnly){
275
            setCaption(getCaption() + READ_ONLY_CAPTION_SUFFIX);
276
        } else {
277
            setCaption(getCaption().replace(READ_ONLY_CAPTION_SUFFIX, ""));
278
        }
279
    }
280

    
281
}
(1-1/17)