commit 725d1ff22626d3b584606a29756c4be7c750aca1
Author: Andreas Kohlbecker <a.kohlbecker@bgbm.org>
Date:   Wed Jul 4 15:06:36 2018 +0200

    fix #7528 indroducing RegistrationStatusSelect to allow setting the status in the RegistrationWorkingsetEditor

diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/component/CdmBeanItemContainerFactory.java b/src/main/java/eu/etaxonomy/cdm/vaadin/component/CdmBeanItemContainerFactory.java
index 826fb733..e0e3c3a7 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/component/CdmBeanItemContainerFactory.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/component/CdmBeanItemContainerFactory.java
@@ -19,6 +19,7 @@ import eu.etaxonomy.cdm.api.application.CdmRepository;
 import eu.etaxonomy.cdm.api.service.pager.Pager;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
+import eu.etaxonomy.cdm.model.common.IEnumTerm;
 import eu.etaxonomy.cdm.model.common.TermType;
 import eu.etaxonomy.cdm.model.common.TermVocabulary;
 import eu.etaxonomy.cdm.persistence.query.OrderHint;
@@ -112,5 +113,16 @@ public class CdmBeanItemContainerFactory {
         return buildBeanItemContainer(type, null);
     }
 
+    /**
+     * @param values
+     * @return
+     */
+    public <T extends IEnumTerm<T>> BeanItemContainer<T> buildBeanItemContainer(Class<T> termType, T ... enumTerms) {
+        BeanItemContainer<T> termItemContainer = new BeanItemContainer<>(termType);
+        List<T> termList = Arrays.asList(enumTerms);
+        termItemContainer.addAll(termList);
+        return termItemContainer;
+    }
+
 
 }
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/component/registration/RegistrationStatusFieldInstantiator.java b/src/main/java/eu/etaxonomy/cdm/vaadin/component/registration/RegistrationStatusFieldInstantiator.java
new file mode 100644
index 00000000..aec0e687
--- /dev/null
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/component/registration/RegistrationStatusFieldInstantiator.java
@@ -0,0 +1,26 @@
+/**
+* Copyright (C) 2018 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.vaadin.component.registration;
+
+import java.io.Serializable;
+
+import com.vaadin.ui.AbstractField;
+
+import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
+
+/**
+ * @author a.kohlbecker
+ * @since Jul 4, 2018
+ *
+ */
+public interface RegistrationStatusFieldInstantiator<T> extends Serializable {
+
+    public AbstractField<T> create(RegistrationDTO regDto);
+
+}
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/component/registration/RegistrationStatusSelect.java b/src/main/java/eu/etaxonomy/cdm/vaadin/component/registration/RegistrationStatusSelect.java
new file mode 100644
index 00000000..9f67610b
--- /dev/null
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/component/registration/RegistrationStatusSelect.java
@@ -0,0 +1,89 @@
+/**
+* Copyright (C) 2018 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.vaadin.component.registration;
+
+import java.util.Collection;
+
+import com.vaadin.data.Container;
+import com.vaadin.ui.ListSelect;
+
+import eu.etaxonomy.cdm.model.name.RegistrationStatus;
+
+/**
+ * @author a.kohlbecker
+ * @since Jul 4, 2018
+ *
+ */
+public class RegistrationStatusSelect extends ListSelect {
+
+
+    private static final long serialVersionUID = 2400974680207121417L;
+
+    Object previousValue = null;
+
+    public RegistrationStatusSelect(){
+        super();
+        init();
+    }
+
+    /**
+     * @param caption
+     * @param options
+     */
+    public RegistrationStatusSelect(String caption, Collection<?> options) {
+        super(caption, options);
+        init();
+    }
+
+    /**
+     * @param caption
+     * @param dataSource
+     */
+    public RegistrationStatusSelect(String caption, Container dataSource) {
+        super(caption, dataSource);
+        init();
+    }
+
+    /**
+     * @param caption
+     */
+    public RegistrationStatusSelect(String caption) {
+        super(caption);
+        init();
+    }
+
+    /**
+     *
+     */
+    public void init() {
+        addStyleName("registration-status");
+        setRows(1);
+        setWidth("110px");
+
+        addValueChangeListener(e -> updateStyles());
+    }
+
+
+    /**
+     * @param newValue
+     * @param previousValue
+     */
+    public void updateStyles() {
+        Object newValue = getValue();
+        String styles = getStyleName();
+        if(previousValue != null){
+            styles = styles.replace("registration-status-" + ((RegistrationStatus)previousValue).name(), "");
+        }
+        if(newValue != null){
+            setStyleName(styles + " registration-status-" + ((RegistrationStatus)newValue).name());
+        }
+        previousValue = newValue;
+    }
+
+}
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 de392405..d811740e 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
@@ -11,7 +11,9 @@ package eu.etaxonomy.cdm.vaadin.view.registration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.Stack;
 import java.util.UUID;
@@ -26,6 +28,7 @@ import org.vaadin.spring.events.annotation.EventBusListenerMethod;
 import com.vaadin.server.SystemError;
 import com.vaadin.spring.annotation.SpringComponent;
 import com.vaadin.spring.annotation.ViewScope;
+import com.vaadin.ui.AbstractField;
 import com.vaadin.ui.Button;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.UI;
@@ -34,6 +37,7 @@ import com.vaadin.ui.Window;
 
 import eu.etaxonomy.cdm.api.service.INameService;
 import eu.etaxonomy.cdm.api.service.IRegistrationService;
+import eu.etaxonomy.cdm.api.service.config.RegistrationStatusTransitions;
 import eu.etaxonomy.cdm.api.service.dto.EntityReference;
 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
 import eu.etaxonomy.cdm.api.service.dto.TypedEntityReference;
@@ -59,7 +63,10 @@ import eu.etaxonomy.cdm.persistence.query.MatchMode;
 import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
 import eu.etaxonomy.cdm.service.CdmStore;
 import eu.etaxonomy.cdm.service.IRegistrationWorkingSetService;
+import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
+import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
+import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
 import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
 import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
@@ -209,6 +216,42 @@ public class RegistrationWorkingsetPresenter extends AbstractPresenter<Registrat
     @Override
     public void handleViewEntered() {
         super.handleViewEntered();
+        // TODO currently cannot specify type more precisely, see AbstractSelect
+        // FIXME externalize into class file!!!!!!!!!!!!
+        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
+
+            private static final long serialVersionUID = 7099181280977511048L;
+
+            @Override
+            public AbstractField<Object> create(RegistrationDTO regDto) {
+
+                CdmBeanItemContainerFactory selectFieldFactory = new CdmBeanItemContainerFactory(getRepo());
+                // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
+                UserHelper userHelper = UserHelper.fromSession();
+                Set<RegistrationStatus> availableStatus = new HashSet<>();
+
+                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
+                availableStatus.add(regDto.getStatus());
+                if(canChangeStatus){
+                    if(userHelper.userIsAdmin()){
+                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
+                    } else {
+                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
+                    }
+                }
+
+                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
+                        RegistrationStatus.class,
+                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
+                        );
+                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
+                select.setEnabled(canChangeStatus);
+                select.setNullSelectionAllowed(false);
+                return select;
+            }
+
+
+        });
         loadWorkingSet(getView().getCitationUuid());
         applyWorkingset();
 
@@ -296,6 +339,18 @@ public class RegistrationWorkingsetPresenter extends AbstractPresenter<Registrat
         }
     }
 
+    private void saveRegistrationStatusChange(UUID uuid, Object value) {
+        Registration reg = getRepo().getRegistrationService().load(uuid);
+        if(value != null && value instanceof RegistrationStatus && !Objects.equals(value, reg.getStatus())){
+            reg.setStatus((RegistrationStatus)value);
+            getRegistrationStore().saveBean(reg, (AbstractView)getView());
+            refreshView(true);
+        } else {
+            // only log an error here!
+            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
+        }
+    }
+
 
     @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
     public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetView.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetView.java
index 082b7d10..77f2ee89 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetView.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetView.java
@@ -19,6 +19,7 @@ import com.vaadin.ui.Button;
 
 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
 import eu.etaxonomy.cdm.model.name.TaxonName;
+import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
 import eu.etaxonomy.cdm.vaadin.model.registration.RegistrationWorkingSet;
 import eu.etaxonomy.vaadin.mvp.ApplicationView;
 
@@ -106,5 +107,7 @@ public interface RegistrationWorkingsetView extends ApplicationView{
      */
     Map<UUID, RegistrationDetailsItem> getRegistrationItemMap();
 
+    void setStatusComponentInstantiator(RegistrationStatusFieldInstantiator statusComponentInstantiator);
+
 
 }
diff --git a/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorksetViewBean.java b/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorksetViewBean.java
index c97b2d81..21cd371f 100644
--- a/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorksetViewBean.java
+++ b/src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorksetViewBean.java
@@ -31,8 +31,10 @@ import com.vaadin.server.FontAwesome;
 import com.vaadin.server.Page;
 import com.vaadin.shared.ui.label.ContentMode;
 import com.vaadin.spring.annotation.SpringView;
+import com.vaadin.ui.AbstractField;
 import com.vaadin.ui.Alignment;
 import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
 import com.vaadin.ui.CssLayout;
 import com.vaadin.ui.GridLayout;
 import com.vaadin.ui.HorizontalLayout;
@@ -58,6 +60,7 @@ import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItemButtons;
 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItemNameAndTypeButtons;
 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItemNameAndTypeButtons.TypeDesignationWorkingSetButton;
 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItemsPanel;
+import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusLabel;
 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStyles;
 import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
@@ -135,6 +138,9 @@ public class RegistrationWorksetViewBean extends AbstractPageView<RegistrationWo
      */
     private Map<UUID, EntityReference> typifiedNamesMap = new HashMap<>();
 
+    private RegistrationStatusFieldInstantiator statusFieldInstantiator;
+
+
     public RegistrationWorksetViewBean() {
         super();
     }
@@ -386,12 +392,19 @@ public class RegistrationWorksetViewBean extends AbstractPageView<RegistrationWo
                 );
         messageButton.setStyleName(ValoTheme.BUTTON_TINY);
 
-        RegistrationStatusLabel stateLabel = new RegistrationStatusLabel().update(dto.getStatus());
+        Component statusComponent;
+        if(statusFieldInstantiator != null){
+            AbstractField<Object> statusField = statusFieldInstantiator.create(dto);
+            statusField.setValue(dto.getStatus());
+            statusComponent = statusField;
+        } else {
+            statusComponent = new RegistrationStatusLabel().update(dto.getStatus());
+        }
         Label submitterLabel = new Label(dto.getSubmitterUserName());
         submitterLabel.setStyleName(LABEL_NOWRAP + " submitter");
         submitterLabel.setIcon(FontAwesome.USER);
         submitterLabel.setContentMode(ContentMode.HTML);
-        CssLayout stateAndSubmitter = new CssLayout(stateLabel, submitterLabel);
+        CssLayout stateAndSubmitter = new CssLayout(statusComponent, submitterLabel);
 
 
         if(UserHelper.fromSession().userIsRegistrationCurator() || UserHelper.fromSession().userIsAdmin()) {
@@ -588,4 +601,13 @@ public class RegistrationWorksetViewBean extends AbstractPageView<RegistrationWo
     }
 
 
+    /**
+     * @param statusFieldInstantiator the statusFieldInstantiator to set
+     */
+    @Override
+    public void setStatusComponentInstantiator(RegistrationStatusFieldInstantiator statusComponentInstantiator) {
+        this.statusFieldInstantiator = statusComponentInstantiator;
+    }
+
+
 }
diff --git a/src/main/webapp/VAADIN/themes/edit-valo/edit-valo.scss b/src/main/webapp/VAADIN/themes/edit-valo/edit-valo.scss
index c11e652a..349c5630 100644
--- a/src/main/webapp/VAADIN/themes/edit-valo/edit-valo.scss
+++ b/src/main/webapp/VAADIN/themes/edit-valo/edit-valo.scss
@@ -74,7 +74,7 @@ $v-component-group-spacing: 6px;
 }
 
 // ========================================== //
-// Status colors for the redistration
+// Status colors for the registration
 // 
 // change-color cant be used since this is not fully supported by the vaadin sass-compiler
 // see https://github.com/vaadin/sass-compiler/issues/147
@@ -88,6 +88,43 @@ $status-published-color: adjust-color($plain-red, $hue: 105deg);
 $status-ready-color: adjust-color($plain-red, $hue: 180deg);
 // ========================================== //
 
+@mixin registration-status-colors($sub-selector: '') {
+    .registration-status-REJECTED #{$sub-selector} {
+        color: $status-rejected-color;
+    }
+    .registration-status-CURATION #{$sub-selector} {
+        color: $status-curation-color;
+    }
+    .registration-status-PREPARATION #{$sub-selector} {
+        color: $status-preparation-color;
+    }
+    .registration-status-PUBLISHED #{$sub-selector} {
+        color: $status-published-color;
+    }
+    .registration-status-READY #{$sub-selector} {
+        color: $status-ready-color;
+    }
+}
+
+@mixin registration-status-bg-colors($sub-selector: '') {
+    .bg-status-REJECTED #{$sub-selector} {
+        background-color: $status-rejected-color;
+    }
+    .bg-status-CURATION #{$sub-selector} {
+        background-color: $status-curation-color;
+    }
+    .bg-status-PREPARATION #{$sub-selector}  {
+        background-color: $status-preparation-color;
+    }
+    .bg-status-PUBLISHED #{$sub-selector} {
+        background-color: $status-published-color;
+    }
+    .bg-status-READY #{$sub-selector} {
+        background-color: $status-ready-color;
+    }
+}
+
+
 
 @mixin edit-valo {
   @include valo;
@@ -361,38 +398,10 @@ $status-ready-color: adjust-color($plain-red, $hue: 180deg);
         display: block;
     }
     
-   // status colors --------------------------------- //
-    .registration-status-REJECTED {
-        color: $status-rejected-color;
-    }
-    .registration-status-CURATION {
-        color: $status-curation-color;
-    }
-    .registration-status-PREPARATION {
-        color: $status-preparation-color;
-    }
-    .registration-status-PUBLISHED {
-        color: $status-published-color;
-    }
-    .registration-status-READY {
-        color: $status-ready-color;
-    }
-
-    .bg-status-REJECTED {
-        background-color: $status-rejected-color;
-    }
-    .bg-status-CURATION {
-        background-color: $status-curation-color;
-    }
-    .bg-status-PREPARATION {
-        background-color: $status-preparation-color;
-    }
-    .bg-status-PUBLISHED {
-        background-color: $status-published-color;
-    }
-    .bg-status-READY {
-        background-color: $status-ready-color;
-    }
+   @include registration-status-colors();
+   @include registration-status-bg-colors(); // TODO still needed?
+   @include registration-status-colors(.v-select-select);
+   
     // ----------------------------------------------- //
     
     #registration-list {
@@ -405,7 +414,7 @@ $status-ready-color: adjust-color($plain-red, $hue: 180deg);
         border: valo-border($border: $v-border, $color: $v-background-color, $strength: 1.4);
         border-radius: $v-border-radius - first-number($v-border) $v-border-radius - first-number($v-border) 0 0;
         /* ----------------------------------------------- */
-        
+        // TODO can the mixin registration-status-colors() be used here?
         // for grid rows
         .status-REJECTED {
             color: $status-rejected-color;
