Project

General

Profile

« Previous | Next » 

Revision d3be16a7

Added by Andreas Kohlbecker almost 7 years ago

ref #6169 add, remove, move buttons in ToManyRelatedEntitiesListSelect operational and with correct state

View differences:

src/main/java/eu/etaxonomy/vaadin/component/ToManyRelatedEntitiesListSelect.java
9 9
package eu.etaxonomy.vaadin.component;
10 10

  
11 11
import java.util.ArrayList;
12
import java.util.HashSet;
12
import java.util.Collections;
13
import java.util.LinkedList;
13 14
import java.util.List;
14
import java.util.Set;
15 15

  
16 16
import org.apache.log4j.Logger;
17 17

  
......
30 30
import eu.etaxonomy.vaadin.mvp.AbstractCdmEditorPresenter;
31 31

  
32 32
/**
33
 * Manages the a collection of items internally as LinkedList<V>. If the Collection to operate on is a Set a Converter must be
34
 * set. THe internally used fields are used in un-buffered mode.
35
 *
33 36
 * @author a.kohlbecker
34 37
 * @since May 11, 2017
35 38
 *
......
50 53

  
51 54
    private boolean withEditButton = false;
52 55

  
56
    private static final int GRID_X_FIELD = 0;
57

  
58
    protected boolean addEmptyRowOnInitContent = true;
59

  
53 60
    //NOTE: Managing the item
54 61
    //      IDs makes BeanContainer more complex to use, but it is necessary in some cases where the
55
    //      equals() or hashCode() methods have been reimplemented in the bean.
56
    //      TODO CdmBase has a reimplemented equals method, do we need to use the BeanContainer instead?
62
    //      equals() or hashCode() methods have been re-implemented in the bean.
63
    //      TODO CdmBase has a re-implemented equals method, do we need to use the BeanContainer instead?
57 64
    private BeanItemContainer<V> beans;
58 65

  
59 66
   //private LinkedList<V> itemList = new LinkedList<>();
60 67

  
61 68
    private int GRID_COLS = 2;
62 69

  
63
    private GridLayout grid = new GridLayout(GRID_COLS,1);
64

  
65
    private Set<F> nestedFields = new HashSet<>() ;
70
    private GridLayout grid = new GridLayout(GRID_COLS, 1);
66 71

  
67 72
    public  ToManyRelatedEntitiesListSelect(Class<V> itemType, Class<F> fieldType, String caption){
68 73
        this.fieldType = fieldType;
69 74
        this.itemType = itemType;
70 75
        setCaption(caption);
71 76
        beans = new BeanItemContainer<V>(itemType);
72
    }
73 77

  
74
    private Component buttonGroup(F field){
75

  
76
        CssLayout buttonGroup = new CssLayout();
77
        Button add = new Button(FontAwesome.PLUS);
78
        ClickListener addclickListerner = newRemoveButtonClicklistener(field);
79
        if(addclickListerner != null){
80
            add.addClickListener(addclickListerner);
81
        }
78
    }
82 79

  
83
        if(withEditButton){
84
            Button edit = new Button(FontAwesome.EDIT);
85
            ClickListener editClickListerner = newEditButtonClicklistener(field);
86
            if(editClickListerner != null){
87
                edit.addClickListener(editClickListerner);
80
    /**
81
     * @param field
82
     * @return
83
     */
84
    protected Integer findRow(F field) {
85
        Integer row = null;
86
        for(int r = 0; r < grid.getRows(); r++){
87
            if(grid.getComponent(GRID_X_FIELD, r).equals(field)){
88
                row = r;
89
                break;
88 90
            }
89
            buttonGroup.addComponent(edit);
90
            addStyledComponents(edit);
91 91
        }
92
        return row;
93
    }
92 94

  
93
        Button remove = new Button(FontAwesome.MINUS);
94
        ClickListener removeclickListerner = newRemoveButtonClicklistener(field);
95
        if(removeclickListerner != null){
96
            remove.addClickListener(removeclickListerner);
97
        }
95
    /**
96
     * @param field
97
     * @return
98
     */
99
    private void addRowAfter(F field) {
98 100

  
99
        buttonGroup.addComponent(add);
100
        buttonGroup.addComponent(remove);
101
        addStyledComponents(add, remove);
102
        if(isOrderedCollection){
103
            Button moveUp = new Button(FontAwesome.ARROW_UP);
104
            Button moveDown = new Button(FontAwesome.ARROW_DOWN);
105
            buttonGroup.addComponents(moveUp, moveDown);
106
            addStyledComponents(moveUp, moveDown);
101
        Integer row = findRow(field);
102

  
103
        grid.insertRow(row + 1);
104

  
105
        addNewRow(row + 1, null);
106
        updateValue();
107

  
108
    }
109

  
110
    /**
111
     * @param field
112
     * @return
113
     */
114
    private void removeRow(F field) {
115

  
116
        Integer row = findRow(field);
117
        grid.removeRow(row);
118
        updateValue();
119
        updateButtonStates();
120

  
121
    }
122

  
123
    /**
124
     * @param field
125
     * @return
126
     */
127
    private void moveRowDown(F field) {
128

  
129
        Integer row = findRow(field);
130
        swapRows(row);
131
    }
132

  
133
    /**
134
     * @param field
135
     * @return
136
     */
137
    private void moveRowUp(F field) {
138

  
139
        Integer row = findRow(field);
140
        swapRows(row - 1);
141
    }
142

  
143
    /**
144
     * @param i
145
     */
146
    private void swapRows(int i) {
147
        if(i >= 0 && i + 1 < grid.getRows()){
148
            grid.replaceComponent(grid.getComponent(GRID_X_FIELD, i), grid.getComponent(GRID_X_FIELD, i + 1));
149
            grid.replaceComponent(grid.getComponent(GRID_X_FIELD  + 1 , i), grid.getComponent(GRID_X_FIELD + 1, i + 1));
150
            updateButtonStates();
151
            updateValue();
152
        } else {
153
            throw new RuntimeException("Cannot swap rows out of the grid bounds");
107 154
        }
108
        buttonGroup.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
155
    }
109 156

  
110
        return buttonGroup;
157
    /**
158
     *
159
     */
160
    protected void updateValue() {
161
        try {
162
            setValue(getValueFromNestedFields());
163
        } catch (ReadOnlyException e){
164
            logger.debug("datasource is readonly, only internal value was updated");
165
        }
111 166
    }
112 167

  
113 168
    /**
......
138 193
    @Override
139 194
    protected Component initContent() {
140 195
        grid.setColumnExpandRatio(0, 1.0f);
196
        // set internal value to null to add an empty row
197

  
198
        if(addEmptyRowOnInitContent){
199
            // add an empty row
200
            setInternalValue(null);
201
        }
141 202
        return grid;
142 203
    }
143 204

  
......
154 215
     */
155 216
    @Override
156 217
    protected void setInternalValue(List<V> newValue) {
157
        super.setInternalValue(newValue);
158 218

  
159
        // newValue is already converted, need to use the original value from the data source
160
        isOrderedCollection = List.class.isAssignableFrom(getPropertyDataSource().getValue().getClass());
219
         grid.removeAllComponents();
220
         grid.setRows(1);
221

  
222
        if(newValue != null){
223
            // FIMXE is it really needed to backup as linked list?
224
            LinkedList<V> linkedList;
225
            if(newValue instanceof LinkedList){
226
                linkedList = (LinkedList<V>) newValue;
227
            } else {
228
                linkedList = new LinkedList<>(newValue);
229
            }
230
            super.setInternalValue(linkedList);
231

  
232
            // newValue is already converted, need to use the original value from the data source
233
            isOrderedCollection = List.class.isAssignableFrom(getPropertyDataSource().getValue().getClass());
161 234

  
162
        beans.addAll(newValue);
235
            //FIXME is beans really used?
236
            beans.addAll(linkedList);
163 237

  
164
        grid.setRows(newValue.size());
165
        int row = 0;
166
        for(V val : newValue){
167
            row = addNewRow(row, val);
238
            int row = 0;
239
            if(newValue.size() > 0){
240
                for(V val : linkedList){
241
                    row = addNewRow(row, val);
242
                }
243
            }
244
        }
245

  
246
        if(newValue == null || newValue.isEmpty()) {
247
            // add an empty row
248
            addNewRow(0, null);
168 249
        }
169 250
    }
170 251

  
......
176 257
    protected int addNewRow(int row, V val) {
177 258
        try {
178 259
            F field = newFieldInstance(val);
179
            nestedFields .add(field);
180 260
            addStyledComponent(field);
181
            grid.addComponent(field, 0, row);
261

  
262
            // important! all fields must be un-buffered
263
            field.setBuffered(false);
264

  
265
            if(getNestedFields().size() == grid.getRows()){
266
                grid.setRows(grid.getRows() + 1);
267
            }
268
            grid.addComponent(field, GRID_X_FIELD, row);
182 269
            grid.addComponent(buttonGroup(field), 1, row);
270
            updateButtonStates();
183 271
            nestFieldGroup(field);
184 272
            row++;
185 273
        } catch (InstantiationException e) {
......
192 280
        return row;
193 281
    }
194 282

  
283
    private Component buttonGroup(F field){
284

  
285
        CssLayout buttonGroup = new CssLayout();
286
        Button add = new Button(FontAwesome.PLUS);
287
        add.addClickListener(e -> addRowAfter(field));
288

  
289
        if(withEditButton){
290
            Button edit = new Button(FontAwesome.EDIT);
291
            ClickListener editClickListerner = newEditButtonClicklistener(field);
292
            if(editClickListerner != null){
293
                edit.addClickListener(editClickListerner);
294
            }
295
            buttonGroup.addComponent(edit);
296
            addStyledComponents(edit);
297
        }
298

  
299
        Button remove = new Button(FontAwesome.MINUS);
300
        remove.addClickListener(e -> removeRow(field));
301

  
302

  
303
        buttonGroup.addComponent(add);
304
        buttonGroup.addComponent(remove);
305
        addStyledComponents(add, remove);
306
        if(isOrderedCollection){
307
            Button moveUp = new Button(FontAwesome.ARROW_UP);
308
            moveUp.addClickListener(e -> moveRowUp(field));
309
            Button moveDown = new Button(FontAwesome.ARROW_DOWN);
310
            moveDown.addClickListener(e -> moveRowDown(field));
311

  
312

  
313
            buttonGroup.addComponents(moveUp, moveDown);
314
            addStyledComponents(moveUp, moveDown);
315
        }
316
        buttonGroup.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
317

  
318
        return buttonGroup;
319
    }
320

  
321
    private void updateButtonStates(){
322

  
323
        int fieldsCount = getNestedFields().size();
324
        for(int row = 0; row < fieldsCount; row++){
325

  
326
            boolean isFirst = row == 0;
327
            boolean isLast = row == fieldsCount - 1;
328

  
329
            CssLayout buttonGroup = (CssLayout) grid.getComponent(GRID_X_FIELD + 1, row);
330

  
331
            // add
332
            buttonGroup.getComponent(0).setEnabled(isLast || isOrderedCollection);
333
            // remove
334
            buttonGroup.getComponent(1).setEnabled(!isFirst);
335
            // up
336
            if(buttonGroup.getComponentCount() > 2){
337
                buttonGroup.getComponent(2).setEnabled(!isFirst);
338
                // down
339
                buttonGroup.getComponent(3).setEnabled(!isLast);
340
            }
341
        }
342
    }
343

  
344

  
345
    protected List<F> getNestedFields(){
346
        List<F> nestedFields = new ArrayList<>(grid.getRows());
347
        for(int r = 0; r < grid.getRows(); r++){
348
            F f = (F) grid.getComponent(GRID_X_FIELD, r);
349
            if(f == null){
350
                logger.debug(String.format("NULL field at %d,%d", GRID_X_FIELD, r));
351
            } else {
352
                nestedFields.add(f);
353
            }
354
        }
355
        return Collections.unmodifiableList(nestedFields);
356
    }
357

  
195 358
    /**
196 359
     *
197 360
     * @param val
......
254 417
     */
255 418
    @Override
256 419
    public void commit() throws SourceException, InvalidValueException {
257
        nestedFields.forEach(f -> f.commit());
420
        getNestedFields().forEach(f -> f.commit());
258 421
        // calling super.commit() is useless if operating on a transient property!!
259 422
        super.commit();
260 423
    }
......
271 434
     */
272 435
    public List<V> getValueFromNestedFields() {
273 436
        List<V> nestedValues = new ArrayList<>();
274
        nestedFields.forEach(f -> nestedValues.add(f.getValue()));
437
        getNestedFields().forEach(f -> {
438
                logger.trace(String.format("getValueFromNestedFields() - %s:%s",
439
                       f != null ? f.getClass().getSimpleName() : "null",
440
                       f != null ? f.getValue() : "null"
441
                ));
442
                if(f != null){
443
                    nestedValues.add(f.getValue());
444
                }
445
            });
275 446
        return nestedValues;
276 447
    }
277 448

  

Also available in: Unified diff