commit e90e4ec3d22b5e30ca2d422c31f052b79ec9fc36
Author: Andreas Kohlbecker <a.kohlbecker@bgbm.org>
Date:   Fri Apr 6 13:45:15 2018 +0200

    ref #7344 new TaxonNameEditor mode to allow autofilling of name authorship fields

diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNameEditorPresenter.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNameEditorPresenter.java
index a74043c5..e2c3070e 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNameEditorPresenter.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNameEditorPresenter.java
@@ -64,7 +64,12 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
     /**
      *
      */
-    private static final List<String> BASIONYM_INIT_STRATEGY = Arrays.asList("$", "relationsFromThisName", "relationsToThisName.type", "homotypicalGroup.typifiedNames");
+    private static final List<String> BASIONYM_INIT_STRATEGY = Arrays.asList(
+            "$",
+            "relationsFromThisName",
+            "relationsToThisName.type",
+            "homotypicalGroup.typifiedNames"
+            );
 
     private static final List<String> REFERENCE_INIT_STRATEGY = Arrays.asList("authorship", "inReference.authorship", "inReference.inReference.authorship", "inReference.inReference.inReference.authorship");
 
@@ -145,17 +150,19 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
 
                 "status.type",
 
-                "combinationAuthorship",
-                "exCombinationAuthorship",
-                "basionymAuthorship",
-                "exBasionymAuthorship",
+                "combinationAuthorship.teamMembers",
+                "exCombinationAuthorship.teamMembers",
+                "basionymAuthorship.teamMembers",
+                "exBasionymAuthorship.teamMembers",
 
                 // basionyms: relationsToThisName.fromName
                 "relationsToThisName.type",
                 "relationsToThisName.fromName.rank",
-                "relationsToThisName.fromName.nomenclaturalReference.authorship",
-                "relationsToThisName.fromName.nomenclaturalReference.inReference.authorship",
-                "relationsToThisName.fromName.nomenclaturalReference.inReference.inReference.inReference.authorship",
+                "relationsToThisName.fromName.combinationAuthorship.teamMembers",
+                "relationsToThisName.fromName.exCombinationAuthorship.teamMembers",
+                "relationsToThisName.fromName.nomenclaturalReference.authorship.teamMembers",
+                "relationsToThisName.fromName.nomenclaturalReference.inReference.authorship.teamMembers",
+                "relationsToThisName.fromName.nomenclaturalReference.inReference.inReference.inReference.authorship.teamMembers",
                 "relationsToThisName.fromName.relationsToThisName",
                 "relationsToThisName.fromName.relationsFromThisName",
 
@@ -172,7 +179,7 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
             taxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
         }
 
-        if(getView().isModeEnabled(TaxonNamePopupEditorMode.nomenclaturalReferenceSectionEditingOnly)){
+        if(getView().isModeEnabled(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY)){
             if(taxonName.getNomenclaturalReference() != null){
                 Reference nomRef = (Reference)taxonName.getNomenclaturalReference();
                 //getView().getNomReferenceCombobox().setEnabled(nomRef.isOfType(ReferenceType.Section));
@@ -331,6 +338,7 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
                 // so re reload it using the uuid since new beans might not have an Id at this point.
                 // modifiedReference = getRepo().getReferenceService().load(modifiedReference.getUuid(), Arrays.asList("inReference"));
                 getView().getNomReferenceCombobox().reload(); // refreshSelectedValue(modifiedReference);
+
             }
 
             referenceEditorPopup = null;
@@ -340,6 +348,7 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
                 // TaxonName modifiedTaxonName = basionymNamePopup.getBean();
                 // modifiedTaxonName = getRepo().getNameService().load(modifiedTaxonName.getUuid(), BASIONYM_INIT_STRATEGY);
                 ((ReloadableSelect)basionymSourceField).reload();
+                getView().updateAuthorshipFields();
 
             }
             if(event.getReason() == Reason.DELETE){
@@ -365,7 +374,7 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
         basionymNamePopup.withDeleteButton(true);
         getView().getModesActive().stream()
                 .filter(
-                        m -> !TaxonNamePopupEditorMode.nomenclaturalReferenceSectionEditingOnly.equals(m))
+                        m -> !TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY.equals(m))
                 .forEach(m -> basionymNamePopup.enableMode(m));
         basionymNamePopup.loadInEditor(event.getEntityId());
         basionymNamePopup.getBasionymToggle().setVisible(false);
@@ -386,7 +395,7 @@ public class TaxonNameEditorPresenter extends AbstractCdmEditorPresenter<TaxonNa
         basionymNamePopup.withDeleteButton(true);
         getView().getModesActive().stream()
                 .filter(
-                        m -> !TaxonNamePopupEditorMode.nomenclaturalReferenceSectionEditingOnly.equals(m))
+                        m -> !TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY.equals(m))
                 .forEach(m -> basionymNamePopup.enableMode(m));
         basionymNamePopup.loadInEditor(null);
         basionymNamePopup.getBasionymToggle().setVisible(false);
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditor.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditor.java
index 3cc4bd85..8d437dd8 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditor.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditor.java
@@ -17,6 +17,7 @@ import org.springframework.security.core.GrantedAuthority;
 
 import com.vaadin.shared.ui.label.ContentMode;
 import com.vaadin.spring.annotation.SpringComponent;
+import com.vaadin.ui.AbstractField;
 import com.vaadin.ui.Alignment;
 import com.vaadin.ui.CheckBox;
 import com.vaadin.ui.GridLayout;
@@ -24,6 +25,7 @@ import com.vaadin.ui.Label;
 import com.vaadin.ui.ListSelect;
 import com.vaadin.ui.TextField;
 
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.name.Rank;
 import eu.etaxonomy.cdm.model.name.TaxonName;
@@ -94,6 +96,12 @@ public class TaxonNamePopupEditor extends AbstractCdmPopupEditor<TaxonName, Taxo
 
     private EnumSet<TaxonNamePopupEditorMode> modesActive = EnumSet.noneOf(TaxonNamePopupEditorMode.class);
 
+    private Boolean isInferredCombinationAuthorship = null;
+
+    private Boolean isInferredBasionymAuthorship = null;
+
+    private Boolean isInferredExBasionymAuthorship = null;
+
     /**
      * @param layout
      * @param dtoType
@@ -217,6 +225,7 @@ public class TaxonNamePopupEditor extends AbstractCdmPopupEditor<TaxonName, Taxo
         basionymToggle.setValue(HAS_BASIONYM_DEFAULT);
         basionymToggle.addValueChangeListener(e -> {
                 updateFieldVisibility();
+                updateAuthorshipFields();
             });
         basionymToggle.setStyleName(getDefaultComponentStyles());
         grid.addComponent(basionymToggle, 2, row, 3, row);
@@ -323,45 +332,45 @@ public class TaxonNamePopupEditor extends AbstractCdmPopupEditor<TaxonName, Taxo
 
         setAdvancedModeEnabled(true);
         registerAdvancedModeComponents(fullTitleCacheFiled, protectedNameCacheField);
-        registerAdvancedModeComponents(basionymAuthorshipField.getCachFields());
-        registerAdvancedModeComponents(exBasionymAuthorshipField.getCachFields());
+
+        registerAdvancedModeComponents(combinationAuthorshipField);
+        registerAdvancedModeComponents(basionymAuthorshipField);
+        registerAdvancedModeComponents(exBasionymAuthorshipField);
+
         registerAdvancedModeComponents(combinationAuthorshipField.getCachFields());
         registerAdvancedModeComponents(exCombinationAuthorshipField.getCachFields());
+        registerAdvancedModeComponents(basionymAuthorshipField.getCachFields());
+        registerAdvancedModeComponents(exBasionymAuthorshipField.getCachFields());
+
         setAdvancedMode(false);
 
     }
 
-    /**
-     * @param rank
-     * @return
-     */
-    private void updateFieldVisibility() {
-
-        // TODO use getField() instead and remove field references
-
-        TaxonName taxonName = getBean();
-        Rank rank = taxonName.getRank();
-
-        boolean isSpeciesOrBelow = !rank.isHigher(Rank.SPECIES());
-        Boolean withBasionym = BooleanUtils.isTrue(basionymToggle.getValue());
-        Boolean withValidation = BooleanUtils.isTrue(validationToggle.getValue());
-
-        basionymAuthorshipField.setVisible(withBasionym != null && withBasionym);
-        exBasionymAuthorshipField.setVisible(withBasionym);
-        basionymsComboboxSelect.setVisible(withBasionym);
-
-        if(taxonName != null){
-            if(modesActive.contains(TaxonNamePopupEditorMode.suppressReplacementAuthorshipData)){
-                basionymAuthorshipField.setVisible(taxonName.getBasionymAuthorship() != null);
-                exBasionymAuthorshipField.setVisible(taxonName.getExBasionymAuthorship() != null);
+    protected TeamOrPersonBase inferBasiomynAuthors(TaxonName taxonName) {
+        TaxonName basionym = taxonName.getBasionym();
+        if(basionym != null){
+            if(basionym.getCombinationAuthorship() != null){
+                return basionym.getCombinationAuthorship();
+            } else if(basionym.getNomenclaturalReference() != null){
+                return basionym.getNomenclaturalReference().getAuthorship();
             }
         }
+        return null;
+    }
 
-        infraSpecificEpithetField.setVisible(rank.isInfraSpecific());
-        specificEpithetField.setVisible(isSpeciesOrBelow);
-        infraGenericEpithetField.setVisible(rank.isInfraGenericButNotSpeciesGroup());
-        genusOrUninomialField.setCaption(isSpeciesOrBelow ? "Genus" : "Uninomial");
-        exCombinationAuthorshipField.setVisible(isSpeciesOrBelow && withValidation);
+    protected TeamOrPersonBase inferExBasiomynAuthors(TaxonName taxonName) {
+        TaxonName basionym = taxonName.getBasionym();
+        if(basionym != null){
+                return basionym.getExCombinationAuthorship();
+        }
+        return null;
+    }
+
+    protected TeamOrPersonBase inferCombinationAuthors(TaxonName taxonName) {
+        if(taxonName.getNomenclaturalReference() != null) {
+            return taxonName.getNomenclaturalReference().getAuthorship();
+        }
+        return null;
     }
 
     @Override
@@ -378,13 +387,13 @@ public class TaxonNamePopupEditor extends AbstractCdmPopupEditor<TaxonName, Taxo
         validationToggle.setReadOnly(showExAuthors);
         exCombinationAuthorshipField.setVisible(showExAuthors);
 
-        if(isModeEnabled(TaxonNamePopupEditorMode.suppressReplacementAuthorshipData)){
-            combinationAuthorshipField.setVisible(taxonName.getCombinationAuthorship() != null);
+        if(isModeEnabled(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA)){
+            updateAuthorshipFields();
         }
-        if(isModeEnabled(TaxonNamePopupEditorMode.nomenclaturalReferenceSectionEditingOnly) && getBean().getNomenclaturalReference() != null) {
+        if(isModeEnabled(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY) && getBean().getNomenclaturalReference() != null) {
             nomReferenceCombobox.setCaption("Selection limited to nomenclatural reference and sections");
         }
-        if(isModeEnabled(TaxonNamePopupEditorMode.requireNomenclaturalReference)) {
+        if(isModeEnabled(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE)) {
             if(combinationAuthorshipField.getValue() == null){
                 nomReferenceCombobox.setRequired(true);
             } else {
@@ -398,6 +407,119 @@ public class TaxonNamePopupEditor extends AbstractCdmPopupEditor<TaxonName, Taxo
 
     }
 
+    /**
+     * @param taxonName
+     */
+    @Override
+    public void updateAuthorshipFields() {
+
+        TaxonName taxonName = getBean();
+
+        // ------------- CombinationAuthors
+        isInferredCombinationAuthorship = updateAuthorshipField(
+                taxonName.getCombinationAuthorship(),
+                inferCombinationAuthors(taxonName),
+                combinationAuthorshipField,
+                nomReferenceCombobox.getSelect(),
+                isInferredCombinationAuthorship);
+
+
+        // ------------- Basionym and ExBasionymAuthors
+        if(BooleanUtils.isTrue(basionymToggle.getValue())){
+
+            isInferredBasionymAuthorship = updateAuthorshipField(
+                    taxonName.getBasionymAuthorship(),
+                    inferBasiomynAuthors(taxonName),
+                    basionymAuthorshipField,
+                    basionymsComboboxSelect,
+                    isInferredBasionymAuthorship
+                    );
+
+            isInferredExBasionymAuthorship = updateAuthorshipField(
+                    taxonName.getExBasionymAuthorship(),
+                    inferExBasiomynAuthors(taxonName),
+                    exBasionymAuthorshipField,
+                    //no point adding the basionymsComboboxSelect again, it has bee registered already for the BasionymAuthorship above
+                    null,
+                    isInferredExBasionymAuthorship
+                    );
+        }
+    }
+
+    /**
+     *
+     * @param authorship
+     *    the value of the taxonName authorship field
+     * @param inferredAuthors
+     *    the value inferred from other fields which may be set as authorship to the taxon name
+     * @param authorshipField
+     *    the ui element to edit the taxonName authorship field
+     * @param updateTriggerField
+     * @param lastInferredAuthorshipState
+     * @return
+     */
+    protected Boolean updateAuthorshipField(TeamOrPersonBase<?> authorship, TeamOrPersonBase inferredAuthors,
+            TeamOrPersonField authorshipField, AbstractField updateTriggerField,
+            Boolean lastInferredAuthorshipState) {
+
+        if(authorship == null){
+            authorshipField.setValue(inferredAuthors);
+            lastInferredAuthorshipState = true;
+        } else {
+            boolean authorshipMatch = authorship == inferredAuthors;
+            if(lastInferredAuthorshipState == null){
+                // initialization of isInferredCombinationAuthorship in case the editor is just being initialized
+                lastInferredAuthorshipState = authorshipMatch;
+                if(updateTriggerField != null){
+                    // IMPORTANT!
+                    // this ChangeListener must be added at this very late point in the editor lifecycle so that it is called after
+                    // the ToOneRelatedEntityReloader which may have been added to the updateTriggerField in the presenters handleViewEntered() method.
+                    // Otherwise we risk multiple representation problems in the hibernate session
+                    updateTriggerField.addValueChangeListener(e -> updateAuthorshipFields());
+                }
+            }
+            if(!authorshipMatch && lastInferredAuthorshipState){
+                // update the combinationAuthorshipField to follow changes of the nomenclatural reference in case it was autofilled before
+                authorshipField.setValue(inferredAuthors);
+                lastInferredAuthorshipState = true;
+            }
+        }
+        authorshipField.setVisible(!lastInferredAuthorshipState);
+        return lastInferredAuthorshipState;
+    }
+
+    /**
+     * @param rank
+     * @return
+     */
+    private void updateFieldVisibility() {
+
+        // TODO use getField() instead and remove field references
+
+        TaxonName taxonName = getBean();
+        Rank rank = taxonName.getRank();
+
+        boolean isSpeciesOrBelow = !rank.isHigher(Rank.SPECIES());
+        Boolean withBasionym = BooleanUtils.isTrue(basionymToggle.getValue());
+        Boolean withValidation = BooleanUtils.isTrue(validationToggle.getValue());
+
+        basionymAuthorshipField.setVisible(withBasionym != null && withBasionym);
+        exBasionymAuthorshipField.setVisible(withBasionym);
+        basionymsComboboxSelect.setVisible(withBasionym);
+
+        if(taxonName != null){
+            if(modesActive.contains(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA)){
+                updateAuthorshipFields();
+            }
+        }
+
+        infraSpecificEpithetField.setVisible(rank.isInfraSpecific());
+        specificEpithetField.setVisible(isSpeciesOrBelow);
+        infraGenericEpithetField.setVisible(rank.isInfraGenericButNotSpeciesGroup());
+        genusOrUninomialField.setCaption(isSpeciesOrBelow ? "Genus" : "Uninomial");
+        exCombinationAuthorshipField.setVisible(isSpeciesOrBelow && withValidation);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorMode.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorMode.java
index 21301bd7..e12bde48 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorMode.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorMode.java
@@ -19,7 +19,7 @@ public enum TaxonNamePopupEditorMode {
      * CombinationAuthorship BasionymAuthorship fields only visible if
      * not empty
      */
-    suppressReplacementAuthorshipData,
+    AUTOFILL_AUTHORSHIP_DATA,
 
     /**
      * Editing of the nomenclatural reference is limited to editing the sub section of the
@@ -29,13 +29,13 @@ public enum TaxonNamePopupEditorMode {
      * section can be edited via a ReferencePopupEditor.
      *
      */
-    nomenclaturalReferenceSectionEditingOnly,
+    NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY,
 
     /**
      * setting the nomenclatural reference is required with the exception
      * that existing data is considered complete if the combination
      * authors are set.
      */
-    requireNomenclaturalReference
+    REQUIRE_NOMENCLATURALREFERENCE
 
 }
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorView.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorView.java
index dcc5a192..2c71e4dc 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorView.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditorView.java
@@ -10,9 +10,12 @@ package eu.etaxonomy.cdm.vaadin.view.name;
 
 import java.util.EnumSet;
 
+import org.apache.commons.lang3.BooleanUtils;
+
 import com.vaadin.ui.CheckBox;
 import com.vaadin.ui.ListSelect;
 
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
 import eu.etaxonomy.cdm.model.name.TaxonName;
 import eu.etaxonomy.cdm.model.reference.Reference;
 import eu.etaxonomy.cdm.vaadin.component.common.TeamOrPersonField;
@@ -81,4 +84,6 @@ public interface TaxonNamePopupEditorView extends ApplicationView<TaxonNameEdito
      */
     CheckBox getBasionymToggle();
 
+    void updateAuthorshipFields();
+
 }
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetPresenter.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetPresenter.java
index fdff89cf..be7600c2 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetPresenter.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetPresenter.java
@@ -75,6 +75,7 @@ import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
 import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorMode;
+import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorView;
 import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
 import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
 import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
@@ -365,10 +366,10 @@ public class RegistrationWorkingsetPresenter extends AbstractPresenter<Registrat
      *
      * @param popup
      */
-    protected void configureTaxonNameEditor(TaxonNamePopupEditor popup) {
-        popup.enableMode(TaxonNamePopupEditorMode.suppressReplacementAuthorshipData);
-        popup.enableMode(TaxonNamePopupEditorMode.nomenclaturalReferenceSectionEditingOnly);
-        popup.enableMode(TaxonNamePopupEditorMode.requireNomenclaturalReference);
+    protected void configureTaxonNameEditor(TaxonNamePopupEditorView popup) {
+        popup.enableMode(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA);
+        popup.enableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
+        // popup.enableMode(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE);
     }
 
     /**
