Project

General

Profile

Download (25.1 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.mvp;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.Stack;
16

    
17
import org.apache.log4j.Logger;
18
import org.vaadin.spring.events.EventScope;
19

    
20
import com.vaadin.data.Validator.InvalidValueException;
21
import com.vaadin.data.fieldgroup.BeanFieldGroup;
22
import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
23
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
24
import com.vaadin.data.fieldgroup.FieldGroup.CommitHandler;
25
import com.vaadin.data.fieldgroup.FieldGroup.FieldGroupInvalidValueException;
26
import com.vaadin.server.AbstractErrorMessage.ContentMode;
27
import com.vaadin.server.ErrorMessage.ErrorLevel;
28
import com.vaadin.server.FontAwesome;
29
import com.vaadin.server.UserError;
30
import com.vaadin.shared.ui.MarginInfo;
31
import com.vaadin.ui.AbstractComponentContainer;
32
import com.vaadin.ui.AbstractField;
33
import com.vaadin.ui.AbstractLayout;
34
import com.vaadin.ui.AbstractOrderedLayout;
35
import com.vaadin.ui.Alignment;
36
import com.vaadin.ui.Button;
37
import com.vaadin.ui.CheckBox;
38
import com.vaadin.ui.Component;
39
import com.vaadin.ui.CssLayout;
40
import com.vaadin.ui.Field;
41
import com.vaadin.ui.GridLayout;
42
import com.vaadin.ui.GridLayout.OutOfBoundsException;
43
import com.vaadin.ui.GridLayout.OverlapsException;
44
import com.vaadin.ui.HorizontalLayout;
45
import com.vaadin.ui.Layout;
46
import com.vaadin.ui.Layout.MarginHandler;
47
import com.vaadin.ui.Notification;
48
import com.vaadin.ui.Notification.Type;
49
import com.vaadin.ui.PopupDateField;
50
import com.vaadin.ui.TextField;
51
import com.vaadin.ui.VerticalLayout;
52
import com.vaadin.ui.themes.ValoTheme;
53

    
54
import eu.etaxonomy.cdm.database.PermissionDeniedException;
55
import eu.etaxonomy.cdm.vaadin.component.TextFieldNFix;
56
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction;
57
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
58
import eu.etaxonomy.vaadin.component.NestedFieldGroup;
59
import eu.etaxonomy.vaadin.component.SwitchableTextField;
60
import eu.etaxonomy.vaadin.mvp.event.EditorDeleteEvent;
61
import eu.etaxonomy.vaadin.mvp.event.EditorPreSaveEvent;
62
import eu.etaxonomy.vaadin.mvp.event.EditorSaveEvent;
63
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
64
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
65

    
66
/**
67
 *
68
 * Optional with a delete button which can be enabled with {@link #withDeleteButton(boolean)}
69
 *
70
 * @author a.kohlbecker
71
 * @since Apr 5, 2017
72
 *
73
 */
74
public abstract class AbstractPopupEditor<DTO extends Object, P extends AbstractEditorPresenter<DTO, ? extends ApplicationView>>
75
    extends AbstractPopupView<P> {
76

    
77
    public static final Logger logger = Logger.getLogger(AbstractPopupEditor.class);
78

    
79
    private BeanFieldGroup<DTO> fieldGroup;
80

    
81
    private VerticalLayout mainLayout;
82

    
83
    private Layout fieldLayout;
84

    
85
    private HorizontalLayout buttonLayout;
86

    
87
    private Button save;
88

    
89
    private Button cancel;
90

    
91
    private Button delete;
92

    
93
    private CssLayout toolBar = new CssLayout();
94

    
95
    private CssLayout toolBarButtonGroup = new CssLayout();
96

    
97
    private GridLayout _gridLayoutCache;
98

    
99
    private boolean isBeanLoaded;
100

    
101
    private Stack<EditorActionContext> context = new Stack<EditorActionContext>();
102

    
103
    private boolean isContextUpdated;
104

    
105
    private boolean isAdvancedMode = false;
106

    
107
    private List<Component> advancedModeComponents = new ArrayList<>();
108

    
109
    private Button advancedModeButton;
110

    
111
    public AbstractPopupEditor(Layout layout, Class<DTO> dtoType) {
112

    
113
        mainLayout = new VerticalLayout();
114
        // IMPORTANT: mainLayout must be set to full size otherwise the
115
        // popup window may have problems with automatic resizing of its
116
        // content.
117
        mainLayout.setSizeFull();
118

    
119
        setCompositionRoot(mainLayout);
120

    
121
        fieldGroup = new BeanFieldGroup<>(dtoType);
122
        fieldGroup.addCommitHandler(new SaveHandler());
123

    
124
        toolBar.addStyleName(ValoTheme.WINDOW_TOP_TOOLBAR);
125
        toolBar.setWidth(100, Unit.PERCENTAGE);
126
        toolBarButtonGroup.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
127
        toolBarButtonGroup.setWidthUndefined();
128
        toolBar.addComponent(toolBarButtonGroup);
129
        toolBar.setVisible(false);
130

    
131
        fieldLayout = layout;
132
        fieldLayout.setWidthUndefined();
133
        if(fieldLayout instanceof AbstractOrderedLayout){
134
            ((AbstractOrderedLayout)fieldLayout).setSpacing(true);
135
        }
136
        if(MarginHandler.class.isAssignableFrom(fieldLayout.getClass())){
137
            ((MarginHandler)fieldLayout).setMargin(new MarginInfo(false, true, true, true));
138
        }
139

    
140
        buttonLayout = new HorizontalLayout();
141
        buttonLayout.setStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR);
142
        buttonLayout.setWidth(100, Unit.PERCENTAGE);
143
        buttonLayout.setSpacing(true);
144

    
145
        save = new Button("Save", FontAwesome.SAVE);
146
        save.setStyleName(ValoTheme.BUTTON_PRIMARY);
147
        save.addClickListener(e -> save());
148

    
149
        cancel = new Button("Cancel", FontAwesome.REMOVE);
150
        cancel.addClickListener(e -> cancel());
151

    
152
        delete = new Button("Delete", FontAwesome.TRASH);
153
        delete.setStyleName(ValoTheme.BUTTON_DANGER);
154
        delete.addClickListener(e -> delete());
155
        delete.setVisible(false);
156

    
157
        buttonLayout.addComponents(delete, save, cancel);
158
        // delete is initially invisible, let save take all space
159
        buttonLayout.setExpandRatio(save, 1);
160
        buttonLayout.setComponentAlignment(delete, Alignment.TOP_RIGHT);
161
        buttonLayout.setComponentAlignment(save, Alignment.TOP_RIGHT);
162
        buttonLayout.setComponentAlignment(cancel, Alignment.TOP_RIGHT);
163

    
164
        mainLayout.addComponents(toolBar, fieldLayout, buttonLayout);
165
        mainLayout.setComponentAlignment(toolBar, Alignment.TOP_RIGHT);
166

    
167
        updateToolBarVisibility();
168
    }
169

    
170
    protected VerticalLayout getMainLayout() {
171
        return mainLayout;
172
    }
173

    
174
    protected Layout getFieldLayout() {
175
        return fieldLayout;
176
    }
177

    
178
    /**
179
     * @return
180
     */
181
    private GridLayout gridLayout() {
182
        if(_gridLayoutCache == null){
183
            if(fieldLayout instanceof GridLayout){
184
                _gridLayoutCache = (GridLayout)fieldLayout;
185
            } else {
186
                throw new RuntimeException("The fieldlayout of this editor is not a GridLayout");
187
            }
188
        }
189
        return _gridLayoutCache;
190
    }
191

    
192
    @Override
193
    public void setReadOnly(boolean readOnly) {
194
        super.setReadOnly(readOnly);
195
        save.setVisible(!readOnly);
196
        delete.setVisible(!readOnly);
197
        cancel.setCaption(readOnly ? "Close" : "Cancel");
198
        recursiveReadonly(readOnly, (AbstractComponentContainer)getFieldLayout());
199
    }
200

    
201
    /**
202
     * @param readOnly
203
     * @param layout
204
     */
205
    protected void recursiveReadonly(boolean readOnly, AbstractComponentContainer layout) {
206
        for(Component c : layout){
207
            c.setReadOnly(readOnly);
208
            if(c instanceof AbstractComponentContainer){
209
                recursiveReadonly(readOnly, layout);
210
            }
211
        }
212
    }
213

    
214
    /**
215
     * @return
216
     * @return
217
     */
218
    protected AbstractLayout getToolBar() {
219
        return toolBar;
220
    }
221

    
222
    /**
223
     * @return
224
     * @return
225
     */
226
    protected void toolBarAdd(Component c) {
227
        toolBar.addComponent(c, toolBar.getComponentIndex(toolBarButtonGroup) - 1);
228
        updateToolBarVisibility();
229
    }
230

    
231
    /**
232
     * @return
233
     * @return
234
     */
235
    protected void toolBarButtonGroupAdd(Component c) {
236
        toolBarButtonGroup.addComponent(c);
237
        updateToolBarVisibility();
238
    }
239

    
240
    /**
241
     * @return
242
     * @return
243
     */
244
    protected void toolBarButtonGroupRemove(Component c) {
245
        toolBarButtonGroup.removeComponent(c);
246
        updateToolBarVisibility();
247
    }
248

    
249
    /**
250
     *
251
     */
252
    private void updateToolBarVisibility() {
253
        boolean showToolbar = toolBarButtonGroup.getComponentCount() + toolBar.getComponentCount() > 1;
254
        toolBar.setVisible(toolBarButtonGroup.getComponentCount() + toolBar.getComponentCount() > 1);
255
        if(!showToolbar){
256
            mainLayout.setMargin(new MarginInfo(true, false, false, false));
257
        } else {
258
            mainLayout.setMargin(false);
259
        }
260

    
261
    }
262

    
263
    /**
264
     * The top tool-bar is initially invisible.
265
     *
266
     * @param visible
267
     */
268
    protected void setToolBarVisible(boolean visible){
269
        toolBar.setVisible(true);
270
    }
271

    
272
    /**
273
     * @return the isAdvancedMode
274
     */
275
    public boolean isAdvancedMode() {
276
        return isAdvancedMode;
277
    }
278

    
279
    /**
280
     * @param isAdvancedMode the isAdvancedMode to set
281
     */
282
    public void setAdvancedMode(boolean isAdvancedMode) {
283
        this.isAdvancedMode = isAdvancedMode;
284
        advancedModeComponents.forEach(c -> c.setVisible(isAdvancedMode));
285
    }
286

    
287
    public void setAdvancedModeEnabled(boolean activate){
288
        if(activate && advancedModeButton == null){
289
            advancedModeButton = new Button(FontAwesome.WRENCH); // FontAwesome.FLASK
290
            advancedModeButton.setIconAlternateText("Advanced mode");
291
            advancedModeButton.addStyleName(ValoTheme.BUTTON_TINY);
292
            toolBarButtonGroupAdd(advancedModeButton);
293
            advancedModeButton.addClickListener(e -> {
294
                setAdvancedMode(!isAdvancedMode);
295
                }
296
            );
297

    
298
        } else if(advancedModeButton != null) {
299
            toolBarButtonGroupRemove(advancedModeButton);
300
            advancedModeButton = null;
301
        }
302
    }
303

    
304
    public void registerAdvancedModeComponents(Component ... c){
305
        advancedModeComponents.addAll(Arrays.asList(c));
306
    }
307

    
308

    
309
    // ------------------------ event handler ------------------------ //
310

    
311
    private class SaveHandler implements CommitHandler {
312

    
313
        private static final long serialVersionUID = 2047223089707080659L;
314

    
315
        @Override
316
        public void preCommit(CommitEvent commitEvent) throws CommitException {
317
            logger.debug("preCommit(), publishing EditorPreSaveEvent");
318
            // notify the presenter to start a transaction
319
            viewEventBus.publish(this, new EditorPreSaveEvent<DTO>(AbstractPopupEditor.this, getBean()));
320
        }
321

    
322
        @Override
323
        public void postCommit(CommitEvent commitEvent) throws CommitException {
324
            try {
325
                if(logger.isTraceEnabled()){
326
                    logger.trace("postCommit() publishing EditorSaveEvent for " + getBean().toString());
327
                }
328
                // notify the presenter to persist the bean and to commit the transaction
329
                viewEventBus.publish(this, new EditorSaveEvent<DTO>(AbstractPopupEditor.this, getBean()));
330
                if(logger.isTraceEnabled()){
331
                    logger.trace("postCommit() publishing DoneWithPopupEvent");
332
                }
333
                // notify the NavigationManagerBean to close the window and to dispose the view
334
                viewEventBus.publish(EventScope.UI, this, new DoneWithPopupEvent(AbstractPopupEditor.this, Reason.SAVE));
335
            } catch (Exception e) {
336
                logger.error(e);
337
                throw new CommitException("Failed to store data to backend", e);
338
            }
339
        }
340
    }
341

    
342
    protected void addCommitHandler(CommitHandler commitHandler) {
343
        fieldGroup.addCommitHandler(commitHandler);
344
    }
345

    
346

    
347
    /**
348
     * Cancel editing and discard all modifications.
349
     */
350
    @Override
351
    public void cancel() {
352
        fieldGroup.discard();
353
        viewEventBus.publish(EventScope.UI, this, new DoneWithPopupEvent(this, Reason.CANCEL));
354
    }
355

    
356
    /**
357
     * @return
358
     */
359
    private void delete() {
360
        viewEventBus.publish(this, new EditorDeleteEvent<DTO>(this, fieldGroup.getItemDataSource().getBean()));
361
        viewEventBus.publish(EventScope.UI, this, new DoneWithPopupEvent(this, Reason.DELETE));
362
    }
363

    
364
    /**
365
     * Save the changes made in the editor.
366
     */
367
    private void save() {
368
        try {
369
            fieldGroup.commit();
370
        } catch (CommitException e) {
371
            fieldGroup.getFields().forEach(f -> ((AbstractField<?>)f).setValidationVisible(true));
372
            if(e.getCause() != null && e.getCause() instanceof FieldGroupInvalidValueException){
373
                FieldGroupInvalidValueException invalidValueException = (FieldGroupInvalidValueException)e.getCause();
374
                updateFieldNotifications(invalidValueException.getInvalidFields());
375
                Notification.show("The entered data in " + invalidValueException.getInvalidFields().size() + " fields is incomplete or invalid.");
376
            } else if(e.getCause() != null && e.getCause().getCause() != null && e.getCause().getCause() instanceof PermissionDeniedException){
377
                PermissionDeniedException permissionDeniedException = (PermissionDeniedException)e.getCause().getCause();
378
                Notification.show("Permission denied", permissionDeniedException.getMessage(), Type.ERROR_MESSAGE);
379
            } else {
380
//                Logger.getLogger(this.getClass()).error("Error saving", e);
381
//                Notification.show("Error saving", Type.ERROR_MESSAGE);
382
                throw new RuntimeException("Error saving", e);
383
            }
384
        }
385
    }
386

    
387
    /**
388
     * @param invalidFields
389
     */
390
    private void updateFieldNotifications(Map<Field<?>, InvalidValueException> invalidFields) {
391
        for(Field<?> f : invalidFields.keySet()){
392
            if(f instanceof AbstractField){
393
                String message = invalidFields.get(f).getHtmlMessage();
394
                ((AbstractField)f).setComponentError(new UserError(message, ContentMode.HTML, ErrorLevel.ERROR));
395
            }
396
        }
397

    
398
    }
399

    
400
    // ------------------------ field adding methods ------------------------ //
401

    
402

    
403
    protected TextField addTextField(String caption, String propertyId) {
404
        return addField(new TextFieldNFix(caption), propertyId);
405
    }
406

    
407
    protected TextField addTextField(String caption, String propertyId, int column1, int row1,
408
            int column2, int row2)
409
            throws OverlapsException, OutOfBoundsException {
410
        return addField(new TextFieldNFix(caption), propertyId, column1, row1, column2, row2);
411
    }
412

    
413
    protected TextField addTextField(String caption, String propertyId, int column, int row)
414
            throws OverlapsException, OutOfBoundsException {
415
        return addField(new TextFieldNFix(caption), propertyId, column, row);
416
    }
417

    
418
    protected SwitchableTextField addSwitchableTextField(String caption, String textPropertyId, String switchPropertyId, int column1, int row1,
419
            int column2, int row2)
420
            throws OverlapsException, OutOfBoundsException {
421

    
422
        SwitchableTextField field = new SwitchableTextField(caption);
423
        field.bindTo(fieldGroup, textPropertyId, switchPropertyId);
424
        addComponent(field, column1, row1, column2, row2);
425
        return field;
426
    }
427

    
428
    protected SwitchableTextField addSwitchableTextField(String caption, String textPropertyId, String switchPropertyId, int column, int row)
429
            throws OverlapsException, OutOfBoundsException {
430

    
431
        SwitchableTextField field = new SwitchableTextField(caption);
432
        field.bindTo(fieldGroup, textPropertyId, switchPropertyId);
433
        addComponent(field, column, row);
434
        return field;
435
    }
436

    
437
    protected PopupDateField addDateField(String caption, String propertyId) {
438
        return addField(new PopupDateField(caption), propertyId);
439
    }
440

    
441
    protected CheckBox addCheckBox(String caption, String propertyId) {
442
        return addField(new CheckBox(caption), propertyId);
443
    }
444

    
445
    protected CheckBox addCheckBox(String caption, String propertyId, int column, int row){
446
        return addField(new CheckBox(caption), propertyId, column, row);
447
    }
448

    
449
    protected <T extends Field> T addField(T field, String propertyId) {
450
        fieldGroup.bind(field, propertyId);
451
        if(NestedFieldGroup.class.isAssignableFrom(field.getClass())){
452
            ((NestedFieldGroup)field).registerParentFieldGroup(fieldGroup);
453
        }
454
        addComponent(field);
455
        return field;
456
    }
457

    
458
    /**
459
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
460
     *
461
     * @param field
462
     *            the field to be added, not <code>null</code>.
463
     * @param propertyId
464
     * @param column
465
     *            the column index, starting from 0.
466
     * @param row
467
     *            the row index, starting from 0.
468
     * @throws OverlapsException
469
     *             if the new component overlaps with any of the components
470
     *             already in the grid.
471
     * @throws OutOfBoundsException
472
     *             if the cell is outside the grid area.
473
     */
474
    protected <T extends Field> T addField(T field, String propertyId, int column, int row)
475
            throws OverlapsException, OutOfBoundsException {
476
        fieldGroup.bind(field, propertyId);
477
        if(NestedFieldGroup.class.isAssignableFrom(field.getClass())){
478
            ((NestedFieldGroup)field).registerParentFieldGroup(fieldGroup);
479
        }
480
        addComponent(field, column, row);
481
        return field;
482
    }
483

    
484
    /**
485
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
486
     *
487
     * @param field
488
     * @param propertyId
489
     * @param column1
490
     * @param row1
491
     * @param column2
492
     * @param row2
493
     * @return
494
     * @throws OverlapsException
495
     * @throws OutOfBoundsException
496
     */
497
    protected <T extends Field> T addField(T field, String propertyId, int column1, int row1,
498
            int column2, int row2)
499
            throws OverlapsException, OutOfBoundsException {
500
        if(propertyId != null){
501
            fieldGroup.bind(field, propertyId);
502
            if(NestedFieldGroup.class.isAssignableFrom(field.getClass())){
503
                ((NestedFieldGroup)field).registerParentFieldGroup(fieldGroup);
504
            }
505
        }
506
        addComponent(field, column1, row1, column2, row2);
507
        return field;
508
    }
509

    
510
    protected Field<?> getField(Object propertyId){
511
        return fieldGroup.getField(propertyId);
512
    }
513

    
514
    protected void addComponent(Component component) {
515
        fieldLayout.addComponent(component);
516
        applyDefaultComponentStyles(component);
517
    }
518

    
519
    protected void bindField(Field field, String propertyId){
520
        fieldGroup.bind(field, propertyId);
521
    }
522

    
523
    /**
524
     * @param component
525
     */
526
    public void applyDefaultComponentStyles(Component component) {
527
        component.addStyleName(getDefaultComponentStyles());
528
    }
529

    
530
    protected abstract String getDefaultComponentStyles();
531

    
532
    /**
533
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
534
     * <p>
535
     * Adds the component to the grid in cells column1,row1 (NortWest corner of
536
     * the area.) End coordinates (SouthEast corner of the area) are the same as
537
     * column1,row1. The coordinates are zero-based. Component width and height
538
     * is 1.
539
     *
540
     * @param component
541
     *            the component to be added, not <code>null</code>.
542
     * @param column
543
     *            the column index, starting from 0.
544
     * @param row
545
     *            the row index, starting from 0.
546
     * @throws OverlapsException
547
     *             if the new component overlaps with any of the components
548
     *             already in the grid.
549
     * @throws OutOfBoundsException
550
     *             if the cell is outside the grid area.
551
     */
552
    public void addComponent(Component component, int column, int row)
553
            throws OverlapsException, OutOfBoundsException {
554
        applyDefaultComponentStyles(component);
555
        gridLayout().addComponent(component, column, row, column, row);
556
    }
557

    
558
    /**
559
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
560
     * <p>
561
     * Adds a component to the grid in the specified area. The area is defined
562
     * by specifying the upper left corner (column1, row1) and the lower right
563
     * corner (column2, row2) of the area. The coordinates are zero-based.
564
     * </p>
565
     *
566
     * <p>
567
     * If the area overlaps with any of the existing components already present
568
     * in the grid, the operation will fail and an {@link OverlapsException} is
569
     * thrown.
570
     * </p>
571
     *
572
     * @param component
573
     *            the component to be added, not <code>null</code>.
574
     * @param column1
575
     *            the column of the upper left corner of the area <code>c</code>
576
     *            is supposed to occupy. The leftmost column has index 0.
577
     * @param row1
578
     *            the row of the upper left corner of the area <code>c</code> is
579
     *            supposed to occupy. The topmost row has index 0.
580
     * @param column2
581
     *            the column of the lower right corner of the area
582
     *            <code>c</code> is supposed to occupy.
583
     * @param row2
584
     *            the row of the lower right corner of the area <code>c</code>
585
     *            is supposed to occupy.
586
     * @throws OverlapsException
587
     *             if the new component overlaps with any of the components
588
     *             already in the grid.
589
     * @throws OutOfBoundsException
590
     *             if the cells are outside the grid area.
591
     */
592
    public void addComponent(Component component, int column1, int row1,
593
            int column2, int row2)
594
            throws OverlapsException, OutOfBoundsException {
595
        applyDefaultComponentStyles(component);
596
        gridLayout().addComponent(component, column1, row1, column2, row2);
597
    }
598

    
599

    
600
    public void withDeleteButton(boolean withDelete){
601

    
602
        if(withDelete){
603
            buttonLayout.setExpandRatio(save, 0);
604
            buttonLayout.setExpandRatio(delete, 1);
605
        } else {
606
            buttonLayout.setExpandRatio(save, 1);
607
            buttonLayout.setExpandRatio(delete, 0);
608
        }
609
        delete.setVisible(withDelete);
610
    }
611

    
612

    
613
    // ------------------------ data binding ------------------------ //
614

    
615
    protected void bindDesign(Component component) {
616
        fieldLayout.removeAllComponents();
617
        fieldGroup.bindMemberFields(component);
618
        fieldLayout.addComponent(component);
619
    }
620

    
621

    
622
    public final void loadInEditor(Object identifier) {
623

    
624
        DTO beanToEdit = getPresenter().loadBeanById(identifier);
625
        fieldGroup.setItemDataSource(beanToEdit);
626
        afterItemDataSourceSet();
627
        getPresenter().adaptToUserPermission(beanToEdit);
628
        isBeanLoaded = true;
629
    }
630

    
631
    /**
632
     * Passes the beanInstantiator to the presenter method {@link AbstractEditorPresenter#setBeanInstantiator(BeanInstantiator)}
633
     *
634
     * @param beanInstantiator
635
     */
636
    public final void setBeanInstantiator(BeanInstantiator<DTO> beanInstantiator) {
637
        getPresenter().setBeanInstantiator(beanInstantiator);
638
    }
639

    
640
    /**
641
     * Returns the bean contained in the itemDatasource of the fieldGroup.
642
     *
643
     * @return
644
     */
645
    public DTO getBean() {
646
        if(fieldGroup.getItemDataSource() != null){
647
            return fieldGroup.getItemDataSource().getBean();
648

    
649
        }
650
        return null;
651
    }
652

    
653
    /**
654
     * @return true once the bean has been loaded indicating that all fields have
655
     *   been setup configured so that the editor is ready for use.
656
     */
657
    public boolean isBeanLoaded() {
658
        return isBeanLoaded;
659
    }
660

    
661
    /**
662
     * This method should only be used by the presenter of this view
663
     *
664
     * @param bean
665
     */
666
    protected void updateItemDataSource(DTO bean) {
667
        fieldGroup.getItemDataSource().setBean(bean);
668
    }
669

    
670
    /**
671
     * This method is called after setting the item data source whereby the
672
     * {@link FieldGroup#configureField(Field<?> field)} method will be called.
673
     * In this method all fields are set to default states defined for the fieldGroup.
674
     * <p>
675
     * You can now implement this method if you need to modify the state or value of individual fields.
676
     */
677
    protected void afterItemDataSourceSet() {
678
    }
679

    
680
    // ------------------------ issue related temporary solutions --------------------- //
681
    /**
682
     * Publicly accessible equivalent to getPreseneter(), needed for
683
     * managing the presenter listeners.
684
     * <p>
685
     * TODO: refactor the presenter listeners management to get rid of this method
686
     *
687
     * @return
688
     * @deprecated marked deprecated to emphasize on the special character of this method
689
     *    which should only be used internally see #6673
690
     */
691
    @Deprecated
692
    public P presenter() {
693
        return getPresenter();
694
    }
695

    
696
    /**
697
     * Returns the context of editor actions for this editor.
698
     * The context submitted with {@link #setParentContext(Stack)} will be updated
699
     * to represent the current context.
700
     *
701
     * @return the context
702
     */
703
    public Stack<EditorActionContext> getEditorActionContext() {
704
        if(!isContextUpdated){
705
            if(getBean() == null){
706
                throw new RuntimeException("getContext() is only possible after the bean is loaded");
707
            }
708
            context.push(new AbstractEditorAction.EditorActionContext(getBean(), this));
709
            isContextUpdated = true;
710
        }
711
        return context;
712
    }
713

    
714
    /**
715
     * Set the context of editor actions parent to this editor
716
     *
717
     * @param context the context to set
718
     */
719
    public void setParentEditorActionContext(Stack<EditorActionContext> context) {
720
        if(context != null){
721
            this.context.addAll(context);
722
        }
723
    }
724

    
725
}
(4-4/9)