From 422d81609362de1fdd0c8a7d95e84ad89ced9d17 Mon Sep 17 00:00:00 2001
From: anhefti <andreas.hefti@let.ethz.ch>
Date: Thu, 21 Feb 2019 17:00:42 +0100
Subject: [PATCH] SEBSERV-27 User Account Form language and Time Zone selector

---
 .../ch/ethz/seb/sebserver/gbl/Constants.java  |   2 +
 .../seb/sebserver/gbl/api/APIMessage.java     |   4 +
 .../seb/sebserver/gbl/model/EntityKey.java    |  13 +-
 .../sebserver/gbl/model/user/UserAccount.java |  11 +-
 .../sebserver/gbl/model/user/UserInfo.java    |  14 +-
 .../seb/sebserver/gbl/model/user/UserMod.java |  23 +-
 .../seb/sebserver/gui/RAPConfiguration.java   |   8 +-
 .../seb/sebserver/gui/service/form/Form.java  |  44 +-
 .../gui/service/form/FormBuilder.java         | 395 ++++++++++++------
 .../gui/service/form/FormHandle.java          |  29 +-
 .../gui/service/i18n/I18nSupport.java         |  40 ++
 .../gui/service/page/PageContext.java         |   2 +
 .../sebserver/gui/service/page/PageUtils.java |  67 +++
 .../gui/service/page/action/Action.java       |  11 +
 .../page/action/UserAccountActions.java       |  53 ++-
 .../page/activity/ActivitySelection.java      |   3 +-
 .../service/page/content/InstitutionForm.java |  62 +--
 .../service/page/content/UserAccountForm.java | 132 +++++-
 .../service/page/impl/PageContextImpl.java    |  11 +
 .../remote/webservice/api/FormBinding.java    |   4 +-
 .../remote/webservice/api/RestCall.java       |  10 +-
 .../remote/webservice/api/RestCallError.java  |   8 +
 .../gui/service/table/TableFilter.java        |  12 +-
 .../gui/service/widget/LanguageSelector.java  |  55 ---
 .../gui/service/widget/SingleSelection.java   |   7 +
 .../gui/service/widget/WidgetFactory.java     |  85 +---
 .../servicelayer/dao/impl/UserDaoImpl.java    |   2 +-
 src/main/resources/messages.properties        |  19 +-
 28 files changed, 772 insertions(+), 354 deletions(-)
 create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java
 delete mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/widget/LanguageSelector.java

diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java
index a36e1277..23360ad3 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java
@@ -17,6 +17,8 @@ public final class Constants {
     public static final Character LIST_SEPARATOR_CHAR = ',';
     public static final String LIST_SEPARATOR = ",";
     public static final String EMPTY_NOTE = "--";
+    public static final String FORM_URL_ENCODED_SEPARATOR = "&";
+    public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = "=";
 
     /** Date-Time formatter without milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss */
     public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java
index b3a91f61..5db80b43 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java
@@ -54,6 +54,10 @@ public class APIMessage implements Serializable {
             this.systemMessage = systemMessage;
         }
 
+        public boolean isOf(final APIMessage message) {
+            return message != null && this.messageCode.equals(message.messageCode);
+        }
+
         public APIMessage of() {
             return new APIMessage(this.messageCode, this.systemMessage);
         }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java
index 978c8085..7c3f0482 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java
@@ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.gbl.model;
 import javax.validation.constraints.NotNull;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 import ch.ethz.seb.sebserver.gbl.api.EntityType;
@@ -24,20 +23,21 @@ public class EntityKey {
     @JsonProperty(value = "entityType", required = true)
     @NotNull
     public final EntityType entityType;
-    @JsonIgnore
-    public final boolean isIdPK;
 
     @JsonCreator
     public EntityKey(
             @JsonProperty(value = "modelId", required = true) final String modelId,
             @JsonProperty(value = "entityType", required = true) final EntityType entityType) {
 
-        assert (modelId != null) : "modelId has null reference";
-        assert (entityType != null) : "entityType has null reference";
+        if (modelId == null) {
+            throw new IllegalArgumentException("modelId has null reference");
+        }
+        if (entityType == null) {
+            throw new IllegalArgumentException("entityType has null reference");
+        }
 
         this.modelId = modelId;
         this.entityType = entityType;
-        this.isIdPK = entityType != EntityType.USER;
     }
 
     public EntityKey(
@@ -46,7 +46,6 @@ public class EntityKey {
 
         this.modelId = String.valueOf(pk);
         this.entityType = entityType;
-        this.isIdPK = true;
     }
 
     public String getModelId() {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserAccount.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserAccount.java
index 2d6432ad..eab6ffcd 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserAccount.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserAccount.java
@@ -13,12 +13,18 @@ import java.util.Set;
 
 import org.joda.time.DateTimeZone;
 
-public interface UserAccount {
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
 
+public interface UserAccount extends GrantEntity {
+
+    @Override
     String getModelId();
 
+    @Override
     Long getInstitutionId();
 
+    @Override
     String getName();
 
     String getUsername();
@@ -39,4 +45,7 @@ public interface UserAccount {
 
     String getRetypedNewPassword();
 
+    @Override
+    EntityKey getEntityKey();
+
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java
index 8761e392..af9d124c 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java
@@ -17,6 +17,7 @@ import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 
 import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.joda.time.DateTimeZone;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -28,8 +29,8 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
 import ch.ethz.seb.sebserver.gbl.model.Activatable;
 import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
 import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 import ch.ethz.seb.sebserver.gbl.util.Utils;
-import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
 
 /** The user info domain model contains primary user information
  *
@@ -37,7 +38,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
  * to and from JSON within the Jackson library.
  *
  * This domain model is immutable and thread-save */
-public final class UserInfo implements UserAccount, GrantEntity, Activatable, Serializable {
+public final class UserInfo implements UserAccount, Activatable, Serializable {
 
     private static final long serialVersionUID = 2526446136264377808L;
 
@@ -197,6 +198,15 @@ public final class UserInfo implements UserAccount, GrantEntity, Activatable, Se
         return null;
     }
 
+    @JsonIgnore
+    @Override
+    public EntityKey getEntityKey() {
+        if (StringUtils.isBlank(this.uuid)) {
+            return null;
+        }
+        return new EntityKey(this.uuid, entityType());
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java
index b977265c..4178766f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java
@@ -16,9 +16,11 @@ import javax.validation.constraints.Email;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 
+import org.apache.commons.lang3.StringUtils;
 import org.joda.time.DateTimeZone;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
@@ -26,9 +28,9 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
 import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
 import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
 import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
-import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 
-public final class UserMod implements UserAccount, GrantEntity {
+public final class UserMod implements UserAccount {
 
     public static final String ATTR_NAME_NEW_PASSWORD = "newPassword";
     public static final String ATTR_NAME_RETYPED_NEW_PASSWORD = "retypedNewPassword";
@@ -71,10 +73,12 @@ public final class UserMod implements UserAccount, GrantEntity {
     @JsonProperty(USER_ROLE.REFERENCE_NAME)
     public final Set<String> roles;
 
+    @NotNull(message = "user:newPassword:notNull")
     @Size(min = 8, max = 255, message = "user:password:size:{min}:{max}:${validatedValue}")
     @JsonProperty(ATTR_NAME_NEW_PASSWORD)
     private final String newPassword;
 
+    @NotNull(message = "user:retypedNewPassword:notNull")
     @JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD)
     private final String retypedNewPassword;
 
@@ -140,9 +144,9 @@ public final class UserMod implements UserAccount, GrantEntity {
         this.name = null;
         this.username = null;
         this.email = null;
-        this.locale = null;
-        this.timeZone = null;
-        this.roles = null;
+        this.locale = Locale.ENGLISH;
+        this.timeZone = DateTimeZone.UTC;
+        this.roles = Collections.emptySet();
     }
 
     @Override
@@ -223,6 +227,15 @@ public final class UserMod implements UserAccount, GrantEntity {
         return false;
     }
 
+    @JsonIgnore
+    @Override
+    public EntityKey getEntityKey() {
+        if (StringUtils.isBlank(this.uuid)) {
+            return null;
+        }
+        return new EntityKey(this.uuid, entityType());
+    }
+
     @Override
     public String toString() {
         return "UserMod [uuid=" + this.uuid + ", institutionId=" + this.institutionId + ", name=" + this.name
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/RAPConfiguration.java b/src/main/java/ch/ethz/seb/sebserver/gui/RAPConfiguration.java
index 15a4edb4..03618e37 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/RAPConfiguration.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/RAPConfiguration.java
@@ -110,15 +110,9 @@ public class RAPConfiguration implements ApplicationConfiguration {
 
                 log.debug("Initialize Spring-Context on Servlet-Context: " + servletContext);
 
-                final WebApplicationContext cc = WebApplicationContextUtils.getRequiredWebApplicationContext(
+                return WebApplicationContextUtils.getRequiredWebApplicationContext(
                         servletContext);
 
-                if (cc == null) {
-                    log.error("Failed to initialize Spring-Context on Servlet-Context: " + servletContext);
-                    throw new RuntimeException(
-                            "Failed to initialize Spring-Context on Servlet-Context: " + servletContext);
-                }
-                return cc;
             } catch (final Exception e) {
                 log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession);
                 throw new RuntimeException("Failed to initialize Spring-Context on HttpSession: " + httpSession);
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/form/Form.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/form/Form.java
index ad30fee4..8029d5c1 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/form/Form.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/form/Form.java
@@ -23,12 +23,11 @@ import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Text;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
 
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
+import ch.ethz.seb.sebserver.gbl.Constants;
 import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
@@ -40,6 +39,7 @@ public final class Form implements FormBinding {
     private final JSONMapper jsonMapper;
     private final ObjectNode objectRoot;
 
+    private final Map<String, String> staticValues = new LinkedHashMap<>();
     private final Map<String, FormFieldAccessor> formFields = new LinkedHashMap<>();
     private final Map<String, Form> subForms = new LinkedHashMap<>();
     private final Map<String, List<Form>> subLists = new LinkedHashMap<>();
@@ -69,16 +69,17 @@ public final class Form implements FormBinding {
     }
 
     @Override
-    public MultiValueMap<String, String> getFormAsQueryAttributes() {
-        final LinkedMultiValueMap<String, String> result = new LinkedMultiValueMap<>();
-        for (final Map.Entry<String, FormFieldAccessor> entry : this.formFields.entrySet()) {
-            final String value = entry.getValue().getValue();
-            if (StringUtils.isNoneBlank(value)) {
-                result.add(entry.getKey(), value);
-            }
+    public String getFormUrlEncoded() {
+        final StringBuffer buffer = new StringBuffer();
+        for (final Map.Entry<String, String> entry : this.staticValues.entrySet()) {
+            appendFormUrlEncoded(buffer, entry.getKey(), entry.getValue());
         }
 
-        return result;
+        for (final Map.Entry<String, FormFieldAccessor> entry : this.formFields.entrySet()) {
+            appendFormUrlEncoded(buffer, entry.getKey(), entry.getValue().getValue());
+        }
+
+        return buffer.toString();
     }
 
     public String getValue(final String name) {
@@ -91,7 +92,9 @@ public final class Form implements FormBinding {
     }
 
     public void putStatic(final String name, final String value) {
-        this.objectRoot.put(name, value);
+        if (StringUtils.isNoneBlank(value)) {
+            this.staticValues.put(name, value);
+        }
     }
 
     public void addToGroup(final String groupName, final String fieldName) {
@@ -101,6 +104,10 @@ public final class Form implements FormBinding {
         }
     }
 
+    public boolean hasFields() {
+        return !this.formFields.isEmpty();
+    }
+
     public Form putField(final String name, final Label label, final Label field) {
         this.formFields.put(name, createAccessor(label, field));
         return this;
@@ -172,6 +179,10 @@ public final class Form implements FormBinding {
     }
 
     private void flush() {
+        for (final Map.Entry<String, String> entry : this.staticValues.entrySet()) {
+            this.objectRoot.put(entry.getKey(), entry.getValue());
+        }
+
         for (final Map.Entry<String, FormFieldAccessor> entry : this.formFields.entrySet()) {
             final FormFieldAccessor accessor = entry.getValue();
             if (accessor.control.isVisible()) {
@@ -229,6 +240,17 @@ public final class Form implements FormBinding {
     }
     //@formatter:on
 
+    private void appendFormUrlEncoded(final StringBuffer buffer, final String name, final String value) {
+        if (StringUtils.isNoneBlank(value)) {
+            if (buffer.length() > 0) {
+                buffer.append(Constants.FORM_URL_ENCODED_SEPARATOR);
+            }
+            buffer.append(name)
+                    .append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
+                    .append(value);
+        }
+    }
+
     public static abstract class FormFieldAccessor {
 
         public final Label label;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormBuilder.java
index 396e36a7..d811f277 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormBuilder.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormBuilder.java
@@ -12,18 +12,20 @@ import java.util.List;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 import org.apache.commons.lang3.StringUtils;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import ch.ethz.seb.sebserver.gbl.Constants;
 import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 import ch.ethz.seb.sebserver.gbl.util.Tuple;
@@ -32,6 +34,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
 import ch.ethz.seb.sebserver.gui.service.widget.ImageUpload;
+import ch.ethz.seb.sebserver.gui.service.widget.SingleSelection;
 import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
 
 public class FormBuilder {
@@ -45,6 +48,10 @@ public class FormBuilder {
     public final Form form;
 
     private boolean readonly = false;
+    private int defaultSpanLabel = 1;
+    private int defaultSpanInput = 2;
+    private int defaultSpanEmptyCell = 1;
+    private boolean emptyCellSeparation = true;
 
     FormBuilder(
             final EntityKey entityKey,
@@ -84,12 +91,47 @@ public class FormBuilder {
         return this;
     }
 
+    public FormBuilder withDefaultSpanLabel(final int span) {
+        this.defaultSpanLabel = span;
+        return this;
+    }
+
+    public FormBuilder withDefaultSpanInput(final int span) {
+        this.defaultSpanInput = span;
+        return this;
+    }
+
+    public FormBuilder withDefaultSpanEmptyCell(final int span) {
+        this.defaultSpanEmptyCell = span;
+        return this;
+    }
+
+    public FormBuilder withEmptyCellSeparation(final boolean separation) {
+        this.emptyCellSeparation = separation;
+        return this;
+    }
+
+    public FormBuilder addEmptyCellIf(final BooleanSupplier condition) {
+        if (condition != null && condition.getAsBoolean()) {
+            return addEmptyCell();
+        }
+        return this;
+    }
+
     public FormBuilder addEmptyCell() {
         return addEmptyCell(1);
     }
 
     public FormBuilder addEmptyCell(final int span) {
-        this.widgetFactory.formEmpty(this.formParent, span, 1);
+        empty(this.formParent, span, 1);
+        return this;
+    }
+
+    public FormBuilder putStaticValueIf(final BooleanSupplier condition, final String name, final String value) {
+        if (condition != null && condition.getAsBoolean()) {
+            return putStaticValue(name, value);
+        }
+
         return this;
     }
 
@@ -102,128 +144,14 @@ public class FormBuilder {
         return this;
     }
 
-    public FormBuilder addTextField(
-            final String name,
-            final String label,
-            final String value) {
-
-        return addTextField(name, label, value, 1, null);
-    }
-
-    public FormBuilder addTextField(
-            final String name,
-            final String label,
-            final String value,
-            final int span) {
-
-        return addTextField(name, label, value, span, null);
-    }
-
-    public FormBuilder addTextField(
-            final String name,
-            final String label,
-            final String value,
-            final int span,
-            final String group) {
-
-        final Label lab = this.widgetFactory.formLabelLocalized(this.formParent, label);
-        if (this.readonly) {
-            this.form.putField(name, lab, this.widgetFactory.formValueLabel(this.formParent, value, span));
-        } else {
-            this.form.putField(name, lab, this.widgetFactory.formTextInput(this.formParent, value, span, 1));
+    public FormBuilder addField(final FieldTemplate template) {
+        if (template.condition == null || template.condition.getAsBoolean()) {
+            template.spanLabel = (template.spanLabel < 0) ? this.defaultSpanLabel : template.spanLabel;
+            template.spanInput = (template.spanInput < 0) ? this.defaultSpanInput : template.spanInput;
+            template.spanEmptyCell = (template.spanEmptyCell < 0) ? this.defaultSpanEmptyCell : template.spanEmptyCell;
+            template.autoEmptyCellSeparation = template.autoEmptyCellSeparation || this.emptyCellSeparation;
+            template.build(this);
         }
-        if (StringUtils.isNoneBlank(group)) {
-            this.form.addToGroup(group, name);
-        }
-        return this;
-    }
-
-    public FormBuilder addSingleSelection(
-            final String name,
-            final String label,
-            final String value,
-            final List<Tuple<String>> items,
-            final Consumer<Form> selectionListener) {
-
-        return addSingleSelection(name, label, value, items, selectionListener, 1, null);
-    }
-
-    public FormBuilder addSingleSelection(
-            final String name,
-            final String label,
-            final String value,
-            final List<Tuple<String>> items,
-            final Consumer<Form> selectionListener,
-            final int span) {
-
-        return addSingleSelection(name, label, value, items, selectionListener, span, null);
-    }
-
-    public FormBuilder addSingleSelection(
-            final String name,
-            final String label,
-            final String value,
-            final List<Tuple<String>> items,
-            final Consumer<Form> selectionListener,
-            final int span,
-            final String group) {
-
-        final Label lab = this.widgetFactory.formLabelLocalized(this.formParent, label);
-        if (this.readonly) {
-            this.form.putField(name, lab, this.widgetFactory.formValueLabel(this.formParent, value, 2));
-        } else {
-            final Combo selection =
-                    this.widgetFactory.formSingleSelectionLocalized(this.formParent, value, items, span, 1);
-            this.form.putField(name, lab, selection);
-            if (selectionListener != null) {
-                selection.addListener(SWT.Selection, e -> {
-                    selectionListener.accept(this.form);
-                });
-            }
-        }
-        if (StringUtils.isNoneBlank(group)) {
-            this.form.addToGroup(group, name);
-        }
-        return this;
-    }
-
-    public FormBuilder addImageUploadIf(
-            final BooleanSupplier condition,
-            final String name,
-            final String label,
-            final String value,
-            final int span) {
-
-        if (condition != null && condition.getAsBoolean()) {
-            return addImageUpload(name, label, value, span);
-        }
-        return this;
-    }
-
-    public FormBuilder addImageUpload(
-            final String name,
-            final String label,
-            final String value,
-            final int span) {
-
-        return addImageUpload(name, label, value, span, null);
-    }
-
-    public FormBuilder addImageUpload(
-            final String name,
-            final String label,
-            final String value,
-            final int span,
-            final String group) {
-
-        final Label lab = this.widgetFactory.formLabelLocalized(this.formParent, label);
-        final ImageUpload imageUpload = this.widgetFactory.formImageUpload(
-                this.formParent,
-                value,
-                new LocTextKey("sebserver.overall.upload"),
-                span, 1, this.readonly);
-        this.form.putField(name, lab, imageUpload);
-
         return this;
     }
 
@@ -239,4 +167,225 @@ public class FormBuilder {
                 this.polyglotPageService.getI18nSupport());
     }
 
+    private void empty(final Composite parent, final int hspan, final int vspan) {
+        final Label empty = new Label(parent, SWT.LEFT);
+        empty.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan));
+        empty.setText("");
+    }
+
+    public static TextField text(final String name, final String label, final String value) {
+        return new TextField(name, label, value);
+    }
+
+    public static SingleSelectionField singleSelection(
+            final String name,
+            final String label,
+            final String value,
+            final Supplier<List<Tuple<String>>> itemsSupplier) {
+        return new SingleSelectionField(name, label, value, itemsSupplier);
+    }
+
+    public static ImageUploadField imageUpload(final String name, final String label, final String value) {
+        return new ImageUploadField(name, label, value);
+    }
+
+    abstract static class FieldTemplate {
+        int spanLabel = -1;
+        int spanInput = -1;
+        int spanEmptyCell = -1;
+        boolean autoEmptyCellSeparation = false;
+        String group = null;
+        BooleanSupplier condition = null;
+
+        final String name;
+        final String label;
+        final String value;
+
+        protected FieldTemplate(final String name, final String label, final String value) {
+            this.name = name;
+            this.label = label;
+            this.value = value;
+        }
+
+        public FieldTemplate withLabelSpan(final int span) {
+            this.spanLabel = span;
+            return this;
+        }
+
+        public FieldTemplate withInputSpan(final int span) {
+            this.spanInput = span;
+            return this;
+        }
+
+        public FieldTemplate withEmptyCellSpan(final int span) {
+            this.spanEmptyCell = span;
+            return this;
+        }
+
+        public FieldTemplate withEmptyCellSeparation(final boolean separation) {
+            this.autoEmptyCellSeparation = separation;
+            return this;
+        }
+
+        public FieldTemplate withGroup(final String group) {
+            this.group = group;
+            return this;
+        }
+
+        public FieldTemplate withCondition(final BooleanSupplier condition) {
+            this.condition = condition;
+            return this;
+        }
+
+        abstract void build(FormBuilder builder);
+
+    }
+
+    public static final class TextField extends FieldTemplate {
+
+        boolean isPassword = false;
+
+        TextField(final String name, final String label, final String value) {
+            super(name, label, value);
+        }
+
+        public TextField asPasswordField() {
+            this.isPassword = true;
+            return this;
+        }
+
+        @Override
+        void build(final FormBuilder builder) {
+            if (this.isPassword && builder.readonly) {
+                return;
+            }
+
+            if (this.autoEmptyCellSeparation && builder.form.hasFields()) {
+                builder.addEmptyCell(this.spanEmptyCell);
+            }
+
+            final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
+            if (builder.readonly) {
+                builder.form.putField(this.name, lab,
+                        builder.valueLabel(builder.formParent, this.value, this.spanInput));
+            } else {
+                final Text textInput = new Text(builder.formParent, (this.isPassword)
+                        ? SWT.LEFT | SWT.BORDER | SWT.PASSWORD
+                        : SWT.LEFT | SWT.BORDER);
+                final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
+                gridData.heightHint = 15;
+                textInput.setLayoutData(gridData);
+                if (this.value != null) {
+                    textInput.setText(this.value);
+                }
+                builder.form.putField(this.name, lab, textInput);
+            }
+            if (StringUtils.isNoneBlank(this.group)) {
+                builder.form.addToGroup(this.group, this.name);
+            }
+        }
+    }
+
+    public static final class SingleSelectionField extends FieldTemplate {
+
+        final Supplier<List<Tuple<String>>> itemsSupplier;
+        boolean isLocalizationSupplied = false;
+        Consumer<Form> selectionListener = null;
+
+        SingleSelectionField(
+                final String name,
+                final String label,
+                final String value,
+                final Supplier<List<Tuple<String>>> itemsSupplier) {
+
+            super(name, label, value);
+            this.itemsSupplier = itemsSupplier;
+        }
+
+        public SingleSelectionField withLocalizationSupplied() {
+            this.isLocalizationSupplied = true;
+            return this;
+        }
+
+        public SingleSelectionField withSelectionListener(final Consumer<Form> selectionListener) {
+            this.selectionListener = selectionListener;
+            return this;
+        }
+
+        @Override
+        void build(final FormBuilder builder) {
+
+            if (this.autoEmptyCellSeparation && builder.form.hasFields()) {
+                builder.addEmptyCell(this.spanEmptyCell);
+            }
+
+            final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
+            if (builder.readonly) {
+                builder.form.putField(
+                        this.name, lab,
+                        builder.valueLabel(builder.formParent, this.value, this.spanInput));
+            } else {
+                final SingleSelection selection = (this.isLocalizationSupplied)
+                        ? builder.widgetFactory.singleSelectionLocalizedSupplier(
+                                builder.formParent,
+                                this.itemsSupplier)
+                        : builder.widgetFactory.singleSelectionLocalized(
+                                builder.formParent,
+                                this.itemsSupplier.get());
+                final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
+                gridData.heightHint = 25;
+                selection.setLayoutData(gridData);
+                selection.select(this.value);
+                builder.form.putField(this.name, lab, selection);
+                if (this.selectionListener != null) {
+                    selection.addListener(SWT.Selection, e -> {
+                        this.selectionListener.accept(builder.form);
+                    });
+                }
+            }
+            if (StringUtils.isNoneBlank(this.group)) {
+                builder.form.addToGroup(this.group, this.name);
+            }
+        }
+    }
+
+    public static final class ImageUploadField extends FieldTemplate {
+
+        ImageUploadField(final String name, final String label, final String value) {
+            super(name, label, value);
+        }
+
+        @Override
+        void build(final FormBuilder builder) {
+
+            if (this.autoEmptyCellSeparation && builder.form.hasFields()) {
+                builder.addEmptyCell(this.spanEmptyCell);
+            }
+
+            final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
+            final ImageUpload imageUpload = builder.widgetFactory.formImageUpload(
+                    builder.formParent,
+                    this.value,
+                    new LocTextKey("sebserver.overall.upload"),
+                    this.spanInput, 1, builder.readonly);
+            builder.form.putField(this.name, lab, imageUpload);
+        }
+
+    }
+
+    private Label labelLocalized(final Composite parent, final String locTextKey, final int hspan) {
+        final Label label = this.widgetFactory.labelLocalized(parent, locTextKey);
+        final GridData gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false, hspan, 1);
+        label.setLayoutData(gridData);
+        return label;
+    }
+
+    private Label valueLabel(final Composite parent, final String value, final int hspan) {
+        final Label label = new Label(parent, SWT.NONE);
+        label.setText((StringUtils.isNoneBlank(value)) ? value : Constants.EMPTY_NOTE);
+        final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, hspan, 1);
+        label.setLayoutData(gridData);
+        return label;
+    }
+
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormHandle.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormHandle.java
index cda4f2dd..a20a1317 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormHandle.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/form/FormHandle.java
@@ -68,23 +68,26 @@ public class FormHandle<T> {
                 .map(result -> {
                     this.pageContext.publishPageEvent(new ActionEvent(action, result));
                     return result;
-                }).onErrorDo(error -> {
-                    if (error instanceof RestCallError) {
-                        ((RestCallError) error)
-                                .getErrorMessages()
-                                .stream()
-                                .map(FieldValidationError::new)
-                                .forEach(fve -> this.form.process(
-                                        name -> name.equals(fve.fieldName),
-                                        fieldAccessor -> showValidationError(fieldAccessor, fve)));
-                    } else {
-                        log.error("Unexpected error while trying to post form: ", error);
-                        this.pageContext.notifyError(error);
-                    }
                 })
+                .onErrorDo(this::handleError)
                 .map(this.postPostHandle);
     }
 
+    private void handleError(final Throwable error) {
+        if (error instanceof RestCallError) {
+            ((RestCallError) error)
+                    .getErrorMessages()
+                    .stream()
+                    .map(FieldValidationError::new)
+                    .forEach(fve -> this.form.process(
+                            name -> name.equals(fve.fieldName),
+                            fieldAccessor -> showValidationError(fieldAccessor, fve)));
+        } else {
+            log.error("Unexpected error while trying to post form: ", error);
+            this.pageContext.notifyError(error);
+        }
+    }
+
     private final void showValidationError(
             final FormFieldAccessor fieldAccessor,
             final FieldValidationError valError) {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java
index 940d7722..b2e3023d 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java
@@ -9,9 +9,15 @@
 package ch.ethz.seb.sebserver.gui.service.i18n;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
+import java.util.stream.Collectors;
 
+import org.apache.commons.lang3.StringUtils;
 import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import ch.ethz.seb.sebserver.gbl.util.Tuple;
 
 public interface I18nSupport {
 
@@ -72,4 +78,38 @@ public interface I18nSupport {
      * @return the text in current language parsed from localized text */
     String getText(String key, Locale locale, String def, Object... args);
 
+    default List<Tuple<String>> getLanguageResources() {
+        return getLanguageResources(this);
+    }
+
+    default List<Tuple<String>> getTimeZoneResources() {
+        return getTimeZoneResources(this);
+    }
+
+    /** Get a list of language key/name tuples for all supported languages in the
+     * language of the current users locale.
+     *
+     * @param i18nSupport I18nSupport to get the actual current users locale
+     * @return list of language key/name tuples for all supported languages in the language of the current users
+     *         locale */
+    static List<Tuple<String>> getLanguageResources(final I18nSupport i18nSupport) {
+        final Locale currentLocale = i18nSupport.getCurrentLocale();
+        return i18nSupport.supportedLanguages()
+                .stream()
+                .map(locale -> new Tuple<>(locale.toLanguageTag(), locale.getDisplayLanguage(currentLocale)))
+                .filter(tuple -> StringUtils.isNoneBlank(tuple._2))
+                .sorted((t1, t2) -> t1._2.compareTo(t2._2))
+                .collect(Collectors.toList());
+    }
+
+    static List<Tuple<String>> getTimeZoneResources(final I18nSupport i18nSupport) {
+        final Locale currentLocale = i18nSupport.getCurrentLocale();
+        return DateTimeZone
+                .getAvailableIDs()
+                .stream()
+                .map(id -> new Tuple<>(id, DateTimeZone.forID(id).getName(0, currentLocale) + " (" + id + ")"))
+                .sorted((t1, t2) -> t1._2.compareTo(t2._2))
+                .collect(Collectors.toList());
+    }
+
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
index 39b3b1a3..7f09b41f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
@@ -154,6 +154,8 @@ public interface PageContext {
 
     <T> T logoutOnError(Throwable error);
 
+    void publishPageMessage(LocTextKey title, LocTextKey message);
+
     void publishPageMessage(PageMessageException pme);
 
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java
new file mode 100644
index 00000000..27ff9201
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.page;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
+import ch.ethz.seb.sebserver.gbl.model.Entity;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.gbl.util.Tuple;
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionDependency;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames;
+
+public final class PageUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(PageUtils.class);
+
+    public static final Supplier<LocTextKey> confirmDeactivation(
+            final Entity entity,
+            final RestService restService) {
+
+        return () -> {
+            try {
+                final Set<EntityKey> dependencies = restService.getBuilder(GetInstitutionDependency.class)
+                        .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(entity.getModelId()))
+                        .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name())
+                        .call()
+                        .getOrThrow();
+                final int size = dependencies.size();
+                if (size > 0) {
+                    return new LocTextKey("sebserver.dialog.confirm.deactivation", String.valueOf(size));
+                } else {
+                    return new LocTextKey("sebserver.dialog.confirm.deactivation.noDependencies");
+                }
+            } catch (final Exception e) {
+                log.error("Failed to get dependencyies for Entity: {}", entity, e);
+                return new LocTextKey("sebserver.dialog.confirm.deactivation", "");
+            }
+        };
+    }
+
+    public static List<Tuple<String>> getInstitutionSelectionResource(final RestService restService) {
+        return restService.getBuilder(GetInstitutionNames.class)
+                .call()
+                .getOr(Collections.emptyList())
+                .stream()
+                .map(entityName -> new Tuple<>(entityName.modelId, entityName.name))
+                .collect(Collectors.toList());
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java
index 3c0a51e3..63340c1e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java
@@ -22,6 +22,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 
 public final class Action implements Runnable {
@@ -73,6 +74,16 @@ public final class Action implements Runnable {
 
         } catch (final PageMessageException pme) {
             Action.this.pageContext.publishPageMessage(pme);
+
+        } catch (final RestCallError restCallError) {
+            if (restCallError.isFieldValidationError()) {
+                Action.this.pageContext.publishPageMessage(
+                        new LocTextKey("sebserver.form.validation.error.title"),
+                        new LocTextKey("sebserver.form.validation.error.message"));
+            } else {
+                log.error("Failed to execute action: {}", Action.this, restCallError);
+                Action.this.pageContext.notifyError("action.error.unexpected.message", restCallError);
+            }
         } catch (final Throwable t) {
             log.error("Failed to execute action: {}", Action.this, t);
             Action.this.pageContext.notifyError("action.error.unexpected.message", t);
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/UserAccountActions.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/UserAccountActions.java
index 3f07b0ae..c87c8db8 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/UserAccountActions.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/UserAccountActions.java
@@ -9,9 +9,12 @@
 package ch.ethz.seb.sebserver.gui.service.page.action;
 
 import java.util.Collection;
+import java.util.function.Function;
 
+import ch.ethz.seb.sebserver.gbl.api.API;
 import ch.ethz.seb.sebserver.gbl.api.EntityType;
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
 import ch.ethz.seb.sebserver.gbl.util.Result;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
@@ -19,9 +22,18 @@ import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
 import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
 import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.Activity;
 import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount;
 
 public final class UserAccountActions {
 
+    public static Function<UserInfo, UserInfo> postSaveAdapter(final PageContext pageContext) {
+        return userAccount -> {
+            goToUserAccount(pageContext, userAccount.getModelId(), false);
+            return userAccount;
+        };
+    }
+
     public static Result<?> newUserAccount(final Action action) {
         return Result.of(goToUserAccount(action.pageContext, null, true));
     }
@@ -34,6 +46,46 @@ public final class UserAccountActions {
         return fromSelection(action, true);
     }
 
+    public static Result<?> editUserAccount(final Action action) {
+        return Result.of(goToUserAccount(
+                action.pageContext,
+                action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
+                true));
+    }
+
+    public static Result<?> cancelEditUserAccount(final Action action) {
+        if (action.pageContext.getEntityKey() == null) {
+            final ActivitySelection toList = Activity.USER_ACCOUNT_LIST.createSelection();
+            action.pageContext.publishPageEvent(new ActivitySelectionEvent(toList));
+            return Result.of(toList);
+        } else {
+            return Result.of(goToUserAccount(
+                    action.pageContext,
+                    action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
+                    false));
+        }
+    }
+
+    public static Result<?> activateUserAccount(final Action action) {
+        return action.restService
+                .getBuilder(ActivateUserAccount.class)
+                .withURIVariable(
+                        API.PARAM_MODEL_ID,
+                        action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
+                .call()
+                .map(report -> goToUserAccount(action.pageContext, report.getSingleSource().modelId, false));
+    }
+
+    public static Result<?> deactivateUserAccount(final Action action) {
+        return action.restService
+                .getBuilder(DeactivateUserAccount.class)
+                .withURIVariable(
+                        API.PARAM_MODEL_ID,
+                        action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
+                .call()
+                .map(report -> goToUserAccount(action.pageContext, report.getSingleSource().modelId, false));
+    }
+
     private static Result<?> fromSelection(final Action action, final boolean edit) {
         final Collection<String> selection = action.selectionSupplier.get();
         if (selection.isEmpty()) {
@@ -50,7 +102,6 @@ public final class UserAccountActions {
 
         final ActivitySelection activitySelection = Activity.USER_ACCOUNT_FORM
                 .createSelection()
-                .withEntity(new EntityKey(modelId, EntityType.USER))
                 .withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit));
 
         if (modelId != null) {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java
index 10a10627..9b15a06f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java
@@ -22,6 +22,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.page.action.ActionPane;
 import ch.ethz.seb.sebserver.gui.service.page.content.InstitutionForm;
 import ch.ethz.seb.sebserver.gui.service.page.content.InstitutionList;
+import ch.ethz.seb.sebserver.gui.service.page.content.UserAccountForm;
 import ch.ethz.seb.sebserver.gui.service.page.content.UserAccountList;
 import ch.ethz.seb.sebserver.gui.service.page.impl.TODOTemplate;
 
@@ -51,7 +52,7 @@ public class ActivitySelection {
                 new LocTextKey("sebserver.activities.useraccount")),
 
         USER_ACCOUNT_FORM(
-                UserAccountList.class,
+                UserAccountForm.class,
                 ActionPane.class,
                 new LocTextKey("sebserver.activities.useraccount")),
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java
index 4484cf20..c42ef299 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java
@@ -8,9 +8,6 @@
 
 package ch.ethz.seb.sebserver.gui.service.page.content;
 
-import java.util.Set;
-import java.util.function.Supplier;
-
 import org.eclipse.swt.widgets.Composite;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -18,23 +15,22 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.seb.sebserver.gbl.api.API;
-import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
 import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
 import ch.ethz.seb.sebserver.gbl.model.Domain;
-import ch.ethz.seb.sebserver.gbl.model.Entity;
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
+import ch.ethz.seb.sebserver.gui.service.form.FormBuilder;
 import ch.ethz.seb.sebserver.gui.service.form.FormHandle;
 import ch.ethz.seb.sebserver.gui.service.form.PageFormService;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
 import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
 import ch.ethz.seb.sebserver.gui.service.page.action.InstitutionActions;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionDependency;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.SaveInstitution;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@@ -71,7 +67,7 @@ public class InstitutionForm implements TemplateComposer {
         final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
         final EntityKey entityKey = pageContext.getEntityKey();
 
-        // get data or create new and handle error
+        // get data or create new. Handle error if happen
         final Institution institution = (entityKey == null)
                 ? new Institution(null, null, null, null, false)
                 : this.restService
@@ -103,35 +99,28 @@ public class InstitutionForm implements TemplateComposer {
                 institution.name);
         final Composite content = widgetFactory.defaultPageLayout(
                 formContext.getParent(),
-                titleKey,
-                ActionDefinition.INSTITUTION_SAVE,
-                title -> event -> {
-                    final Entity entity = (Entity) event.source;
-                    widgetFactory.injectI18n(title, new LocTextKey(
-                            "sebserver.institution.form.title",
-                            entity.getName()));
-                    title.getParent().layout();
-                });
+                titleKey);
 
         // The Institution form
         final FormHandle<Institution> formHandle = this.pageFormService.getBuilder(
                 formContext.copyOf(content), 4)
                 .readonly(pageContext.isReadonly())
-                .putStaticValue("id", institution.getModelId())
-                .addTextField(
+                .putStaticValueIf(() -> entityKey != null,
+                        Domain.INSTITUTION.ATTR_ID,
+                        institution.getModelId())
+                .addField(FormBuilder.text(
                         Domain.INSTITUTION.ATTR_NAME,
                         "sebserver.institution.form.name",
-                        institution.name, 2)
-                .addEmptyCell()
-                .addTextField(
+                        institution.name))
+                .addField(FormBuilder.text(
                         Domain.INSTITUTION.ATTR_URL_SUFFIX,
                         "sebserver.institution.form.urlSuffix",
-                        institution.urlSuffix, 2)
-                .addEmptyCell()
-                .addImageUploadIf(() -> entityKey != null,
+                        institution.urlSuffix))
+                .addField(FormBuilder.imageUpload(
                         Domain.INSTITUTION.ATTR_LOGO_IMAGE,
                         "sebserver.institution.form.logoImage",
-                        institution.logoImage, 2)
+                        institution.logoImage)
+                        .withCondition(() -> entityKey != null))
                 .buildFor((entityKey == null)
                         ? this.restService.getRestCall(NewInstitution.class)
                         : this.restService.getRestCall(SaveInstitution.class),
@@ -155,7 +144,7 @@ public class InstitutionForm implements TemplateComposer {
             } else {
                 formContext.createAction(ActionDefinition.INSTITUTION_DEACTIVATE)
                         .withExec(InstitutionActions::deactivateInstitution)
-                        .withConfirm(confirmDeactivation(institution))
+                        .withConfirm(PageUtils.confirmDeactivation(institution, this.restService))
                         .publishIf(() -> modifyGrant);
             }
 
@@ -170,25 +159,4 @@ public class InstitutionForm implements TemplateComposer {
         }
     }
 
-    private Supplier<LocTextKey> confirmDeactivation(final Institution institution) {
-        return () -> {
-            try {
-                final Set<EntityKey> dependencies = this.restService.getBuilder(GetInstitutionDependency.class)
-                        .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(institution.id))
-                        .withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name())
-                        .call()
-                        .getOrThrow();
-                final int size = dependencies.size();
-                if (size > 0) {
-                    return new LocTextKey("sebserver.institution.form.confirm.deactivation", String.valueOf(size));
-                } else {
-                    return new LocTextKey("sebserver.institution.form.confirm.deactivation.noDependencies");
-                }
-            } catch (final Exception e) {
-                log.error("Failed to get dependencyies for Institution: {}", institution, e);
-                return new LocTextKey("sebserver.institution.form.confirm.deactivation", "");
-            }
-        };
-    }
-
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/UserAccountForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/UserAccountForm.java
index de0b59bc..83745550 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/UserAccountForm.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/UserAccountForm.java
@@ -9,22 +9,36 @@
 package ch.ethz.seb.sebserver.gui.service.page.content;
 
 import java.util.UUID;
+import java.util.function.BooleanSupplier;
 
+import org.eclipse.swt.widgets.Composite;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
+import ch.ethz.seb.sebserver.gbl.model.Domain;
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 import ch.ethz.seb.sebserver.gbl.model.user.UserAccount;
+import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
 import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
+import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
+import ch.ethz.seb.sebserver.gui.service.form.FormBuilder;
+import ch.ethz.seb.sebserver.gui.service.form.FormHandle;
 import ch.ethz.seb.sebserver.gui.service.form.PageFormService;
+import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
 import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
 import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
+import ch.ethz.seb.sebserver.gui.service.page.action.UserAccountActions;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
 import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
 import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
 
@@ -58,9 +72,12 @@ public class UserAccountForm implements TemplateComposer {
 
         final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
         final EntityKey entityKey = pageContext.getEntityKey();
+        final BooleanSupplier isNew = () -> entityKey == null;
+        final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
+        final BooleanSupplier isSEBAdmin = () -> this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
 
-        // get data or create new and handle error
-        final UserAccount userAccount = (entityKey == null)
+        // get data or create new. handle error if happen
+        final UserAccount userAccount = isNew.getAsBoolean()
                 ? new UserMod(
                         UUID.randomUUID().toString(),
                         this.currentUser.get().institutionId)
@@ -72,10 +89,119 @@ public class UserAccountForm implements TemplateComposer {
 
         if (userAccount == null) {
             log.error(
-                    "Failed to get UserAccount. Error was notified to the User. See previous logs for more infomation");
+                    "Failed to get UserAccount. "
+                            + "Error was notified to the User. "
+                            + "See previous logs for more infomation");
             return;
         }
 
+        // new PageContext with actual EntityKey
+        final PageContext formContext = pageContext;
+        pageContext.withEntityKey(userAccount.getEntityKey());
+
+        if (log.isDebugEnabled()) {
+            log.debug("UserAccount Form for user {}", userAccount.getName());
+        }
+
+        // the default page layout with title
+        final LocTextKey titleKey = new LocTextKey(
+                isNotNew.getAsBoolean()
+                        ? "sebserver.useraccount.form.title"
+                        : "sebserver.useraccount.form.title.new",
+                userAccount.getUsername());
+        final Composite content = widgetFactory.defaultPageLayout(
+                formContext.getParent(),
+                titleKey);
+
+        // The UserAccount form
+        final FormHandle<UserInfo> formHandle = this.pageFormService.getBuilder(
+                formContext.copyOf(content), 4)
+                .readonly(pageContext.isReadonly())
+                .putStaticValueIf(isNotNew,
+                        Domain.USER.ATTR_UUID,
+                        userAccount.getModelId())
+                .putStaticValueIf(isNew,
+                        Domain.USER.ATTR_TIMEZONE,
+                        userAccount.getTimeZone().getID())
+                .addField(FormBuilder.singleSelection(
+                        Domain.USER.ATTR_INSTITUTION_ID,
+                        "sebserver.useraccount.form.institution",
+                        String.valueOf(userAccount.getInstitutionId()),
+                        () -> PageUtils.getInstitutionSelectionResource(this.restService))
+                        .withCondition(isSEBAdmin))
+                .addField(FormBuilder.text(
+                        Domain.USER.ATTR_NAME,
+                        "sebserver.useraccount.form.name",
+                        userAccount.getName()))
+                .addField(FormBuilder.text(
+                        Domain.USER.ATTR_USERNAME,
+                        "sebserver.useraccount.form.username",
+                        userAccount.getUsername()))
+                .addField(FormBuilder.text(
+                        Domain.USER.ATTR_EMAIL,
+                        "sebserver.useraccount.form.mail",
+                        userAccount.getEmail()))
+                .addField(FormBuilder.singleSelection(
+                        Domain.USER.ATTR_LOCALE,
+                        "sebserver.useraccount.form.language",
+                        userAccount.getTimeZone().getID(),
+                        () -> widgetFactory.getI18nSupport().getLanguageResources())
+                        .withLocalizationSupplied())
+                .addField(FormBuilder.singleSelection(
+                        Domain.USER.ATTR_TIMEZONE,
+                        "sebserver.useraccount.form.timezone",
+                        userAccount.getTimeZone().getID(),
+                        () -> widgetFactory.getI18nSupport().getTimeZoneResources())
+                        .withLocalizationSupplied())
+                // TODO add role selection (create multi selector)
+                .addField(FormBuilder.text(
+                        UserMod.ATTR_NAME_NEW_PASSWORD,
+                        "sebserver.useraccount.form.password",
+                        null)
+                        .asPasswordField()
+                        .withCondition(isNew))
+                .addField(FormBuilder.text(
+                        UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD,
+                        "sebserver.useraccount.form.password.retyped",
+                        null)
+                        .asPasswordField()
+                        .withCondition(isNew))
+                .buildFor((entityKey == null)
+                        ? this.restService.getRestCall(NewUserAccount.class)
+                        : this.restService.getRestCall(SaveUserAccount.class),
+                        UserAccountActions.postSaveAdapter(pageContext));
+
+        // propagate content actions to action-pane
+        final boolean writeGrant = this.currentUser.hasPrivilege(PrivilegeType.WRITE, userAccount);
+        final boolean modifyGrant = this.currentUser.hasPrivilege(PrivilegeType.MODIFY, userAccount);
+        if (pageContext.isReadonly()) {
+            formContext.createAction(ActionDefinition.USER_ACCOUNT_NEW)
+                    .withExec(UserAccountActions::newUserAccount)
+                    .publishIf(() -> writeGrant);
+            formContext.createAction(ActionDefinition.USER_ACCOUNT_MODIFY)
+                    .withExec(UserAccountActions::editUserAccount)
+                    .publishIf(() -> modifyGrant);
+
+            if (!userAccount.isActive()) {
+                formContext.createAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
+                        .withExec(UserAccountActions::activateUserAccount)
+                        .publishIf(() -> modifyGrant);
+            } else {
+                formContext.createAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
+                        .withExec(UserAccountActions::deactivateUserAccount)
+                        .withConfirm(PageUtils.confirmDeactivation(userAccount, this.restService))
+                        .publishIf(() -> modifyGrant);
+            }
+
+        } else {
+            formContext.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
+                    .withExec(formHandle::postChanges)
+                    .publish()
+                    .createAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
+                    .withExec(UserAccountActions::cancelEditUserAccount)
+                    .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+                    .publish();
+        }
     }
 
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
index a7326505..36ab1216 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
@@ -311,6 +311,17 @@ public class PageContextImpl implements PageContext {
         forwardToPage(this.composerService.loginPage(), pageContext);
     }
 
+    @Override
+    public void publishPageMessage(final LocTextKey title, final LocTextKey message) {
+        final MessageBox messageBox = new Message(
+                getShell(),
+                this.i18nSupport.getText(title),
+                this.i18nSupport.getText(message),
+                SWT.NONE);
+        messageBox.setMarkupEnabled(true);
+        messageBox.open(null);
+    }
+
     @Override
     public void publishPageMessage(final PageMessageException pme) {
         final MessageBox messageBox = new Message(
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java
index aad50bed..56d39b4f 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java
@@ -8,8 +8,6 @@
 
 package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
 
-import org.springframework.util.MultiValueMap;
-
 import ch.ethz.seb.sebserver.gbl.model.EntityKey;
 
 public interface FormBinding {
@@ -18,6 +16,6 @@ public interface FormBinding {
 
     String getFormAsJson();
 
-    MultiValueMap<String, String> getFormAsQueryAttributes();
+    String getFormUrlEncoded();
 
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
index a7649e84..e947f6ea 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
@@ -113,6 +113,7 @@ public abstract class RestCall<T> {
                         }));
             } catch (final Exception e) {
                 log.error("Unexpected error-response while webservice API call for: {}", builder, e);
+                log.error("Unexpected error-response cause: ", t);
                 restCallError.errors.add(APIMessage.ErrorMessage.UNEXPECTED.of(e));
             }
 
@@ -147,6 +148,11 @@ public abstract class RestCall<T> {
             return this;
         }
 
+        public RestCallBuilder withHeaders(final MultiValueMap<String, String> params) {
+            this.httpHeaders.addAll(params);
+            return this;
+        }
+
         public RestCallBuilder withBody(final Object body) {
             if (body instanceof String) {
                 this.body = String.valueOf(body);
@@ -198,7 +204,9 @@ public abstract class RestCall<T> {
                 return withURIVariable(API.PARAM_MODEL_ID, formBinding.entityKey().modelId)
                         .withBody(formBinding.getFormAsJson());
             } else {
-                return withQueryParams(formBinding.getFormAsQueryAttributes());
+                this.body = formBinding.getFormUrlEncoded();
+                return this;
+                //return withHeaders(formBinding.getFormAsQueryAttributes());
             }
         }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCallError.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCallError.java
index aecc9e41..1ffc61b4 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCallError.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCallError.java
@@ -37,6 +37,14 @@ public class RestCallError extends RuntimeException implements APIMessageError {
         return !this.errors.isEmpty();
     }
 
+    public boolean isFieldValidationError() {
+        return this.errors
+                .stream()
+                .filter(error -> APIMessage.ErrorMessage.FIELD_VALIDATION.isOf(error))
+                .findFirst()
+                .isPresent();
+    }
+
     @Override
     public String toString() {
         return "RestCallError [errors=" + this.errors + "]";
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java
index e36dae7f..673d67eb 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java
@@ -26,7 +26,7 @@ import org.springframework.util.MultiValueMap;
 import ch.ethz.seb.sebserver.gbl.model.Entity;
 import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
 import ch.ethz.seb.sebserver.gui.service.table.ColumnDefinition.TableFilterAttribute;
-import ch.ethz.seb.sebserver.gui.service.widget.LanguageSelector;
+import ch.ethz.seb.sebserver.gui.service.widget.SingleSelection;
 import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.ImageIcon;
 
 public class TableFilter<ROW extends Entity> extends Composite {
@@ -232,7 +232,7 @@ public class TableFilter<ROW extends Entity> extends Composite {
 
     private class LanguageFilter extends FilterComponent {
 
-        private LanguageSelector selector;
+        private SingleSelection selector;
 
         LanguageFilter(final TableFilterAttribute attribute) {
             super(attribute);
@@ -240,7 +240,12 @@ public class TableFilter<ROW extends Entity> extends Composite {
 
         @Override
         FilterComponent build(final Composite parent) {
-            this.selector = TableFilter.this.entityTable.widgetFactory.countrySelector(parent);
+            this.selector = TableFilter.this.entityTable.widgetFactory
+                    .singleSelectionLocalizedSupplier(
+                            parent,
+                            () -> TableFilter.this.entityTable.widgetFactory
+                                    .getI18nSupport()
+                                    .getLanguageResources());
             this.selector.setLayoutData(this.rowData);
             return this;
         }
@@ -249,7 +254,6 @@ public class TableFilter<ROW extends Entity> extends Composite {
         FilterComponent reset() {
             if (this.selector != null) {
                 this.selector.clear();
-                this.selector.layout();
             }
             return this;
         }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/LanguageSelector.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/LanguageSelector.java
deleted file mode 100644
index b67fc331..00000000
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/LanguageSelector.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-package ch.ethz.seb.sebserver.gui.service.widget;
-
-import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY;
-
-import java.util.List;
-import java.util.Locale;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang3.StringUtils;
-import org.eclipse.swt.widgets.Composite;
-
-import ch.ethz.seb.sebserver.gbl.util.Tuple;
-import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
-
-public class LanguageSelector extends SingleSelection {
-
-    private static final long serialVersionUID = -8590909580787576722L;
-
-    private final Consumer<LanguageSelector> updateFunction;
-
-    public LanguageSelector(final Composite parent, final I18nSupport i18nSupport) {
-        super(parent, getLanguages(i18nSupport));
-        this.updateFunction = updateFunction(i18nSupport);
-        this.setData(POLYGLOT_WIDGET_FUNCTION_KEY, this.updateFunction);
-    }
-
-    private static final Consumer<LanguageSelector> updateFunction(final I18nSupport i18nSupport) {
-        return selection -> selection.applyNewMapping(getLanguages(i18nSupport));
-    }
-
-    public static final List<Tuple<String>> getLanguages(final I18nSupport i18nSupport) {
-        final Locale currentLocale = i18nSupport.getCurrentLocale();
-        return i18nSupport.supportedLanguages()
-                .stream()
-                .map(locale -> new Tuple<>(locale.toLanguageTag(), locale.getDisplayLanguage(currentLocale)))
-                .filter(tuple -> StringUtils.isNoneBlank(tuple._2))
-                .sorted((t1, t2) -> t1._2.compareTo(t2._2))
-                .collect(Collectors.toList());
-    }
-
-    public void clear() {
-        super.clearSelection();
-        this.updateFunction.accept(this);
-    }
-
-}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/SingleSelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/SingleSelection.java
index 8404e8e6..b78e8fd3 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/SingleSelection.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/SingleSelection.java
@@ -33,6 +33,7 @@ public class SingleSelection extends Combo {
     }
 
     protected void applyNewMapping(final List<Tuple<String>> mapping) {
+        final String selectionValue = getSelectionValue();
         this.valueMapping.clear();
         this.keyMapping.clear();
         this.valueMapping.addAll(mapping.stream()
@@ -42,6 +43,7 @@ public class SingleSelection extends Combo {
                 .map(t -> t._1)
                 .collect(Collectors.toList()));
         super.setItems(this.valueMapping.toArray(new String[mapping.size()]));
+        select(selectionValue);
     }
 
     public void select(final String key) {
@@ -62,4 +64,9 @@ public class SingleSelection extends Combo {
         return this.keyMapping.get(selectionindex);
     }
 
+    public void clear() {
+        super.clearSelection();
+        super.setItems(this.valueMapping.toArray(new String[this.valueMapping.size()]));
+    }
+
 }
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java
index 892c8486..4fff9887 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java
@@ -16,8 +16,8 @@ import java.util.List;
 import java.util.Locale;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
-import org.apache.commons.lang3.StringUtils;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Device;
@@ -34,7 +34,6 @@ import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 import org.eclipse.swt.widgets.TableItem;
-import org.eclipse.swt.widgets.Text;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeItem;
 import org.slf4j.Logger;
@@ -42,7 +41,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
-import ch.ethz.seb.sebserver.gbl.Constants;
 import ch.ethz.seb.sebserver.gbl.model.Entity;
 import ch.ethz.seb.sebserver.gbl.model.Page;
 import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@@ -311,68 +309,6 @@ public class WidgetFactory {
         return imageButton;
     }
 
-    public Label formLabelLocalized(final Composite parent, final String locTextKey) {
-        final Label label = labelLocalized(parent, locTextKey);
-        final GridData gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
-        label.setLayoutData(gridData);
-        return label;
-    }
-
-    public Label formValueLabel(final Composite parent, final String value, final int span) {
-        final Label label = new Label(parent, SWT.NONE);
-        label.setText((StringUtils.isNoneBlank(value)) ? value : Constants.EMPTY_NOTE);
-        final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, span, 1);
-        label.setLayoutData(gridData);
-        return label;
-    }
-
-    public Text formTextInput(final Composite parent, final String value) {
-        return formTextInput(parent, value, 1, 1);
-    }
-
-    public Text formTextInput(final Composite parent, final String value, final int hspan, final int vspan) {
-        final Text textInput = new Text(parent, SWT.LEFT | SWT.BORDER);
-        final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan);
-        gridData.heightHint = 15;
-        textInput.setLayoutData(gridData);
-        if (value != null) {
-            textInput.setText(value);
-        }
-        return textInput;
-    }
-
-    public Combo formSingleSelectionLocalized(
-            final Composite parent,
-            final String selection,
-            final List<Tuple<String>> items) {
-
-        return formSingleSelectionLocalized(parent, selection, items, 1, 1);
-    }
-
-    public Combo formSingleSelectionLocalized(
-            final Composite parent,
-            final String selection,
-            final List<Tuple<String>> items,
-            final int hspan, final int vspan) {
-
-        final SingleSelection combo = singleSelectionLocalized(parent, items);
-        final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan);
-        gridData.heightHint = 25;
-        combo.setLayoutData(gridData);
-        combo.select(selection);
-        return combo;
-    }
-
-    public void formEmpty(final Composite parent) {
-        formEmpty(parent, 1, 1);
-    }
-
-    public void formEmpty(final Composite parent, final int hspan, final int vspan) {
-        final Label empty = new Label(parent, SWT.LEFT);
-        empty.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan));
-        empty.setText("");
-    }
-
     public SingleSelection singleSelectionLocalized(
             final Composite parent,
             final List<Tuple<String>> items) {
@@ -382,10 +318,25 @@ public class WidgetFactory {
         return combo;
     }
 
-    public LanguageSelector countrySelector(final Composite parent) {
-        return new LanguageSelector(parent, this.i18nSupport);
+    public SingleSelection singleSelectionLocalizedSupplier(
+            final Composite parent,
+            final Supplier<List<Tuple<String>>> itemsSupplier) {
+
+        final Consumer<SingleSelection> updateFunction =
+                selection -> selection.applyNewMapping(itemsSupplier.get());
+        final SingleSelection selection = new SingleSelection(parent, itemsSupplier.get());
+        selection.setData(POLYGLOT_WIDGET_FUNCTION_KEY, updateFunction);
+        return selection;
     }
 
+//    public SingleSelection languageSelector(final Composite parent) {
+//        final Consumer<SingleSelection> updateFunction =
+//                selection -> selection.applyNewMapping(this.i18nSupport.getLanguageResources());
+//        final SingleSelection selection = new SingleSelection(parent, this.i18nSupport.getLanguageResources());
+//        selection.setData(POLYGLOT_WIDGET_FUNCTION_KEY, updateFunction);
+//        return selection;
+//    }
+
     public ImageUpload formImageUpload(
             final Composite parent,
             final String value,
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java
index 1e495d90..600e2844 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserDaoImpl.java
@@ -333,7 +333,7 @@ public class UserDaoImpl implements UserDAO {
 
     @Override
     public List<Long> extractPKsFromKeys(final Collection<EntityKey> keys) {
-        if (keys == null || keys.isEmpty() || keys.iterator().next().isIdPK) {
+        if (keys == null || keys.isEmpty() || keys.iterator().next().entityType != EntityType.USER) {
             return UserDAO.super.extractPKsFromKeys(keys);
         } else {
             final List<String> uuids = keys.stream()
diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties
index aaccfbfe..6a64a6a0 100644
--- a/src/main/resources/messages.properties
+++ b/src/main/resources/messages.properties
@@ -17,6 +17,8 @@ sebserver.overall.action.filter.clear=Clear Filter Criteria
 # Form validation and messages
 ################################
 
+sebserver.form.validation.error.title=Form Data Validation Failed
+sebserver.form.validation.error.message=There is missing or incorrect form data.
 sebserver.form.validation.fieldError.size=The size must be between {3} and {4}
 sebserver.form.validation.fieldError.name=Name is mandatory and must have a size between 3 and 255 character
 sebserver.form.validation.fieldError.urlSuffix=URL Suffix must have a size between 3 and 255 character
@@ -25,6 +27,9 @@ sebserver.error.unexpected=Unexpected Error
 sebserver.page.message=Information
 sebserver.dialog.confirm.title=Confirmation
 
+sebserver.dialog.confirm.deactivation=Note that there are {0} other entities that belongs to this entity.<br/>Those will also be deactivated by deactivating this entity.<br/><br/>Are You sure to deactivate this entity?
+sebserver.dialog.confirm.deactivation.noDependencies=Are You sure to deactivate?
+
 ################################
 # Login Page
 ################################
@@ -78,8 +83,7 @@ sebserver.institution.form.title=Institution : {0}
 sebserver.institution.form.name=Name
 sebserver.institution.form.urlSuffix=URL Suffix
 sebserver.institution.form.logoImage=Logo Image
-sebserver.institution.form.confirm.deactivation=Note that there are {0} other entities that belongs to this Institution.<br/>Those will also be deactivated by deactivating this Institution.<br/><br/>Are You sure to deactivate this Institution?
-sebserver.institution.form.confirm.deactivation.noDependencies=Are You sure to deactivate this Institution?
+
 
 ################################
 # User Account
@@ -102,5 +106,16 @@ sebserver.useraccount.action.delete=Delete User Account
 
 sebserver.useraccount.info.pleaseSelect=Please Select an User Account first.
 
+sebserver.useraccount.form.title=User Account : {0}
+sebserver.useraccount.form.title.new=New User Account
+sebserver.useraccount.form.institution=Institution
+sebserver.useraccount.form.name=Name
+sebserver.useraccount.form.username=Username
+sebserver.useraccount.form.mail=E-Mail
+sebserver.useraccount.form.language=Language
+sebserver.useraccount.form.timezone=Time Zone
+sebserver.useraccount.form.password=Password
+sebserver.useraccount.form.password.retyped=Retyped Password
+