Merge branch 'release/5.18.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / name / e4 / TaxonNameEditorE4.java
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 import java.util.UUID;
17
18 import javax.annotation.PostConstruct;
19 import javax.annotation.PreDestroy;
20 import javax.inject.Inject;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.eclipse.core.commands.operations.IUndoContext;
24 import org.eclipse.core.commands.operations.UndoContext;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.OperationCanceledException;
27 import org.eclipse.e4.core.contexts.IEclipseContext;
28 import org.eclipse.e4.core.di.annotations.Optional;
29 import org.eclipse.e4.core.services.events.IEventBroker;
30 import org.eclipse.e4.ui.di.Focus;
31 import org.eclipse.e4.ui.di.Persist;
32 import org.eclipse.e4.ui.di.UIEventTopic;
33 import org.eclipse.e4.ui.di.UISynchronize;
34 import org.eclipse.e4.ui.model.application.MApplication;
35 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
36 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
37 import org.eclipse.e4.ui.services.EMenuService;
38 import org.eclipse.e4.ui.workbench.modeling.EModelService;
39 import org.eclipse.e4.ui.workbench.modeling.EPartService;
40 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
41 import org.eclipse.jface.dialogs.MessageDialog;
42 import org.eclipse.jface.viewers.ISelection;
43 import org.eclipse.jface.viewers.ISelectionProvider;
44 import org.eclipse.jface.viewers.StructuredSelection;
45 import org.eclipse.swt.dnd.DND;
46 import org.eclipse.swt.dnd.DropTarget;
47 import org.eclipse.swt.dnd.Transfer;
48 import org.eclipse.swt.graphics.Color;
49 import org.eclipse.swt.widgets.Composite;
50 import org.eclipse.ui.ISelectionListener;
51 import org.eclipse.ui.IWorkbenchPart;
52 import org.eclipse.ui.IWorkbenchPartReference;
53 import org.eclipse.ui.forms.ManagedForm;
54 import org.eclipse.ui.forms.widgets.FormToolkit;
55 import org.eclipse.ui.forms.widgets.ScrolledForm;
56 import org.eclipse.ui.forms.widgets.TableWrapLayout;
57
58 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
59 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
60 import eu.etaxonomy.cdm.api.service.DeleteResult;
61 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
62 import eu.etaxonomy.cdm.model.common.CdmBase;
63 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
64 import eu.etaxonomy.cdm.model.name.TaxonName;
65 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
66 import eu.etaxonomy.cdm.model.taxon.Taxon;
67 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
68 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
69 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
70 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
71 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
72 import eu.etaxonomy.taxeditor.editor.CdmDataTransfer;
73 import eu.etaxonomy.taxeditor.editor.EditorUtil;
74 import eu.etaxonomy.taxeditor.editor.ISecuredEditor;
75 import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
76 import eu.etaxonomy.taxeditor.editor.e4.TaxonEditorInputE4;
77 import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;
78 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
79 import eu.etaxonomy.taxeditor.editor.name.e4.container.AbstractGroupE4;
80 import eu.etaxonomy.taxeditor.editor.name.e4.container.AbstractGroupedContainerE4;
81 import eu.etaxonomy.taxeditor.editor.name.e4.container.AcceptedGroupE4;
82 import eu.etaxonomy.taxeditor.editor.name.e4.container.AcceptedNameContainerE4;
83 import eu.etaxonomy.taxeditor.editor.name.e4.container.ConceptContainerE4;
84 import eu.etaxonomy.taxeditor.editor.name.e4.container.ContainerFactoryE4;
85 import eu.etaxonomy.taxeditor.editor.name.e4.container.HomotypicalSynonymGroupE4;
86 import eu.etaxonomy.taxeditor.editor.name.e4.container.MisappliedGroupE4;
87 import eu.etaxonomy.taxeditor.editor.name.e4.dnd.NameEditorDropTargetListenerE4;
88 import eu.etaxonomy.taxeditor.event.EventUtility;
89 import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
90 import eu.etaxonomy.taxeditor.model.AbstractUtility;
91 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
92 import eu.etaxonomy.taxeditor.model.IPartChangeListener;
93 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
94 import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
95 import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
96 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
97 import eu.etaxonomy.taxeditor.model.MessagingUtils;
98 import eu.etaxonomy.taxeditor.model.TaxeditorPartService;
99 import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
100 import eu.etaxonomy.taxeditor.preference.Resources;
101 import eu.etaxonomy.taxeditor.security.RequiredPermissions;
102 import eu.etaxonomy.taxeditor.store.CdmStore;
103 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
104
105 /**
106 * @author pplitzner
107 * @date Aug 24, 2017
108 */
109 public class TaxonNameEditorE4 implements IConversationEnabled, IDirtyMarkable, IPartContentHasDetails,
110 IPartContentHasSupplementalData, IPartContentHasMedia, IPartContentHasFactualData, IPartChangeListener,
111 ISelectionListener, ISecuredEditor, IE4SavablePart, ITaxonEditor, IDropTargetableE4 {
112
113 private Taxon taxon;
114
115 private ManagedForm managedForm;
116 private ScrolledForm scrolledForm;
117 private Composite parent;
118 private ISelectionProvider simpleSelectionProvider;
119 @Inject
120 private EModelService modelService;
121
122 @Inject
123 private EPartService partService;
124 private TaxonBase selection;
125
126 private ConversationHolder conversation;
127
128 private AcceptedGroupE4 acceptedGroup;
129 private List<HomotypicalSynonymGroupE4> heterotypicSynonymGroups = new ArrayList<>();
130 private MisappliedGroupE4 misappliedGroup;
131
132 private DropTarget target;
133
134 @Inject
135 UISynchronize sync;
136
137 private TaxonBase<?> objectAffectedByLastOperation;
138
139 @Inject
140 private EMenuService menuService;
141
142 @Inject
143 private ESelectionService selService;
144
145 @Inject
146 private IEclipseContext context;
147
148 @Inject
149 private MDirtyable dirty;
150
151 @Inject
152 private MApplication application;
153
154 private MPart thisPart;
155
156 private TaxonEditorInputE4 input;
157
158 private UndoContext undoContext;
159
160 @Inject
161 private IEventBroker eventBroker;
162
163 @Inject
164 public TaxonNameEditorE4() {
165 undoContext = new UndoContext();
166 }
167
168 @PostConstruct
169 public void createPartControl(Composite parent, MPart thisPart) {
170 this.thisPart = thisPart;
171
172 createManagedForm(parent);
173
174 TaxeditorPartService.getInstance().addListener(TaxeditorPartService.PART_ACTIVATED, this);
175
176 }
177
178 protected void createManagedForm(Composite composite) {
179
180 managedForm = new ManagedForm(composite) {
181
182 @Override
183 public void dirtyStateChanged() {
184 dirty.setDirty(true);
185 }
186
187 @Override
188 public boolean setInput(Object input) {
189 if (input instanceof AbstractGroupedContainerE4) {
190 TaxonBase<?> newSelection = ((AbstractGroupedContainerE4<?>) input).getData();
191 if (selection != newSelection || TaxonNameEditorE4.this.isDirty()) {
192 selection = newSelection;
193 selService.setSelection(new StructuredSelection(selection));
194
195 }
196 } else if (input == null) {
197 selection = null;
198 selService.setSelection(new StructuredSelection());
199 }
200
201 return super.setInput(input);
202 }
203 };
204
205 scrolledForm = managedForm.getForm();
206 parent = scrolledForm.getBody();
207
208 parent.setData(taxon);
209
210 TableWrapLayout layout = new TableWrapLayout();
211 layout.leftMargin = 0;
212 layout.rightMargin = 0;
213 layout.topMargin = 0;
214 layout.bottomMargin = 0;
215
216 layout.verticalSpacing = 0;
217 layout.horizontalSpacing = 0;
218
219 parent.setLayout(layout);
220 parent.setBackground(AbstractUtility.getColor(Resources.COLOR_COMPOSITE_BACKGROUND));
221 }
222
223 public void createOrUpdateNameComposites(boolean accepted, boolean heterotypicGroups, boolean misappliedNames) {
224
225 if (accepted) {
226 ContainerFactoryE4.createOrUpdateAcceptedTaxonsHomotypicGroup(this);
227 }
228 if (heterotypicGroups) {
229 ContainerFactoryE4.createOrUpdateHeterotypicSynonymyGroups(this);
230 }
231 if (misappliedNames) {
232 ContainerFactoryE4.createOrUpdateMisapplicationsGroup(this);
233 }
234 ContainerFactoryE4.setMenuToAllContainers(this);
235
236 // Redraw composite
237 parent.pack();
238 managedForm.refresh();
239 managedForm.reflow(true);
240
241 }
242
243 @Override
244 public Taxon getTaxon() {
245 return HibernateProxyHelper.deproxy(taxon);
246 }
247
248 @Override
249 public void addOperation(AbstractPostOperation operation) {
250 input.addOperation(operation);
251 }
252
253 public void setDirty() {
254 managedForm.dirtyStateChanged();
255 }
256
257 @Focus
258 public void setFocus() {
259 // make sure to bind again if maybe in another view the conversation was
260 // unbound
261 eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, this);
262 if (conversation != null && !conversation.isBound()) {
263 conversation.bind();
264 }
265 if (EditorUtil.isFactsVisible()){
266 EditorUtil.showFacts(modelService, partService);
267 }
268 if (EditorUtil.isMediaVisible()){
269 EditorUtil.showMedia(modelService, partService);
270 }
271 if (input != null) {
272 if (getSelectedContainer() == null) {
273 throw new IllegalStateException(Messages.TaxonNameEditor_THERE_SHOULD_ALWAYS_BE);
274 }
275 getSelectedContainer().setSelected();
276
277 if (input.getCdmEntitySession() != null && !input.getCdmEntitySession().isActive()) {
278 input.bind();
279 }
280 }
281 // if(selection!=null){
282 // selService.setSelection(new StructuredSelection(selection));
283 // }
284 // check permissions
285 boolean doEnable = permissionsSatisfied();
286 managedForm.getForm().setEnabled(doEnable);
287
288
289 }
290
291 @Override
292 public boolean permissionsSatisfied() {
293 boolean doEnable = false;
294 if (input != null){
295 TaxonNode taxonNode = input.getTaxonNode();
296 doEnable = CdmStore.currentAuthentiationHasPermission(taxonNode,
297 RequiredPermissions.TAXON_EDIT);
298
299 }
300 return doEnable;
301 }
302
303 @Override
304 public ConversationHolder getConversationHolder() {
305 return conversation;
306 }
307
308 @Override
309 public void update(CdmDataChangeMap events) {
310 // redraw();
311 }
312
313 /**
314 * Redraws this editor return true on success
315 *
316 * @return a boolean.
317 */
318 public boolean redraw() {
319 return redraw(true, true, true, true);
320 }
321
322 /**
323 * {@inheritDoc}
324 *
325 * Redraws the editor controls
326 */
327 public boolean redraw(boolean focus, boolean accepted, boolean heterotypic, boolean misappliedNames) {
328
329 createOrUpdateNameComposites(accepted, heterotypic, misappliedNames);
330
331 if (focus) {
332 setFocus();
333 }
334
335 return true;
336 }
337
338 @Override
339 public boolean postOperation(Object objectAffectedByOperation) {
340 if (objectAffectedByOperation instanceof TaxonBase) {
341 objectAffectedByLastOperation = (TaxonBase<?>) objectAffectedByOperation;
342 }
343 redraw(true, true, true, true);
344 changed(objectAffectedByOperation);
345 onComplete();
346 getContainer(objectAffectedByLastOperation).setFocus();
347 return true;
348 }
349
350 public ManagedForm getManagedForm() {
351 return managedForm;
352 }
353
354 /**
355 * <p>
356 * checkForEmptyNames
357 * </p>
358 *
359 * @return true if there are empty names
360 */
361 public boolean checkForEmptyNames() {
362 for (AbstractGroupedContainerE4<?> container : getGroupedContainers()) {
363 if (container != null
364 && (container.getName() == null || StringUtils.isEmpty(container.getName().getTitleCache()))) {
365 return true;
366 }
367 }
368 return false;
369 }
370
371 public Set<AbstractGroupedContainerE4> getEmptyContainers() {
372 Set<AbstractGroupedContainerE4> containersWithEmptyNames = new HashSet<>();
373
374 for (AbstractGroupedContainerE4<?> container : getGroupedContainers()) {
375 if (container.getName() == null || StringUtils.isEmpty(container.getName().getTitleCache())) {
376 containersWithEmptyNames.add(container);
377 }
378 }
379
380 return containersWithEmptyNames;
381 }
382
383 @Override
384 @Persist
385 public void save(IProgressMonitor monitor) {
386
387 monitor.beginTask(Messages.TaxonNameEditor_SAVING_NAMES, getGroupedContainers().size());
388 if (!conversation.isBound()) {
389 conversation.bind();
390
391 }
392 conversation.commit(true);
393 monitor.worked(1);
394
395 // check for empty names
396 if (checkForEmptyNames()) {
397 MessageDialog.openWarning(AbstractUtility.getShell(), Messages.MultiPageTaxonEditor_NO_NAME_SPECIFIED,
398 Messages.MultiPageTaxonEditor_NO_NAME_SPECIFIED_MESSAGE);
399 return;
400 }
401 for (AbstractGroupedContainerE4<?> container : getGroupedContainers()) {
402
403 monitor.subTask(Messages.TaxonNameEditor_SAVING_COMPOSITES + container.getTaxonBase().getTitleCache());
404 container.persistName();
405 // because of missing cascading the concepts need to be saved
406 // separately
407 if (container instanceof ConceptContainerE4) {
408 input.addToSaveNewConcept((Taxon) container.getData());
409 }
410 // In case the progress monitor was canceled throw an exception.
411 if (monitor.isCanceled()) {
412 throw new OperationCanceledException();
413 }
414
415 // Otherwise declare this step as done.
416 monitor.worked(1);
417
418 }
419 input.setSync(sync);
420 input.merge();
421 // commit the conversation and start a new transaction immediately
422 conversation.commit(true);
423
424 dirty.setDirty(false);
425 EventUtility.postEvent(WorkbenchEventConstants.REFRESH_NAVIGATOR, new TaxonNodeDto(input.getTaxonNode()));
426 EventUtility.postEvent(WorkbenchEventConstants.SAVE_TAXON, true);
427 // Stop the progress monitor.
428 monitor.done();
429 }
430
431 public void init(TaxonEditorInputE4 input) {
432 if (this.input != null) {
433 this.input.dispose();
434 // this.acceptedGroup = null;
435 // this.heterotypicSynonymGroups.clear();
436 // this.misappliedGroup = null;
437 }
438 eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, this);
439 if (!(input != null)) {
440 MessagingUtils.error(this.getClass(), new Exception(Messages.TaxonNameEditor_INVALID_INPUT));
441 return;
442 }
443
444 if (input.getAdapter(Taxon.class) != null) {
445 taxon = CdmBase.deproxy(input.getAdapter(Taxon.class), Taxon.class);
446 } else {
447 MessagingUtils.error(this.getClass(), new Exception(Messages.TaxonNameEditor_INVALID_INPUT_TAXON_NULL));
448 return;
449 }
450
451 this.input = input;
452 conversation = input.getConversationHolder();
453
454 createOrUpdateNameComposites(true, true, true);
455
456 createDragSupport();
457
458 setPartName();
459 // this.setFocus();
460 // set initial selection
461 TaxonBase<?> initiallySelectedTaxonBase = input.getInitiallySelectedTaxonBase();
462 if (initiallySelectedTaxonBase != null) {
463 selService.setSelection(new StructuredSelection(initiallySelectedTaxonBase));
464 getContainer(initiallySelectedTaxonBase).setSelected();
465 }
466 }
467
468 private void createDragSupport() {
469 // Listen for names being dragged outside of existing homotypic groups -
470 // user wants to create a new group
471 Transfer[] types = new Transfer[] { CdmDataTransfer.getInstance() };
472 int operations = DND.DROP_MOVE;
473 if (target == null) {
474 target = new DropTarget(parent, operations);
475 target.setTransfer(types);
476 target.addDropListener(new NameEditorDropTargetListenerE4(this));
477 }
478 }
479
480 public AcceptedNameContainerE4 getAcceptedNameContainer() {
481 return getAcceptedGroup().getAcceptedNameContainer();
482 }
483
484 public HomotypicalSynonymGroupE4 getHomotypicalGroupContainer(HomotypicalGroup homotypicalGroup) {
485 for (HomotypicalSynonymGroupE4 group : getHeterotypicSynonymGroups()) {
486 if (group.getGroup().equals(homotypicalGroup)) {
487 return group;
488 }
489 }
490
491 return null;
492 }
493
494 /**
495 * <p>
496 * getDirtyNames
497 * </p>
498 *
499 * @return a Set containing all composites that have been edited
500 */
501 public Set<AbstractGroupedContainerE4> getDirtyNames() {
502 Set<AbstractGroupedContainerE4> dirtyNames = new HashSet<>();
503
504 for (AbstractGroupedContainerE4<?> composite : getGroupedContainers()) {
505 if (composite.isDirty()) {
506 dirtyNames.add(composite);
507 }
508 }
509
510 return dirtyNames;
511 }
512
513 public List<AbstractGroupedContainerE4> getGroupedContainers() {
514 List<AbstractGroupedContainerE4> groupedComposites = new ArrayList<>();
515
516 for (AbstractGroupE4 group : getAllGroups()) {
517 if (group != null) {
518 groupedComposites.addAll(group.getGroupedContainers());
519 }
520 }
521
522 return groupedComposites;
523 }
524
525 public List<AbstractGroupE4> getAllGroups() {
526 List<AbstractGroupE4> allGroups = new ArrayList<>();
527
528 allGroups.add(getAcceptedGroup());
529
530 heterotypicSynonymGroups = getHeterotypicSynonymGroups();
531
532 if (heterotypicSynonymGroups != null) {
533 allGroups.addAll(heterotypicSynonymGroups);
534 }
535
536 if (misappliedGroup != null) {
537 allGroups.add(misappliedGroup);
538 }
539
540 return allGroups;
541 }
542
543 @Override
544 public IEclipseContext getContext() {
545 return context;
546 }
547
548 @Override
549 public boolean isDirty() {
550 return dirty.isDirty();
551 }
552
553 @PreDestroy
554 public void dispose() {
555 if (conversation != null) {
556 conversation.unregisterForDataStoreChanges(this);
557 conversation.close();
558 }
559 if (input != null) {
560 input.dispose();
561 }
562 dirty.setDirty(false);
563 eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, null);
564 }
565
566 @Override
567 public void selectionChanged(IWorkbenchPart part, ISelection selection) {
568
569 }
570
571 public AbstractGroupedContainerE4 getSelectedContainer() {
572 if (selection == null && input != null){
573 selection = this.input.getTaxon();
574 }
575 return (selection != null) ? getContainer(selection) : getAcceptedNameContainer();
576 }
577
578 @Override
579 public void dragEntered() {
580 // TODO change this
581 getControl().setBackground(AbstractUtility.getColor(Resources.COLOR_DRAG_ENTER));
582 }
583
584 @Override
585 public void dragLeft() {
586 getControl().setBackground(AbstractUtility.getColor(Resources.COLOR_COMPOSITE_BACKGROUND));
587 }
588
589 public void setMisapplicationsGroup(MisappliedGroupE4 misappliedGroup) {
590 this.misappliedGroup = misappliedGroup;
591 }
592
593 public FormToolkit getToolkit() {
594 return managedForm.getToolkit();
595 }
596
597 public List<HomotypicalSynonymGroupE4> getHeterotypicSynonymGroups() {
598 return heterotypicSynonymGroups;
599 }
600
601 public void addHeterotypicSynonymGroup(HomotypicalSynonymGroupE4 group) {
602 heterotypicSynonymGroups.add(group);
603 }
604
605 public AcceptedGroupE4 getAcceptedGroup() {
606 return acceptedGroup;
607 }
608
609 public void setAcceptedGroup(AcceptedGroupE4 acceptedGroup) {
610 this.acceptedGroup = acceptedGroup;
611 }
612
613 public MisappliedGroupE4 getMisappliedGroup() {
614 return misappliedGroup;
615 }
616
617 public boolean isActive() {
618 return this.equals(AbstractUtility.getActivePart());
619 }
620
621 @Override
622 public boolean onComplete() {
623 getContainer(objectAffectedByLastOperation).setSelected();
624 return true;
625 }
626
627 @Override
628 public void partChanged(Integer eventType, IWorkbenchPartReference partRef) {
629 if (!partRef.getPart(false).equals(this)) {
630
631
632 }
633 }
634
635 public void removeGroup(AbstractGroupE4 group) {
636 if (group != null) {
637 group.dispose();
638
639 // if (heterotypicSynonymGroups != null) {
640 heterotypicSynonymGroups.remove(group);
641 // }
642 }
643 }
644
645 public AbstractGroupedContainerE4 getContainer(TaxonBase taxonBase) {
646 @SuppressWarnings("rawtypes")
647 List<AbstractGroupedContainerE4> groupedContainers = getGroupedContainers();
648 for (AbstractGroupedContainerE4<?> container : groupedContainers) {
649 if (container.getData().equals(taxonBase) && container.getNameViewer().getTextWidget() != null) {
650 return container;
651 }
652 }
653 return getAcceptedNameContainer();
654 }
655
656 public void setOnError() {
657 Color disabledColor = AbstractUtility.getColor(Resources.COLOR_EDITOR_ERROR);
658 setEnabled(false, disabledColor);
659 }
660
661 public void setDisabled() {
662 Color disabledColor = AbstractUtility.getColor(Resources.COLOR_TEXT_DISABLED_BACKGROUND);
663 setEnabled(false, disabledColor);
664 }
665
666
667
668 protected void setEnabled(boolean enabled, Color background) {
669
670 for (AbstractGroupedContainerE4<?> groupedContainer : getGroupedContainers()) {
671 groupedContainer.setEnabled(enabled);
672 }
673
674 // send an empty selection to the current provider - TODO only on error
675 // ???
676 if (!enabled) {
677 getManagedForm().setInput(null);
678
679 for (AbstractGroupedContainerE4<?> groupedContainer : getGroupedContainers()) {
680 groupedContainer.setBackground(background);
681 }
682 }
683 getControl().setBackground(background);
684 }
685
686 @Override
687 public void changed(Object element) {
688 // setDirty(true);
689 // if the attribute is null then do not set the dirty flag -> hotfix for
690 // the problem that for tasks done in service methods the changes are
691 // saved automatically
692 if (element != null) {
693 dirty.setDirty(true);
694 // refresh part title
695 // TODO: refresh taxon node in taxon navigator
696 setPartName();
697 }
698
699 if (element instanceof TaxonBase) {
700 AbstractGroupedContainerE4<?> container = getContainer((TaxonBase<?>) element);
701 if (container != null) {
702 container.refresh();
703 }
704 }
705
706 if (element instanceof TaxonRelationship) {
707 AbstractGroupedContainerE4 container = getContainer(((TaxonRelationship) element).getFromTaxon());
708 if (container != null) {
709 container.refresh();
710 }
711 }
712 }
713
714 public void setPartName() {
715 // FIXME: temporary fix for #6437 to avoid outdated title caches
716 thisPart.setLabel(this.taxon.getName().generateFullTitle());
717 // thisPart.setLabel(this.taxon.getName().getFullTitleCache());
718 }
719
720 @Override
721 public void forceDirty() {
722 setDirty();
723 }
724
725 public IUndoContext getUndoContext() {
726 return undoContext;
727 }
728
729 @Override
730 public Composite getControl() {
731 return managedForm.getForm().getBody();
732 }
733
734 public EMenuService getMenuService() {
735 return menuService;
736 }
737
738 public ESelectionService getSelectionService() {
739 return selService;
740 }
741
742 @Override
743 public boolean canAttachMedia() {
744 return true;
745 }
746
747 public TaxonEditorInputE4 getEditorInput() {
748 return input;
749 }
750
751 @Override
752 public TaxonNameEditorE4 getEditor() {
753 return this;
754 }
755
756 @Inject
757 @Optional
758 private void updateView(@UIEventTopic(WorkbenchEventConstants.REFRESH_NAME_EDITOR) CdmBase cdmbase) {
759
760 if(this.taxon != null && (this.taxon.equals(cdmbase)
761 || (this.taxon.getName() != null && this.taxon.getName().equals(cdmbase)))) {
762 this.redraw(false, true, true, true);
763 this.setDirty();
764 if (cdmbase instanceof TaxonBase) {
765 this.selection = (TaxonBase) cdmbase;
766 }
767
768 }
769 }
770
771 @Inject
772 @Optional
773 private void updateView(@UIEventTopic(WorkbenchEventConstants.REFRESH_NAME_EDITOR) List<CdmBase> cdmBases) {
774
775 for (CdmBase cdmBase: cdmBases){
776 if (cdmBase instanceof Taxon || cdmBase instanceof TaxonName){
777 if (this.taxon != null && (this.taxon.equals(cdmBase)
778 || (this.taxon.getName() != null && this.taxon.getName().equals(cdmBase)))) {
779 update();
780 }
781 }
782 }
783 }
784
785 @Inject
786 @Optional
787 private void updateView(@UIEventTopic(WorkbenchEventConstants.REFRESH_NAME_EDITOR) UUID cdmbaseUuid) {
788 if (this.taxon.getUuid().equals(cdmbaseUuid)) {
789 TaxonEditorInputE4 input = TaxonEditorInputE4.NewInstanceFromTaxonBase(cdmbaseUuid);
790 init(input);
791 }
792 }
793
794 @Inject
795 @Optional
796 private void updatefromDelete(@UIEventTopic(WorkbenchEventConstants.DELETE_DERIVATIVE) DeleteResult result) {
797 if (taxon.getName() == null) {
798 return;
799 }
800 Set<DerivedUnit> typeDesignationSpecimens = new HashSet<>();
801 this.taxon.getName().getSpecimenTypeDesignations()
802 .forEach(designation -> typeDesignationSpecimens.add(designation.getTypeSpecimen()));
803 // check if any deleted object was a type specimen
804 if (result.getUpdatedObjects().stream()
805 // filter only DerivedUnits
806 .filter(cdmBase -> cdmBase.isInstanceOf(DerivedUnit.class))
807 // deproxy from CdmBase to DerivedUnit
808 .map(unit -> HibernateProxyHelper.deproxy(unit, DerivedUnit.class))
809 // check for match in type designations
810 .anyMatch(unit -> typeDesignationSpecimens.contains(unit))) {
811 EditorUtil.updateEditor(this.input.getTaxonNode(), this);
812
813 }
814
815 }
816
817 @Override
818 public void update() {
819 EPartService partService = TaxeditorEditorPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getService(EPartService.class);
820 EModelService modelService = TaxeditorEditorPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getService(EModelService.class);
821 EditorUtil.openTaxonBaseE4(this.getTaxon().getUuid(), modelService, partService, application);
822 }
823
824 @Override
825 public TaxonNode getTaxonNode() {
826 return input.getTaxonNode();
827 }
828 }