Project

General

Profile

Download (23.5 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.Map;
12
import java.util.Stack;
13

    
14
import org.apache.log4j.Logger;
15
import org.vaadin.spring.events.EventScope;
16

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

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

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

    
73
    public static final Logger logger = Logger.getLogger(AbstractPopupEditor.class);
74

    
75
    private BeanFieldGroup<DTO> fieldGroup;
76

    
77
    private VerticalLayout mainLayout;
78

    
79
    private Layout fieldLayout;
80

    
81
    private HorizontalLayout buttonLayout;
82

    
83
    private Button save;
84

    
85
    private Button cancel;
86

    
87
    private Button delete;
88

    
89
    private CssLayout toolBar = new CssLayout();
90

    
91
    private CssLayout toolBarButtonGroup = new CssLayout();
92

    
93
    private GridLayout _gridLayoutCache;
94

    
95
    private boolean isBeanLoaded;
96

    
97
    private Stack<EditorActionContext> context = new Stack<EditorActionContext>();
98

    
99
    private boolean isContextUpdated;
100

    
101
    public AbstractPopupEditor(Layout layout, Class<DTO> dtoType) {
102

    
103
        mainLayout = new VerticalLayout();
104
        // IMPORTANT: mainLayout must be set to full size otherwise the
105
        // popup window may have problems with automatic resizing of its
106
        // content.
107
        mainLayout.setSizeFull();
108
        setCompositionRoot(mainLayout);
109

    
110
        fieldGroup = new BeanFieldGroup<>(dtoType);
111
        fieldGroup.addCommitHandler(new SaveHandler());
112

    
113
        toolBar.addStyleName(ValoTheme.WINDOW_TOP_TOOLBAR);
114
        toolBar.setWidth(100, Unit.PERCENTAGE);
115
        toolBarButtonGroup.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
116
        toolBarButtonGroup.setWidthUndefined();
117
        toolBar.addComponent(toolBarButtonGroup);
118
        toolBar.setVisible(false);
119

    
120
        fieldLayout = layout;
121
        fieldLayout.setWidthUndefined();
122
        if(fieldLayout instanceof AbstractOrderedLayout){
123
            ((AbstractOrderedLayout)fieldLayout).setSpacing(true);
124
        }
125

    
126
        buttonLayout = new HorizontalLayout();
127
        buttonLayout.setStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR);
128
        buttonLayout.setWidth(100, Unit.PERCENTAGE);
129
        buttonLayout.setSpacing(true);
130

    
131
        save = new Button("Save", FontAwesome.SAVE);
132
        save.setStyleName(ValoTheme.BUTTON_PRIMARY);
133
        save.addClickListener(e -> save());
134

    
135
        cancel = new Button("Cancel", FontAwesome.REMOVE);
136
        cancel.addClickListener(e -> cancel());
137

    
138
        delete = new Button("Delete", FontAwesome.TRASH);
139
        delete.setStyleName(ValoTheme.BUTTON_DANGER);
140
        delete.addClickListener(e -> delete());
141
        delete.setVisible(false);
142

    
143
        buttonLayout.addComponents(delete, save, cancel);
144
        // delete is initially invisible, let save take all space
145
        buttonLayout.setExpandRatio(save, 1);
146
        buttonLayout.setComponentAlignment(delete, Alignment.TOP_RIGHT);
147
        buttonLayout.setComponentAlignment(save, Alignment.TOP_RIGHT);
148
        buttonLayout.setComponentAlignment(cancel, Alignment.TOP_RIGHT);
149

    
150
        mainLayout.addComponents(toolBar, fieldLayout, buttonLayout);
151
        mainLayout.setComponentAlignment(toolBar, Alignment.TOP_RIGHT);
152

    
153
        updateToolBarVisibility();
154
    }
155

    
156
    protected VerticalLayout getMainLayout() {
157
        return mainLayout;
158
    }
159

    
160
    protected Layout getFieldLayout() {
161
        return fieldLayout;
162
    }
163

    
164
    /**
165
     * @return
166
     */
167
    private GridLayout gridLayout() {
168
        if(_gridLayoutCache == null){
169
            if(fieldLayout instanceof GridLayout){
170
                _gridLayoutCache = (GridLayout)fieldLayout;
171
            } else {
172
                throw new RuntimeException("The fieldlayout of this editor is not a GridLayout");
173
            }
174
        }
175
        return _gridLayoutCache;
176
    }
177

    
178
    @Override
179
    public void setReadOnly(boolean readOnly) {
180
        super.setReadOnly(readOnly);
181
        save.setVisible(!readOnly);
182
        delete.setVisible(!readOnly);
183
        cancel.setCaption(readOnly ? "Close" : "Cancel");
184
        recursiveReadonly(readOnly, (AbstractComponentContainer)getFieldLayout());
185
    }
186

    
187
    /**
188
     * @param readOnly
189
     * @param layout
190
     */
191
    protected void recursiveReadonly(boolean readOnly, AbstractComponentContainer layout) {
192
        for(Component c : layout){
193
            c.setReadOnly(readOnly);
194
            if(c instanceof AbstractComponentContainer){
195
                recursiveReadonly(readOnly, layout);
196
            }
197
        }
198
    }
199

    
200
    /**
201
     * @return
202
     * @return
203
     */
204
    protected AbstractLayout getToolBar() {
205
        return toolBar;
206
    }
207

    
208
    /**
209
     * @return
210
     * @return
211
     */
212
    protected void toolBarAdd(Component c) {
213
        toolBar.addComponent(c, toolBar.getComponentIndex(toolBarButtonGroup) - 1);
214
        updateToolBarVisibility();
215
    }
216

    
217
    /**
218
     * @return
219
     * @return
220
     */
221
    protected void toolBarButtonGroupAdd(Component c) {
222
        toolBarButtonGroup.addComponent(c);
223
        updateToolBarVisibility();
224
    }
225

    
226
    /**
227
     * @return
228
     * @return
229
     */
230
    protected void toolBarButtonGroupRemove(Component c) {
231
        toolBarButtonGroup.removeComponent(c);
232
        updateToolBarVisibility();
233
    }
234

    
235
    /**
236
     *
237
     */
238
    private void updateToolBarVisibility() {
239
        boolean showToolbar = toolBarButtonGroup.getComponentCount() + toolBar.getComponentCount() > 1;
240
        toolBar.setVisible(toolBarButtonGroup.getComponentCount() + toolBar.getComponentCount() > 1);
241
        if(!showToolbar){
242
            mainLayout.setMargin(new MarginInfo(true, false, false, false));
243
        } else {
244
            mainLayout.setMargin(false);
245
        }
246

    
247
    }
248

    
249
    /**
250
     * The top tool-bar is initially invisible.
251
     *
252
     * @param visible
253
     */
254
    protected void setToolBarVisible(boolean visible){
255
        toolBar.setVisible(true);
256
    }
257

    
258

    
259

    
260
    // ------------------------ event handler ------------------------ //
261

    
262
    private class SaveHandler implements CommitHandler {
263

    
264
        private static final long serialVersionUID = 2047223089707080659L;
265

    
266
        @Override
267
        public void preCommit(CommitEvent commitEvent) throws CommitException {
268
            logger.debug("preCommit(), publishing EditorPreSaveEvent");
269
            // notify the presenter to start a transaction
270
            viewEventBus.publish(this, new EditorPreSaveEvent<DTO>(AbstractPopupEditor.this, getBean()));
271
        }
272

    
273
        @Override
274
        public void postCommit(CommitEvent commitEvent) throws CommitException {
275
            try {
276
                if(logger.isTraceEnabled()){
277
                    logger.trace("postCommit() publishing EditorSaveEvent for " + getBean().toString());
278
                }
279
                // notify the presenter to persist the bean and to commit the transaction
280
                viewEventBus.publish(this, new EditorSaveEvent<DTO>(AbstractPopupEditor.this, getBean()));
281
                if(logger.isTraceEnabled()){
282
                    logger.trace("postCommit() publishing DoneWithPopupEvent");
283
                }
284
                // notify the NavigationManagerBean to close the window and to dispose the view
285
                viewEventBus.publish(EventScope.UI, this, new DoneWithPopupEvent(AbstractPopupEditor.this, Reason.SAVE));
286
            } catch (Exception e) {
287
                logger.error(e);
288
                throw new CommitException("Failed to store data to backend", e);
289
            }
290
        }
291
    }
292

    
293
    protected void addCommitHandler(CommitHandler commitHandler) {
294
        fieldGroup.addCommitHandler(commitHandler);
295
    }
296

    
297

    
298
    /**
299
     * Cancel editing and discard all modifications.
300
     */
301
    @Override
302
    public void cancel() {
303
        fieldGroup.discard();
304
        viewEventBus.publish(EventScope.UI, this, new DoneWithPopupEvent(this, Reason.CANCEL));
305
    }
306

    
307
    /**
308
     * @return
309
     */
310
    private void delete() {
311
        viewEventBus.publish(this, new EditorDeleteEvent<DTO>(this, fieldGroup.getItemDataSource().getBean()));
312
        viewEventBus.publish(EventScope.UI, this, new DoneWithPopupEvent(this, Reason.DELETE));
313
    }
314

    
315
    /**
316
     * Save the changes made in the editor.
317
     */
318
    private void save() {
319
        try {
320
            fieldGroup.commit();
321
        } catch (CommitException e) {
322
            fieldGroup.getFields().forEach(f -> ((AbstractField<?>)f).setValidationVisible(true));
323
            if(e.getCause() != null && e.getCause() instanceof FieldGroupInvalidValueException){
324
                FieldGroupInvalidValueException invalidValueException = (FieldGroupInvalidValueException)e.getCause();
325
                updateFieldNotifications(invalidValueException.getInvalidFields());
326
                Notification.show("The entered data in " + invalidValueException.getInvalidFields().size() + " fields is incomplete or invalid.");
327
            } else if(e.getCause() != null && e.getCause().getCause() != null && e.getCause().getCause() instanceof PermissionDeniedException){
328
                PermissionDeniedException permissionDeniedException = (PermissionDeniedException)e.getCause().getCause();
329
                Notification.show("Permission denied", permissionDeniedException.getMessage(), Type.ERROR_MESSAGE);
330
            } else {
331
//                Logger.getLogger(this.getClass()).error("Error saving", e);
332
//                Notification.show("Error saving", Type.ERROR_MESSAGE);
333
                throw new RuntimeException("Error saving", e);
334
            }
335
        }
336
    }
337

    
338
    /**
339
     * @param invalidFields
340
     */
341
    private void updateFieldNotifications(Map<Field<?>, InvalidValueException> invalidFields) {
342
        for(Field<?> f : invalidFields.keySet()){
343
            if(f instanceof AbstractField){
344
                String message = invalidFields.get(f).getHtmlMessage();
345
                ((AbstractField)f).setComponentError(new UserError(message, ContentMode.HTML, ErrorLevel.ERROR));
346
            }
347
        }
348

    
349
    }
350

    
351
    // ------------------------ field adding methods ------------------------ //
352

    
353

    
354
    protected TextField addTextField(String caption, String propertyId) {
355
        return addField(new TextFieldNFix(caption), propertyId);
356
    }
357

    
358
    protected TextField addTextField(String caption, String propertyId, int column1, int row1,
359
            int column2, int row2)
360
            throws OverlapsException, OutOfBoundsException {
361
        return addField(new TextFieldNFix(caption), propertyId, column1, row1, column2, row2);
362
    }
363

    
364
    protected TextField addTextField(String caption, String propertyId, int column, int row)
365
            throws OverlapsException, OutOfBoundsException {
366
        return addField(new TextFieldNFix(caption), propertyId, column, row);
367
    }
368

    
369
    protected SwitchableTextField addSwitchableTextField(String caption, String textPropertyId, String switchPropertyId, int column1, int row1,
370
            int column2, int row2)
371
            throws OverlapsException, OutOfBoundsException {
372

    
373
        SwitchableTextField field = new SwitchableTextField(caption);
374
        field.bindTo(fieldGroup, textPropertyId, switchPropertyId);
375
        addComponent(field, column1, row1, column2, row2);
376
        return field;
377
    }
378

    
379
    protected SwitchableTextField addSwitchableTextField(String caption, String textPropertyId, String switchPropertyId, int column, int row)
380
            throws OverlapsException, OutOfBoundsException {
381

    
382
        SwitchableTextField field = new SwitchableTextField(caption);
383
        field.bindTo(fieldGroup, textPropertyId, switchPropertyId);
384
        addComponent(field, column, row);
385
        return field;
386
    }
387

    
388
    protected PopupDateField addDateField(String caption, String propertyId) {
389
        return addField(new PopupDateField(caption), propertyId);
390
    }
391

    
392
    protected CheckBox addCheckBox(String caption, String propertyId) {
393
        return addField(new CheckBox(caption), propertyId);
394
    }
395

    
396
    protected CheckBox addCheckBox(String caption, String propertyId, int column, int row){
397
        return addField(new CheckBox(caption), propertyId, column, row);
398
    }
399

    
400
    protected <T extends Field> T addField(T field, String propertyId) {
401
        fieldGroup.bind(field, propertyId);
402
        if(NestedFieldGroup.class.isAssignableFrom(field.getClass())){
403
            ((NestedFieldGroup)field).registerParentFieldGroup(fieldGroup);
404
        }
405
        addComponent(field);
406
        return field;
407
    }
408

    
409
    /**
410
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
411
     *
412
     * @param field
413
     *            the field to be added, not <code>null</code>.
414
     * @param propertyId
415
     * @param column
416
     *            the column index, starting from 0.
417
     * @param row
418
     *            the row index, starting from 0.
419
     * @throws OverlapsException
420
     *             if the new component overlaps with any of the components
421
     *             already in the grid.
422
     * @throws OutOfBoundsException
423
     *             if the cell is outside the grid area.
424
     */
425
    protected <T extends Field> T addField(T field, String propertyId, int column, int row)
426
            throws OverlapsException, OutOfBoundsException {
427
        fieldGroup.bind(field, propertyId);
428
        if(NestedFieldGroup.class.isAssignableFrom(field.getClass())){
429
            ((NestedFieldGroup)field).registerParentFieldGroup(fieldGroup);
430
        }
431
        addComponent(field, column, row);
432
        return field;
433
    }
434

    
435
    /**
436
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
437
     *
438
     * @param field
439
     * @param propertyId
440
     * @param column1
441
     * @param row1
442
     * @param column2
443
     * @param row2
444
     * @return
445
     * @throws OverlapsException
446
     * @throws OutOfBoundsException
447
     */
448
    protected <T extends Field> T addField(T field, String propertyId, int column1, int row1,
449
            int column2, int row2)
450
            throws OverlapsException, OutOfBoundsException {
451
        if(propertyId != null){
452
            fieldGroup.bind(field, propertyId);
453
            if(NestedFieldGroup.class.isAssignableFrom(field.getClass())){
454
                ((NestedFieldGroup)field).registerParentFieldGroup(fieldGroup);
455
            }
456
        }
457
        addComponent(field, column1, row1, column2, row2);
458
        return field;
459
    }
460

    
461
    protected Field<?> getField(Object propertyId){
462
        return fieldGroup.getField(propertyId);
463
    }
464

    
465
    protected void addComponent(Component component) {
466
        fieldLayout.addComponent(component);
467
        applyDefaultComponentStyles(component);
468
    }
469

    
470
    protected void bindField(Field field, String propertyId){
471
        fieldGroup.bind(field, propertyId);
472
    }
473

    
474
    /**
475
     * @param component
476
     */
477
    public void applyDefaultComponentStyles(Component component) {
478
        component.addStyleName(getDefaultComponentStyles());
479
    }
480

    
481
    protected abstract String getDefaultComponentStyles();
482

    
483
    /**
484
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
485
     * <p>
486
     * Adds the component to the grid in cells column1,row1 (NortWest corner of
487
     * the area.) End coordinates (SouthEast corner of the area) are the same as
488
     * column1,row1. The coordinates are zero-based. Component width and height
489
     * is 1.
490
     *
491
     * @param component
492
     *            the component to be added, not <code>null</code>.
493
     * @param column
494
     *            the column index, starting from 0.
495
     * @param row
496
     *            the row index, starting from 0.
497
     * @throws OverlapsException
498
     *             if the new component overlaps with any of the components
499
     *             already in the grid.
500
     * @throws OutOfBoundsException
501
     *             if the cell is outside the grid area.
502
     */
503
    public void addComponent(Component component, int column, int row)
504
            throws OverlapsException, OutOfBoundsException {
505
        applyDefaultComponentStyles(component);
506
        gridLayout().addComponent(component, column, row, column, row);
507
    }
508

    
509
    /**
510
     * Can only be used if the <code>fieldlayout</code> is a GridLayout.
511
     * <p>
512
     * Adds a component to the grid in the specified area. The area is defined
513
     * by specifying the upper left corner (column1, row1) and the lower right
514
     * corner (column2, row2) of the area. The coordinates are zero-based.
515
     * </p>
516
     *
517
     * <p>
518
     * If the area overlaps with any of the existing components already present
519
     * in the grid, the operation will fail and an {@link OverlapsException} is
520
     * thrown.
521
     * </p>
522
     *
523
     * @param component
524
     *            the component to be added, not <code>null</code>.
525
     * @param column1
526
     *            the column of the upper left corner of the area <code>c</code>
527
     *            is supposed to occupy. The leftmost column has index 0.
528
     * @param row1
529
     *            the row of the upper left corner of the area <code>c</code> is
530
     *            supposed to occupy. The topmost row has index 0.
531
     * @param column2
532
     *            the column of the lower right corner of the area
533
     *            <code>c</code> is supposed to occupy.
534
     * @param row2
535
     *            the row of the lower right corner of the area <code>c</code>
536
     *            is supposed to occupy.
537
     * @throws OverlapsException
538
     *             if the new component overlaps with any of the components
539
     *             already in the grid.
540
     * @throws OutOfBoundsException
541
     *             if the cells are outside the grid area.
542
     */
543
    public void addComponent(Component component, int column1, int row1,
544
            int column2, int row2)
545
            throws OverlapsException, OutOfBoundsException {
546
        applyDefaultComponentStyles(component);
547
        gridLayout().addComponent(component, column1, row1, column2, row2);
548
    }
549

    
550

    
551
    public void withDeleteButton(boolean withDelete){
552

    
553
        if(withDelete){
554
            buttonLayout.setExpandRatio(save, 0);
555
            buttonLayout.setExpandRatio(delete, 1);
556
        } else {
557
            buttonLayout.setExpandRatio(save, 1);
558
            buttonLayout.setExpandRatio(delete, 0);
559
        }
560
        delete.setVisible(withDelete);
561
    }
562

    
563

    
564
    // ------------------------ data binding ------------------------ //
565

    
566
    protected void bindDesign(Component component) {
567
        fieldLayout.removeAllComponents();
568
        fieldGroup.bindMemberFields(component);
569
        fieldLayout.addComponent(component);
570
    }
571

    
572

    
573
    public final void loadInEditor(Object identifier) {
574

    
575
        DTO beanToEdit = getPresenter().loadBeanById(identifier);
576
        fieldGroup.setItemDataSource(beanToEdit);
577
        afterItemDataSourceSet();
578
        getPresenter().adaptToUserPermission(beanToEdit);
579
        isBeanLoaded = true;
580
    }
581

    
582
    /**
583
     * Passes the beanInstantiator to the presenter method {@link AbstractEditorPresenter#setBeanInstantiator(BeanInstantiator)}
584
     *
585
     * @param beanInstantiator
586
     */
587
    public final void setBeanInstantiator(BeanInstantiator<DTO> beanInstantiator) {
588
        getPresenter().setBeanInstantiator(beanInstantiator);
589
    }
590

    
591
    /**
592
     * Returns the bean contained in the itemDatasource of the fieldGroup.
593
     *
594
     * @return
595
     */
596
    public DTO getBean() {
597
        if(fieldGroup.getItemDataSource() != null){
598
            return fieldGroup.getItemDataSource().getBean();
599

    
600
        }
601
        return null;
602
    }
603

    
604
    /**
605
     * @return true once the bean has been loaded indicating that all fields have
606
     *   been setup configured so that the editor is ready for use.
607
     */
608
    public boolean isBeanLoaded() {
609
        return isBeanLoaded;
610
    }
611

    
612
    /**
613
     * This method should only be used by the presenter of this view
614
     *
615
     * @param bean
616
     */
617
    protected void updateItemDataSource(DTO bean) {
618
        fieldGroup.getItemDataSource().setBean(bean);
619
    }
620

    
621
    /**
622
     * This method is called after setting the item data source whereby the
623
     * {@link FieldGroup#configureField(Field<?> field)} method will be called.
624
     * In this method all fields are set to default states defined for the fieldGroup.
625
     * <p>
626
     * You can now implement this method if you need to modify the state or value of individual fields.
627
     */
628
    protected void afterItemDataSourceSet() {
629
    }
630

    
631
    // ------------------------ issue related temporary solutions --------------------- //
632
    /**
633
     * Publicly accessible equivalent to getPreseneter(), needed for
634
     * managing the presenter listeners.
635
     * <p>
636
     * TODO: refactor the presenter listeners management to get rid of this method
637
     *
638
     * @return
639
     * @deprecated marked deprecated to emphasize on the special character of this method
640
     *    which should only be used internally see #6673
641
     */
642
    @Deprecated
643
    public P presenter() {
644
        return getPresenter();
645
    }
646

    
647
    /**
648
     * Returns the context of editor actions for this editor.
649
     * The context submitted with {@link #setParentContext(Stack)} will be updated
650
     * to represent the current context.
651
     *
652
     * @return the context
653
     */
654
    public Stack<EditorActionContext> getEditorActionContext() {
655
        if(!isContextUpdated){
656
            if(getBean() == null){
657
                throw new RuntimeException("getContext() is only possible after the bean is loaded");
658
            }
659
            context.push(new AbstractEditorAction.EditorActionContext(getBean(), this));
660
            isContextUpdated = true;
661
        }
662
        return context;
663
    }
664

    
665
    /**
666
     * Set the context of editor actions parent to this editor
667
     *
668
     * @param context the context to set
669
     */
670
    public void setParentEditorActionContext(Stack<EditorActionContext> context) {
671
        if(context != null){
672
            this.context.addAll(context);
673
        }
674
    }
675

    
676
}
(4-4/9)