Project

General

Profile

Download (18.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2007 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

    
10
package eu.etaxonomy.taxeditor.editor.name.e4;
11

    
12
import java.util.ArrayList;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Set;
16

    
17
import javax.annotation.PostConstruct;
18
import javax.annotation.PreDestroy;
19
import javax.inject.Inject;
20

    
21
import org.apache.commons.lang.StringUtils;
22
import org.eclipse.core.commands.operations.IUndoContext;
23
import org.eclipse.core.commands.operations.UndoContext;
24
import org.eclipse.core.runtime.IProgressMonitor;
25
import org.eclipse.core.runtime.OperationCanceledException;
26
import org.eclipse.e4.core.services.events.IEventBroker;
27
import org.eclipse.e4.ui.di.Focus;
28
import org.eclipse.e4.ui.di.Persist;
29
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
30
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
31
import org.eclipse.e4.ui.services.EMenuService;
32
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33
import org.eclipse.jface.dialogs.MessageDialog;
34
import org.eclipse.jface.viewers.ISelection;
35
import org.eclipse.jface.viewers.ISelectionProvider;
36
import org.eclipse.jface.viewers.StructuredSelection;
37
import org.eclipse.swt.dnd.DND;
38
import org.eclipse.swt.dnd.DropTarget;
39
import org.eclipse.swt.dnd.Transfer;
40
import org.eclipse.swt.graphics.Color;
41
import org.eclipse.swt.widgets.Composite;
42
import org.eclipse.ui.ISelectionListener;
43
import org.eclipse.ui.IWorkbenchPart;
44
import org.eclipse.ui.IWorkbenchPartReference;
45
import org.eclipse.ui.PartInitException;
46
import org.eclipse.ui.PlatformUI;
47
import org.eclipse.ui.forms.ManagedForm;
48
import org.eclipse.ui.forms.widgets.FormToolkit;
49
import org.eclipse.ui.forms.widgets.ScrolledForm;
50
import org.eclipse.ui.forms.widgets.TableWrapLayout;
51

    
52
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
53
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
54
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
55
import eu.etaxonomy.cdm.model.common.CdmBase;
56
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
57
import eu.etaxonomy.cdm.model.taxon.Taxon;
58
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
59
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
60
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
61
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
62
import eu.etaxonomy.taxeditor.editor.CdmDataTransfer;
63
import eu.etaxonomy.taxeditor.editor.ISecuredEditor;
64
import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
65
import eu.etaxonomy.taxeditor.editor.e4.TaxonEditorInputE4;
66
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
67
import eu.etaxonomy.taxeditor.editor.name.e4.container.AbstractGroupE4;
68
import eu.etaxonomy.taxeditor.editor.name.e4.container.AbstractGroupedContainerE4;
69
import eu.etaxonomy.taxeditor.editor.name.e4.container.AcceptedGroupE4;
70
import eu.etaxonomy.taxeditor.editor.name.e4.container.AcceptedNameContainerE4;
71
import eu.etaxonomy.taxeditor.editor.name.e4.container.ContainerFactoryE4;
72
import eu.etaxonomy.taxeditor.editor.name.e4.container.HomotypicalSynonymGroupE4;
73
import eu.etaxonomy.taxeditor.editor.name.e4.container.MisappliedGroupE4;
74
import eu.etaxonomy.taxeditor.editor.name.e4.dnd.NameEditorDropTargetListenerE4;
75
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
76
import eu.etaxonomy.taxeditor.model.AbstractUtility;
77
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
78
import eu.etaxonomy.taxeditor.model.IPartChangeListener;
79
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
80
import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
81
import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
82
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
83
import eu.etaxonomy.taxeditor.model.TaxeditorPartService;
84
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
85
import eu.etaxonomy.taxeditor.preference.Resources;
86
import eu.etaxonomy.taxeditor.security.RequiredPermissions;
87
import eu.etaxonomy.taxeditor.store.CdmStore;
88
import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
89

    
90
/**
91
 *
92
 * @author pplitzner
93
 * @date Aug 24, 2017
94
 *
95
 */
96
public class TaxonNameEditorE4 implements IConversationEnabled, IDirtyMarkable, IPartContentHasDetails,
97
        IPartContentHasSupplementalData, IPartContentHasMedia, IPartContentHasFactualData, IPartChangeListener,
98
        ISelectionListener, ISecuredEditor, IPostOperationEnabled, IE4SavablePart, ITaxonEditor, IDropTargetableE4 {
99

    
100
	private Taxon taxon;
101

    
102
	private ManagedForm managedForm;
103
	private ScrolledForm scrolledForm;
104
	private Composite parent;
105
	private ISelectionProvider simpleSelectionProvider;
106

    
107
	private TaxonBase selection;
108

    
109
	private ConversationHolder conversation;
110

    
111
	private AcceptedGroupE4 acceptedGroup;
112
	private List<HomotypicalSynonymGroupE4> heterotypicSynonymGroups = new ArrayList<>();
113
	private MisappliedGroupE4 misappliedGroup;
114

    
115
	private DropTarget target;
116

    
117
	private TaxonBase objectAffectedByLastOperation;
118

    
119
	@Inject
120
	private EMenuService menuService;
121

    
122
	@Inject
123
	private ESelectionService selService;
124

    
125
	@Inject
126
	private MDirtyable dirty;
127

    
128
	private MPart thisPart;
129

    
130
    private TaxonEditorInputE4 input;
131

    
132
    private UndoContext undoContext;
133

    
134
    @Inject
135
    private IEventBroker eventBroker;
136

    
137
	@Inject
138
	public TaxonNameEditorE4() {
139
	    undoContext = new UndoContext();
140
	}
141

    
142

    
143
	@PostConstruct
144
    public void createPartControl(Composite parent, MPart thisPart) {
145
	    this.thisPart = thisPart;
146
        if (CdmStore.isActive()){
147
            if(conversation == null){
148
                conversation = CdmStore.createConversation();
149
            }
150
        }
151
        else{
152
            return;
153
        }
154

    
155
        createManagedForm(parent);
156

    
157
		TaxeditorPartService.getInstance().addListener(
158
				TaxeditorPartService.PART_ACTIVATED, this);
159

    
160
	}
161

    
162
	protected void createManagedForm(Composite composite) {
163

    
164
		managedForm = new ManagedForm(composite) {
165

    
166
			@Override
167
			public void dirtyStateChanged() {
168
			    dirty.setDirty(true);
169
			}
170

    
171
			@Override
172
			public boolean setInput(Object input) {
173
				if (input instanceof AbstractGroupedContainerE4) {
174
					selection = ((AbstractGroupedContainerE4) input).getData();
175

    
176
			        selService.setSelection(new StructuredSelection(selection));
177
				}else if(input == null){
178
					selection = null;
179
                    selService.setSelection(new StructuredSelection());
180
				}
181

    
182

    
183
				return super.setInput(input);
184
			}
185
		};
186

    
187
		scrolledForm = managedForm.getForm();
188
		parent = scrolledForm.getBody();
189

    
190
		parent.setData(taxon);
191

    
192
		TableWrapLayout layout = new TableWrapLayout();
193
		layout.leftMargin = 0;
194
		layout.rightMargin = 0;
195
		layout.topMargin = 0;
196
		layout.bottomMargin = 0;
197

    
198
		layout.verticalSpacing = 0;
199
		layout.horizontalSpacing = 0;
200

    
201
		parent.setLayout(layout);
202
		parent.setBackground(AbstractUtility
203
				.getColor(Resources.COLOR_COMPOSITE_BACKGROUND));
204
	}
205

    
206
	public void createOrUpdateNameComposites() {
207
		ContainerFactoryE4.createOrUpdateAcceptedTaxonsHomotypicGroup(this);
208
		ContainerFactoryE4.createOrUpdateHeterotypicSynonymyGroups(this);
209
		ContainerFactoryE4.createOrUpdateMisapplicationsGroup(this);
210

    
211

    
212
		// Redraw composite
213
		managedForm.reflow(true);
214
		managedForm.refresh();
215
	}
216

    
217
	@Override
218
    public Taxon getTaxon() {
219
		return HibernateProxyHelper.deproxy(taxon);
220
	}
221

    
222
	public void setDirty() {
223
		managedForm.dirtyStateChanged();
224
	}
225

    
226
	@Focus
227
	public void setFocus() {
228
	    //make sure to bind again if maybe in another view the conversation was unbound
229
        if(conversation!=null && !conversation.isBound()){
230
            conversation.bind();
231
        }
232
	    if(input!=null){
233
	        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().setFocus();
234
	        if (getSelectedContainer() == null) {
235
	            throw new IllegalStateException(
236
	                    Messages.TaxonNameEditor_THERE_SHOULD_ALWAYS_BE);
237
	        }
238
	        getSelectedContainer().setSelected();
239

    
240
	        // check permissions
241
	        boolean doEnable = permissionsSatisfied();
242
	        managedForm.getForm().setEnabled(doEnable);
243
	    }
244
        eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, this);
245
	}
246

    
247
	@Override
248
	public boolean permissionsSatisfied() {
249
		TaxonNode taxonNode = input.getTaxonNode();
250
		boolean doEnable = CdmStore.currentAuthentiationHasPermission(taxonNode, RequiredPermissions.TAXONNODE_EDIT);
251
		return doEnable;
252
	}
253

    
254
	@Override
255
    public ConversationHolder getConversationHolder() {
256
		return conversation;
257
	}
258

    
259
	/** {@inheritDoc} */
260
	@Override
261
    public void update(CdmDataChangeMap events) {
262
		// redraw();
263
	}
264

    
265
	/**
266
	 * Redraws this editor return true on success
267
	 *
268
	 * @return a boolean.
269
	 */
270
    public boolean redraw() {
271
		return redraw(true);
272
	}
273

    
274
	/**
275
	 * {@inheritDoc}
276
	 *
277
	 * Redraws the editor controls
278
	 */
279
    public boolean redraw(boolean focus) {
280

    
281
		createOrUpdateNameComposites();
282

    
283
		if (focus) {
284
			setFocus();
285
		}
286

    
287
		return true;
288
	}
289

    
290
	@Override
291
    public boolean postOperation(CdmBase objectAffectedByOperation) {
292

    
293
		changed(objectAffectedByOperation);
294

    
295
		redraw(false);
296

    
297
		if (objectAffectedByOperation instanceof TaxonBase) {
298
			objectAffectedByLastOperation = (TaxonBase) objectAffectedByOperation;
299
		}
300

    
301
		return true;
302
	}
303

    
304
	public ManagedForm getManagedForm() {
305
		return managedForm;
306
	}
307

    
308

    
309
	/**
310
	 * <p>
311
	 * checkForEmptyNames
312
	 * </p>
313
	 *
314
	 * @return true if there are empty names
315
	 */
316
	public boolean checkForEmptyNames() {
317
		for (AbstractGroupedContainerE4 container : getGroupedContainers()) {
318
			if (container.getName() == null
319
					|| StringUtils.isEmpty(container.getName().getTitleCache())) {
320
				return true;
321
			}
322
		}
323
		return false;
324
	}
325

    
326
	public Set<AbstractGroupedContainerE4> getEmptyContainers() {
327
		Set<AbstractGroupedContainerE4> containersWithEmptyNames = new HashSet<>();
328

    
329
		for (AbstractGroupedContainerE4 container : getGroupedContainers()) {
330
			if (container.getName() == null
331
					|| StringUtils.isEmpty(container.getName().getTitleCache())) {
332
				containersWithEmptyNames.add(container);
333
			}
334
		}
335

    
336
		return containersWithEmptyNames;
337
	}
338

    
339
	/** {@inheritDoc} */
340
	@Override
341
    @Persist
342
	public void save(IProgressMonitor monitor) {
343

    
344
	    monitor.beginTask(Messages.TaxonNameEditor_SAVING_NAMES, getGroupedContainers().size());
345
	    if (!conversation.isBound()) {
346
	        conversation.bind();
347
	    }
348
	    monitor.worked(1);
349

    
350
	    // check for empty names
351
	    if (checkForEmptyNames()) {
352
	        MessageDialog.openWarning(AbstractUtility.getShell(), Messages.MultiPageTaxonEditor_NO_NAME_SPECIFIED,
353
	                Messages.MultiPageTaxonEditor_NO_NAME_SPECIFIED_MESSAGE);
354
	        return;
355
	    }
356
	    for (AbstractGroupedContainerE4 container : getGroupedContainers()) {
357

    
358
	        monitor.subTask(Messages.TaxonNameEditor_SAVING_COMPOSITES
359
	                + container.getTaxonBase().getTitleCache());
360
	        container.persistName();
361

    
362
	        // In case the progress monitor was canceled throw an exception.
363
	        if (monitor.isCanceled()) {
364
	            throw new OperationCanceledException();
365
	        }
366
	        // commit the conversation and start a new transaction immediately
367
	        input.merge();
368

    
369
	        conversation.commit(true);
370

    
371
	        // Otherwise declare this step as done.
372
	        monitor.worked(1);
373

    
374
	        dirty.setDirty(false);
375
	    }
376

    
377
	    // Stop the progress monitor.
378
	    monitor.done();
379
	}
380

    
381
	public void init(TaxonEditorInputE4 input)
382
			throws PartInitException {
383

    
384
		if (!(input != null)) {
385
            throw new PartInitException(Messages.TaxonNameEditor_INVALID_INPUT);
386
        }
387

    
388
		if (input.getAdapter(Taxon.class) != null) {
389
			taxon = CdmBase.deproxy(input.getAdapter(Taxon.class), Taxon.class);
390
		} else {
391
			throw new PartInitException(Messages.TaxonNameEditor_INVALID_INPUT_TAXON_NULL);
392
		}
393

    
394
		this.input = input;
395

    
396
        createOrUpdateNameComposites();
397

    
398
        setFocus();
399

    
400
        createDragSupport();
401

    
402
        setPartName();
403
	}
404

    
405
   private void createDragSupport() {
406
       // Listen for names being dragged outside of existing homotypic groups -
407
       // user wants to create a new group
408
       Transfer[] types = new Transfer[] { CdmDataTransfer.getInstance() };
409
       int operations = DND.DROP_MOVE;
410
       if (target == null) {
411
           target = new DropTarget(parent, operations);
412
           target.setTransfer(types);
413
           target.addDropListener(new NameEditorDropTargetListenerE4(this));
414
       }
415
   }
416

    
417
	public AcceptedNameContainerE4 getAcceptedNameContainer() {
418
		return getAcceptedGroup().getAcceptedNameContainer();
419
	}
420

    
421
	public HomotypicalSynonymGroupE4 getHomotypicalGroupContainer(
422
			HomotypicalGroup homotypicalGroup) {
423
		for (HomotypicalSynonymGroupE4 group : getHeterotypicSynonymGroups()) {
424
			if (group.getGroup().equals(homotypicalGroup)) {
425
				return group;
426
			}
427
		}
428

    
429
		return null;
430
	}
431

    
432
	/**
433
	 * <p>
434
	 * getDirtyNames
435
	 * </p>
436
	 *
437
	 * @return a Set containing all composites that have been edited
438
	 */
439
	public Set<AbstractGroupedContainerE4> getDirtyNames() {
440
		Set<AbstractGroupedContainerE4> dirtyNames = new HashSet<>();
441

    
442
		for (AbstractGroupedContainerE4 composite : getGroupedContainers()) {
443
			if (composite.isDirty()) {
444
				dirtyNames.add(composite);
445
			}
446
		}
447

    
448
		return dirtyNames;
449
	}
450

    
451
	public List<AbstractGroupedContainerE4> getGroupedContainers() {
452
		List<AbstractGroupedContainerE4> groupedComposites = new ArrayList<>();
453

    
454
		for (AbstractGroupE4 group : getAllGroups()) {
455
			groupedComposites.addAll(group.getGroupedContainers());
456
		}
457

    
458
		return groupedComposites;
459
	}
460

    
461
	public List<AbstractGroupE4> getAllGroups() {
462
		List<AbstractGroupE4> allGroups = new ArrayList<>();
463

    
464
		allGroups.add(getAcceptedGroup());
465

    
466
		heterotypicSynonymGroups = getHeterotypicSynonymGroups();
467

    
468
		if (heterotypicSynonymGroups != null) {
469
			allGroups.addAll(heterotypicSynonymGroups);
470
		}
471

    
472
		if (misappliedGroup != null) {
473
			allGroups.add(misappliedGroup);
474
		}
475

    
476
		return allGroups;
477
	}
478

    
479
	public boolean isDirty() {
480
		return dirty.isDirty();
481
	}
482

    
483
	@PreDestroy
484
	public void dispose() {
485
        if(conversation!=null){
486
            conversation.unregisterForDataStoreChanges(this);
487
            conversation.close();
488
        }
489
	}
490

    
491
	/** {@inheritDoc} */
492
	@Override
493
    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
494

    
495
	}
496

    
497
	public AbstractGroupedContainerE4 getSelectedContainer() {
498

    
499
		TaxonBase selectedTaxonBase = null;
500

    
501
		if (input.getInitiallySelectedTaxonBase() != null) {
502
			selectedTaxonBase = input.getInitiallySelectedTaxonBase();
503
		} else {
504
			if (selection != null) {
505
				selectedTaxonBase = selection;
506
			}
507
		}
508

    
509
		return (selectedTaxonBase != null) ? getContainer(selectedTaxonBase)
510
				: getAcceptedNameContainer();
511
	}
512

    
513
    @Override
514
    public void dragEntered() {
515
        // TODO change this
516
        getControl().setBackground(
517
                AbstractUtility.getColor(Resources.COLOR_DRAG_ENTER));
518
    }
519

    
520
    @Override
521
    public void dragLeft() {
522
        getControl().setBackground(
523
                AbstractUtility.getColor(Resources.COLOR_COMPOSITE_BACKGROUND));
524
    }
525

    
526

    
527
	public void setMisapplicationsGroup(MisappliedGroupE4 misappliedGroup) {
528
		this.misappliedGroup = misappliedGroup;
529
	}
530

    
531
	public FormToolkit getToolkit() {
532
		return managedForm.getToolkit();
533
	}
534

    
535
	public List<HomotypicalSynonymGroupE4> getHeterotypicSynonymGroups() {
536
		return heterotypicSynonymGroups;
537
	}
538

    
539
	public void addHeterotypicSynonymGroup(HomotypicalSynonymGroupE4 group) {
540
		heterotypicSynonymGroups.add(group);
541
	}
542

    
543
	public AcceptedGroupE4 getAcceptedGroup() {
544
		return acceptedGroup;
545
	}
546

    
547
	public void setAcceptedGroup(AcceptedGroupE4 acceptedGroup) {
548
		this.acceptedGroup = acceptedGroup;
549
	}
550

    
551
	public MisappliedGroupE4 getMisappliedGroup() {
552
		return misappliedGroup;
553
	}
554

    
555
	public boolean isActive() {
556
		return this.equals(AbstractUtility.getActiveE4Part());
557
	}
558

    
559
    @Override
560
    public boolean onComplete() {
561
		getContainer(objectAffectedByLastOperation).setSelected();
562
		return true;
563
	}
564

    
565
	/** {@inheritDoc} */
566
	@Override
567
    public void partChanged(Integer eventType, IWorkbenchPartReference partRef) {
568
		if (!partRef.getPart(false).equals(this)) {
569
			// getSelectedObject().colorSelected(AbstractGroupedContainer.SELECTED_NO_FOCUS);
570
		}
571
	}
572

    
573
	public void removeGroup(AbstractGroupE4 group) {
574
		if (group != null) {
575
			group.dispose();
576

    
577
			//if (heterotypicSynonymGroups != null) {
578
			heterotypicSynonymGroups.remove(group);
579
			//}
580
		}
581
	}
582

    
583
	public AbstractGroupedContainerE4 getContainer(TaxonBase taxonBase) {
584
		List<AbstractGroupedContainerE4> groupedContainers = getGroupedContainers();
585
		for (AbstractGroupedContainerE4 container : groupedContainers) {
586
			if (container.getData().equals(taxonBase)
587
					&& container.getNameViewer().getTextWidget() != null) {
588
				return container;
589
			}
590
		}
591
		return getAcceptedNameContainer();
592
	}
593

    
594
    public void setOnError() {
595
		Color disabledColor =  AbstractUtility.getColor(Resources.COLOR_EDITOR_ERROR);
596
		setEnabled(false, disabledColor);
597
	}
598

    
599
	public void setDisabled(){
600
		Color disabledColor =  AbstractUtility.getColor(Resources.COLOR_TEXT_DISABLED_BACKGROUND);
601
		setEnabled(false, disabledColor);
602
	}
603

    
604
	protected void setEnabled(boolean enabled, Color background) {
605

    
606
		for(AbstractGroupedContainerE4 groupedContainer : getGroupedContainers()){
607
			groupedContainer.setEnabled(enabled);
608
		}
609

    
610
		// send an empty selection to the current provider - TODO only on error ???
611
		if (!enabled) {
612
			getManagedForm().setInput(null);
613

    
614
			for (AbstractGroupedContainerE4 groupedContainer : getGroupedContainers()) {
615
				groupedContainer.setBackground(background);
616
			}
617
		}
618
		getControl().setBackground(background);
619
	}
620

    
621
    @Override
622
    public void changed(Object element) {
623
        // setDirty(true);
624
        // if the attribute is null then do not set the dirty flag -> hotfix for the problem that for tasks done in service methods the changes are saved automatically
625
        if (element != null){
626
            dirty.setDirty(true);
627
            //refresh part title
628
            //TODO: refresh taxon node in taxon navigator
629
            setPartName();
630
        }
631

    
632
        if (element instanceof TaxonBase) {
633
            AbstractGroupedContainerE4 container = getContainer((TaxonBase) element);
634
            if (container != null) {
635
                container.refresh();
636
            }
637
        }
638
        if (element instanceof TaxonRelationship) {
639
            AbstractGroupedContainerE4 container = getContainer(((TaxonRelationship) element).getFromTaxon());
640
            if (container != null) {
641
                container.refresh();
642
            }
643
        }
644
    }
645

    
646
    public void setPartName(){
647
        thisPart.setLabel(taxon.toString());
648
    }
649

    
650
    @Override
651
    public void forceDirty() {
652
        setDirty();
653
    }
654

    
655

    
656
    public IUndoContext getUndoContext() {
657
        return undoContext;
658
    }
659

    
660
    @Override
661
    public Composite getControl(){
662
        return managedForm.getForm().getBody();
663
    }
664

    
665
    public EMenuService getMenuService() {
666
        return menuService;
667
    }
668

    
669
    public ESelectionService getSelectionService() {
670
        return selService;
671
    }
672

    
673

    
674
    /**
675
     * {@inheritDoc}
676
     */
677
    @Override
678
    public boolean canAttachMedia() {
679
        return true;
680
    }
681

    
682
    public TaxonEditorInputE4 getEditorInput() {
683
        return input;
684
    }
685

    
686
    /**
687
     * {@inheritDoc}
688
     */
689
    @Override
690
    public TaxonNameEditorE4 getEditor() {
691
        return this;
692
    }
693

    
694
}
(2-2/2)