SEBSERV-27 User Account multi selection

This commit is contained in:
anhefti 2019-02-22 14:15:00 +01:00
parent 422d816093
commit f760eba750
48 changed files with 1027 additions and 733 deletions

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.content;
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
@ -20,21 +20,21 @@ import ch.ethz.seb.sebserver.gbl.model.Domain;
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.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.content.action.InstitutionActions;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.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.NewInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.SaveInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.content;
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
@ -19,17 +19,17 @@ import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.content.action.InstitutionActions;
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.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.GetInstitutions;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.service.table.EntityTable;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.impl;
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
@ -28,8 +28,8 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
import ch.ethz.seb.sebserver.gui.service.widget.Message;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.Message;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.impl;
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
@ -21,15 +21,16 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.activity.ActivitiesPane;
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.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitiesPane;
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionListener;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.ImageIcon;
import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
@Lazy
@Component

View file

@ -6,41 +6,44 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.content;
package ch.ethz.seb.sebserver.gui.content;
import java.util.UUID;
import java.util.function.BooleanSupplier;
import org.apache.tomcat.util.buf.StringUtils;
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.Constants;
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.Domain.USER_ROLE;
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.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.content.action.UserAccountActions;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.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;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component
@ -120,9 +123,6 @@ public class UserAccountForm implements TemplateComposer {
.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",
@ -144,16 +144,18 @@ public class UserAccountForm implements TemplateComposer {
.addField(FormBuilder.singleSelection(
Domain.USER.ATTR_LOCALE,
"sebserver.useraccount.form.language",
userAccount.getTimeZone().getID(),
() -> widgetFactory.getI18nSupport().getLanguageResources())
.withLocalizationSupplied())
userAccount.getLocale().getLanguage(),
widgetFactory.getI18nSupport().localizedLanguageResources()))
.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)
widgetFactory.getI18nSupport().localizedTimeZoneResources()))
.addField(FormBuilder.multiSelection(
USER_ROLE.REFERENCE_NAME,
"sebserver.useraccount.form.roles",
StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR),
widgetFactory.getI18nSupport().localizedUserRoleResources()))
.addField(FormBuilder.text(
UserMod.ATTR_NAME_NEW_PASSWORD,
"sebserver.useraccount.form.password",

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.content;
package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
@ -20,19 +20,19 @@ import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.content.action.UserAccountActions;
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.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.GetUserAccounts;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.service.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.service.table.EntityTable;
import ch.ethz.seb.sebserver.gui.service.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component

View file

@ -6,9 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.action;
package ch.ethz.seb.sebserver.gui.content.action;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.ImageIcon;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
public enum ActionDefinition {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.action;
package ch.ethz.seb.sebserver.gui.content.action;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.template.ImageCell;
@ -23,11 +23,12 @@ import org.springframework.stereotype.Component;
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.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEventListener;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.action;
package ch.ethz.seb.sebserver.gui.content.action;
import java.util.Collection;
import java.util.function.Function;
@ -16,11 +16,12 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
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.institution.ActivateInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
@ -88,12 +89,14 @@ public final class InstitutionActions {
}
private static Result<?> fromSelection(final Action action, final boolean edit) {
final Collection<String> selection = action.selectionSupplier.get();
if (selection.isEmpty()) {
return Result.ofError(new PageMessageException("sebserver.institution.info.pleaseSelect"));
}
return Result.tryCatch(() -> {
final Collection<String> selection = action.getSelectionSupplier().get();
if (selection.isEmpty()) {
throw new PageMessageException("sebserver.institution.info.pleaseSelect");
}
return Result.of(goToInstitution(action.pageContext, selection.iterator().next(), edit));
return goToInstitution(action.pageContext, selection.iterator().next(), edit);
});
}
private static ActivitySelection goToInstitution(

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.action;
package ch.ethz.seb.sebserver.gui.content.action;
import java.util.Collection;
import java.util.function.Function;
@ -16,11 +16,12 @@ 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.content.activity.Activity;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
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;
@ -87,12 +88,14 @@ public final class UserAccountActions {
}
private static Result<?> fromSelection(final Action action, final boolean edit) {
final Collection<String> selection = action.selectionSupplier.get();
if (selection.isEmpty()) {
return Result.ofError(new PageMessageException("sebserver.useraccount.info.pleaseSelect"));
}
return Result.tryCatch(() -> {
final Collection<String> selection = action.getSelectionSupplier().get();
if (selection.isEmpty()) {
throw new PageMessageException("sebserver.useraccount.info.pleaseSelect");
}
return Result.of(goToUserAccount(action.pageContext, selection.iterator().next(), edit));
return goToUserAccount(action.pageContext, selection.iterator().next(), edit);
});
}
private static ActivitySelection goToUserAccount(

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.activity;
package ch.ethz.seb.sebserver.gui.content.activity;
import java.util.Collection;
import java.util.EnumMap;
@ -26,12 +26,13 @@ import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
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.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivityActionHandler;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
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.activity.ActivitySelection.Activity;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
@ -39,8 +40,8 @@ import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component
@ -192,7 +193,7 @@ public class ActivitiesPane implements TemplateComposer {
final MainPageState mainPageState = MainPageState.get();
if (mainPageState.activitySelection == null ||
mainPageState.activitySelection.activity == ActivitySelection.Activity.NONE) {
mainPageState.activitySelection.activity == Activity.NONE) {
mainPageState.activitySelection = getActivitySelection(navigation.getItem(0));
}
pageContext.publishPageEvent(

View file

@ -0,0 +1,81 @@
/*
* 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.content.activity;
import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
import ch.ethz.seb.sebserver.gui.content.action.ActionPane;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
import ch.ethz.seb.sebserver.gui.service.page.impl.TODOTemplate;
public enum Activity {
NONE(TODOTemplate.class, TODOTemplate.class),
INSTITUTION_LIST(
InstitutionList.class,
ActionPane.class,
new LocTextKey("sebserver.activities.institution")),
INSTITUTION_FORM(
InstitutionForm.class,
ActionPane.class,
new LocTextKey("sebserver.activities.institution")),
USER_ACCOUNT_LIST(
UserAccountList.class,
ActionPane.class,
new LocTextKey("sebserver.activities.useraccount")),
USER_ACCOUNT_FORM(
UserAccountForm.class,
ActionPane.class,
new LocTextKey("sebserver.activities.useraccount")),
// USERS(UserAccountsForm.class, ActionPane.class),
//
// EXAMS(ExamsListPage.class, ActionPane.class),
// SEB_CONFIGS(SEBConfigurationForm.class, ActionPane.class),
// SEB_CONFIG(SEBConfigurationPage.class, ActionPane.class),
// SEB_CONFIG_TEMPLATES(TODOTemplate.class, ActionPane.class),
// MONITORING(MonitoringForm.class, ActionPane.class),
// RUNNING_EXAMS(RunningExamForm.class, ActionPane.class),
// RUNNING_EXAM(RunningExamPage.class, ActionPane.class, AttributeKeys.EXAM_ID),
// LOGS(TODOTemplate.class, ActionPane.class),
;
public final LocTextKey title;
public final Class<? extends TemplateComposer> contentPaneComposer;
public final Class<? extends TemplateComposer> actionPaneComposer;
//public final String modelIdAttribute;
private Activity(
final Class<? extends TemplateComposer> objectPaneComposer,
final Class<? extends TemplateComposer> selectionPaneComposer,
final LocTextKey title) {
this.title = title;
this.contentPaneComposer = objectPaneComposer;
this.actionPaneComposer = selectionPaneComposer;
}
private Activity(
final Class<? extends TemplateComposer> objectPaneComposer,
final Class<? extends TemplateComposer> selectionPaneComposer) {
this.title = null;
this.contentPaneComposer = objectPaneComposer;
this.actionPaneComposer = selectionPaneComposer;
}
public final ActivitySelection createSelection() {
return new ActivitySelection(this);
}
}

View file

@ -0,0 +1,63 @@
/*
* 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.form;
import java.util.function.BooleanSupplier;
abstract class FieldBuilder {
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 FieldBuilder(final String name, final String label, final String value) {
this.name = name;
this.label = label;
this.value = value;
}
public FieldBuilder withLabelSpan(final int span) {
this.spanLabel = span;
return this;
}
public FieldBuilder withInputSpan(final int span) {
this.spanInput = span;
return this;
}
public FieldBuilder withEmptyCellSpan(final int span) {
this.spanEmptyCell = span;
return this;
}
public FieldBuilder withEmptyCellSeparation(final boolean separation) {
this.autoEmptyCellSeparation = separation;
return this;
}
public FieldBuilder withGroup(final String group) {
this.group = group;
return this;
}
public FieldBuilder withCondition(final BooleanSupplier condition) {
this.condition = condition;
return this;
}
abstract void build(FormBuilder builder);
}

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.form;
package ch.ethz.seb.sebserver.gui.form;
import java.util.ArrayList;
import java.util.HashSet;
@ -16,13 +16,15 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
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;
@ -31,8 +33,9 @@ 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;
import ch.ethz.seb.sebserver.gui.service.widget.ImageUpload;
import ch.ethz.seb.sebserver.gui.service.widget.SingleSelection;
import ch.ethz.seb.sebserver.gui.widget.ImageUpload;
import ch.ethz.seb.sebserver.gui.widget.MultiSelection;
import ch.ethz.seb.sebserver.gui.widget.SingleSelection;
public final class Form implements FormBinding {
@ -40,7 +43,8 @@ public final class Form implements FormBinding {
private final ObjectNode objectRoot;
private final Map<String, String> staticValues = new LinkedHashMap<>();
private final Map<String, FormFieldAccessor> formFields = new LinkedHashMap<>();
private final MultiValueMap<String, FormFieldAccessor> formFields = new LinkedMultiValueMap<>();
//private final Map<String, List<FormFieldAccessor>> formFields = new LinkedHashMap<>();
private final Map<String, Form> subForms = new LinkedHashMap<>();
private final Map<String, List<Form>> subLists = new LinkedHashMap<>();
private final Map<String, Set<String>> groups = new LinkedHashMap<>();
@ -72,22 +76,26 @@ public final class Form implements FormBinding {
public String getFormUrlEncoded() {
final StringBuffer buffer = new StringBuffer();
for (final Map.Entry<String, String> entry : this.staticValues.entrySet()) {
appendFormUrlEncoded(buffer, entry.getKey(), entry.getValue());
appendFormUrlEncodedValue(buffer, entry.getKey(), entry.getValue());
}
for (final Map.Entry<String, FormFieldAccessor> entry : this.formFields.entrySet()) {
appendFormUrlEncoded(buffer, entry.getKey(), entry.getValue().getValue());
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
entry.getValue()
.stream()
.forEach(ffa -> appendFormUrlEncodedValue(buffer, entry.getKey(), ffa.getValue()));
}
return buffer.toString();
}
public String getValue(final String name) {
final FormFieldAccessor formFieldAccessor = this.formFields.get(name);
if (formFieldAccessor != null) {
return formFieldAccessor.getValue();
public List<String> getValue(final String name) {
if (this.formFields.containsKey(name)) {
return this.formFields
.get(name)
.stream()
.map(ffa -> ffa.getValue())
.collect(Collectors.toList());
}
return null;
}
@ -109,23 +117,25 @@ public final class Form implements FormBinding {
}
public Form putField(final String name, final Label label, final Label field) {
this.formFields.put(name, createAccessor(label, field));
this.formFields.add(name, createAccessor(label, field));
return this;
}
public Form putField(final String name, final Label label, final Text field) {
this.formFields.put(name, createAccessor(label, field));
this.formFields.add(name, createAccessor(label, field));
return this;
}
public void putField(final String name, final Label label, final Combo field) {
if (field instanceof SingleSelection) {
this.formFields.put(name, createAccessor(label, (SingleSelection) field));
}
public void putField(final String name, final Label label, final SingleSelection field) {
this.formFields.add(name, createAccessor(label, field));
}
public void putField(final String name, final Label label, final MultiSelection field) {
this.formFields.add(name, createAccessor(label, field));
}
public void putField(final String name, final Label label, final ImageUpload imageUpload) {
this.formFields.put(name, createAccessor(label, imageUpload));
this.formFields.add(name, createAccessor(label, imageUpload));
}
public void putSubForm(final String name, final Form form) {
@ -174,7 +184,7 @@ public final class Form implements FormBinding {
this.formFields.entrySet()
.stream()
.filter(entity -> nameFilter.test(entity.getKey()))
.map(entity -> entity.getValue())
.flatMap(entity -> entity.getValue().stream())
.forEach(processor);
}
@ -183,11 +193,10 @@ public final class Form implements FormBinding {
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()) {
this.objectRoot.put(entry.getKey(), accessor.getValue());
}
for (final Map.Entry<String, List<FormFieldAccessor>> entry : this.formFields.entrySet()) {
entry.getValue()
.stream()
.forEach(ffa -> this.objectRoot.put(entry.getKey(), ffa.getValue()));
}
for (final Map.Entry<String, Form> entry : this.subForms.entrySet()) {
@ -231,7 +240,15 @@ public final class Form implements FormBinding {
@Override public void setValue(final String value) { singleSelection.select(value); }
};
}
private FormFieldAccessor createAccessor(
final Label label,
final MultiSelection multiSelection) {
return new FormFieldAccessor(label, multiSelection) {
@Override public String getValue() { return multiSelection.getSelectionValue(); }
@Override public void setValue(final String value) { multiSelection.select(value); }
};
}
private FormFieldAccessor createAccessor(final Label label, final ImageUpload imageUpload) {
return new FormFieldAccessor(label, imageUpload) {
@Override public String getValue() { return imageUpload.getImageBase64(); }
@ -240,14 +257,24 @@ 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);
/*
* Adds the given name and value in from URL encoded format to the given StringBuffer.
* Checks first if the value String is a comma separated list. If true, splits values
* and adds every value within the same name mapping to the string buffer
*/
private void appendFormUrlEncodedValue(final StringBuffer buffer, final String name, final String value) {
final String[] split = StringUtils.split(value, Constants.LIST_SEPARATOR_CHAR);
if (split != null) {
for (int i = 0; i < split.length; i++) {
if (StringUtils.isNoneBlank(split[i])) {
if (buffer.length() > 0) {
buffer.append(Constants.FORM_URL_ENCODED_SEPARATOR);
}
buffer.append(name)
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
.append(split[i]);
}
}
buffer.append(name)
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
.append(value);
}
}

View file

@ -0,0 +1,223 @@
/*
* Copyright (c) 2018 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.form;
import java.util.List;
import java.util.function.BooleanSupplier;
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.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabItem;
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;
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.widget.WidgetFactory;
public class FormBuilder {
private static final Logger log = LoggerFactory.getLogger(FormBuilder.class);
final WidgetFactory widgetFactory;
private final PolyglotPageService polyglotPageService;
public final PageContext pageContext;
public final Composite formParent;
public final Form form;
boolean readonly = false;
private int defaultSpanLabel = 1;
private int defaultSpanInput = 2;
private int defaultSpanEmptyCell = 1;
private boolean emptyCellSeparation = true;
FormBuilder(
final EntityKey entityKey,
final JSONMapper jsonMapper,
final WidgetFactory widgetFactory,
final PolyglotPageService polyglotPageService,
final PageContext pageContext,
final int rows) {
this.widgetFactory = widgetFactory;
this.polyglotPageService = polyglotPageService;
this.pageContext = pageContext;
this.form = new Form(jsonMapper, entityKey);
this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
final GridLayout layout = new GridLayout(rows, true);
layout.horizontalSpacing = 10;
layout.verticalSpacing = 10;
layout.marginLeft = 10;
layout.marginTop = 10;
this.formParent.setLayout(layout);
this.formParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
public FormBuilder readonly(final boolean readonly) {
this.readonly = readonly;
return this;
}
public FormBuilder setVisible(final boolean visible, final String group) {
this.form.setVisible(visible, group);
return this;
}
public FormBuilder setControl(final TabItem instTab) {
instTab.setControl(this.formParent);
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) {
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;
}
public FormBuilder putStaticValue(final String name, final String value) {
try {
this.form.putStatic(name, value);
} catch (final Exception e) {
log.error("Failed to put static field value to json object: ", e);
}
return this;
}
public FormBuilder addField(final FieldBuilder 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;
if (template.autoEmptyCellSeparation && this.form.hasFields()) {
addEmptyCell(template.spanEmptyCell);
}
template.build(this);
if (StringUtils.isNoneBlank(template.group)) {
this.form.addToGroup(template.group, template.name);
}
}
return this;
}
public <T> FormHandle<T> buildFor(
final RestCall<T> post,
final Function<T, T> postPostHandle) {
return new FormHandle<>(
this.pageContext,
this.form,
post,
(postPostHandle == null) ? Function.identity() : postPostHandle,
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 TextFieldBuilder text(final String name, final String label, final String value) {
return new TextFieldBuilder(name, label, value);
}
public static SelectionFieldBuilder singleSelection(
final String name,
final String label,
final String value,
final Supplier<List<Tuple<String>>> itemsSupplier) {
return new SelectionFieldBuilder(name, label, value, itemsSupplier);
}
public static SelectionFieldBuilder multiSelection(
final String name,
final String label,
final String value,
final Supplier<List<Tuple<String>>> itemsSupplier) {
return new SelectionFieldBuilder(name, label, value, itemsSupplier)
.asMultiSelection();
}
public static ImageUploadFieldBuilder imageUpload(final String name, final String label, final String value) {
return new ImageUploadFieldBuilder(name, label, value);
}
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.TOP, true, false, hspan, 1);
gridData.verticalIndent = 5;
label.setLayoutData(gridData);
return label;
}
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;
}
}

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.form;
package ch.ethz.seb.sebserver.gui.form;
import java.util.function.Consumer;
import java.util.function.Function;
@ -15,13 +15,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.form.Form.FormFieldAccessor;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.Form.FormFieldAccessor;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.FieldValidationError;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;

View file

@ -0,0 +1,37 @@
/*
* 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.form;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.widget.ImageUpload;
public final class ImageUploadFieldBuilder extends FieldBuilder {
ImageUploadFieldBuilder(final String name, final String label, final String value) {
super(name, label, value);
}
@Override
void build(final FormBuilder builder) {
final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
final ImageUpload imageUpload = builder.widgetFactory.imageUploadLocalized(
builder.formParent,
new LocTextKey("sebserver.overall.upload"),
builder.readonly);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
imageUpload.setLayoutData(gridData);
imageUpload.setImageBase64(this.value);
builder.form.putField(this.name, lab, imageUpload);
}
}

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.form;
package ch.ethz.seb.sebserver.gui.form;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -16,7 +16,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
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.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component

View file

@ -0,0 +1,122 @@
/*
* 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.form;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.widget.MultiSelection;
import ch.ethz.seb.sebserver.gui.widget.Selection;
import ch.ethz.seb.sebserver.gui.widget.SingleSelection;
public final class SelectionFieldBuilder extends FieldBuilder {
final Supplier<List<Tuple<String>>> itemsSupplier;
Consumer<Form> selectionListener = null;
boolean multi = false;
SelectionFieldBuilder(
final String name,
final String label,
final String value,
final Supplier<List<Tuple<String>>> itemsSupplier) {
super(name, label, value);
this.itemsSupplier = itemsSupplier;
}
public SelectionFieldBuilder withSelectionListener(final Consumer<Form> selectionListener) {
this.selectionListener = selectionListener;
return this;
}
public SelectionFieldBuilder asMultiSelection() {
this.multi = true;
return this;
}
@Override
void build(final FormBuilder builder) {
final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
if (builder.readonly) {
buildReadOnly(builder, lab);
} else {
buildInput(builder, lab);
}
}
private void buildInput(final FormBuilder builder, final Label lab) {
final Selection selection = (this.multi)
? builder.widgetFactory.multiSelectionLocalized(builder.formParent, this.itemsSupplier)
: builder.widgetFactory.singleSelectionLocalized(builder.formParent, this.itemsSupplier);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
((Control) selection).setLayoutData(gridData);
selection.select(this.value);
if (this.multi) {
builder.form.putField(this.name, lab, (MultiSelection) selection);
} else {
builder.form.putField(this.name, lab, (SingleSelection) selection);
}
if (this.selectionListener != null) {
((Control) selection).addListener(SWT.Selection, e -> {
this.selectionListener.accept(builder.form);
});
}
}
/* Build the read-only representation of the selection field */
private void buildReadOnly(final FormBuilder builder, final Label lab) {
builder.form.putField(
this.name, lab,
builder.valueLabel(
builder.formParent,
getSelectionValue(this.value, this.multi),
this.spanInput));
}
/*
* For Single selection just the selected value, for multi selection a comma
* separated list of values within a String value.
*
* @param key the key or keys, in case of multi selection a comma separated String of keys
*
* @param multi indicates multi seleciton
*
* @return selected value or comma separated String list of selected values
*/
private String getSelectionValue(final String key, final boolean multi) {
if (multi) {
final Collection<String> keys = Arrays.asList(StringUtils.split(key, Constants.LIST_SEPARATOR));
return StringUtils.join(this.itemsSupplier.get().stream()
.filter(tuple -> keys.contains(tuple._1))
.map(tuple -> tuple._2)
.collect(Collectors.toList()),
Constants.LIST_SEPARATOR);
} else {
return this.itemsSupplier.get().stream()
.filter(tuple -> key.equals(tuple._1))
.findFirst()
.map(tuple -> tuple._2)
.orElse(null);
}
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.form;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public final class TextFieldBuilder extends FieldBuilder {
boolean isPassword = false;
TextFieldBuilder(final String name, final String label, final String value) {
super(name, label, value);
}
public TextFieldBuilder asPasswordField() {
this.isPassword = true;
return this;
}
@Override
void build(final FormBuilder builder) {
if (this.isPassword && builder.readonly) {
return;
}
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);
}
}
}

View file

@ -1,391 +0,0 @@
/*
* Copyright (c) 2018 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.form;
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.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;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
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 {
private static final Logger log = LoggerFactory.getLogger(FormBuilder.class);
private final WidgetFactory widgetFactory;
private final PolyglotPageService polyglotPageService;
public final PageContext pageContext;
public final Composite formParent;
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,
final JSONMapper jsonMapper,
final WidgetFactory widgetFactory,
final PolyglotPageService polyglotPageService,
final PageContext pageContext,
final int rows) {
this.widgetFactory = widgetFactory;
this.polyglotPageService = polyglotPageService;
this.pageContext = pageContext;
this.form = new Form(jsonMapper, entityKey);
this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
final GridLayout layout = new GridLayout(rows, true);
layout.horizontalSpacing = 10;
layout.verticalSpacing = 10;
layout.marginLeft = 10;
layout.marginTop = 10;
this.formParent.setLayout(layout);
this.formParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
public FormBuilder readonly(final boolean readonly) {
this.readonly = readonly;
return this;
}
public FormBuilder setVisible(final boolean visible, final String group) {
this.form.setVisible(visible, group);
return this;
}
public FormBuilder setControl(final TabItem instTab) {
instTab.setControl(this.formParent);
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) {
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;
}
public FormBuilder putStaticValue(final String name, final String value) {
try {
this.form.putStatic(name, value);
} catch (final Exception e) {
log.error("Failed to put static field value to json object: ", e);
}
return this;
}
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);
}
return this;
}
public <T> FormHandle<T> buildFor(
final RestCall<T> post,
final Function<T, T> postPostHandle) {
return new FormHandle<>(
this.pageContext,
this.form,
post,
(postPostHandle == null) ? Function.identity() : postPostHandle,
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;
}
}

View file

@ -8,15 +8,19 @@
package ch.ethz.seb.sebserver.gui.service.i18n;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.function.Supplier;
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.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
public interface I18nSupport {
@ -78,14 +82,30 @@ 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 Supplier<List<Tuple<String>>> localizedResourceSupplier(final List<Tuple<String>> source) {
return () -> source.stream()
.map(tuple -> new Tuple<>(tuple._1, getText(tuple._2)))
.collect(Collectors.toList());
}
default List<Tuple<String>> getTimeZoneResources() {
return getTimeZoneResources(this);
default Supplier<List<Tuple<String>>> localizedLanguageResources() {
return () -> getLanguageResources(this);
}
default Supplier<List<Tuple<String>>> localizedTimeZoneResources() {
return () -> getTimeZoneResources(this);
}
default Supplier<List<Tuple<String>>> localizedUserRoleResources() {
return localizedResourceSupplier(USER_ROLE_RESOURCES);
}
final List<Tuple<String>> USER_ROLE_RESOURCES = Collections.unmodifiableList(
Arrays.asList(UserRole.values())
.stream()
.map(ur -> new Tuple<>(ur.name(), "sebserver.useraccount.role." + ur.name()))
.collect(Collectors.toList()));
/** Get a list of language key/name tuples for all supported languages in the
* language of the current users locale.
*

View file

@ -12,9 +12,9 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;

View file

@ -17,6 +17,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
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.PageMessageException;
@ -29,16 +30,17 @@ public final class Action implements Runnable {
private static final Logger log = LoggerFactory.getLogger(Action.class);
public final RestService restService;
public final PageContext pageContext;
public final ActionDefinition definition;
Supplier<LocTextKey> confirm;
LocTextKey successMessage;
boolean updateOnSelection;
final RestService restService;
final PageContext pageContext;
Function<Action, Result<?>> exec;
Supplier<Set<String>> selectionSupplier;
private Function<Action, Result<?>> exec;
public Action(
final ActionDefinition definition,
final PageContext pageContext,
@ -90,6 +92,10 @@ public final class Action implements Runnable {
}
}
public Supplier<Set<String>> getSelectionSupplier() {
return this.selectionSupplier;
}
public Action withExec(final Function<Action, Result<?>> exec) {
this.exec = exec;
return this;

View file

@ -10,8 +10,8 @@ package ch.ethz.seb.sebserver.gui.service.page.activity;
import org.eclipse.swt.widgets.Tree;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
public interface ActivityActionHandler {

View file

@ -16,15 +16,8 @@ import java.util.function.Consumer;
import org.eclipse.swt.widgets.TreeItem;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
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;
public class ActivitySelection {
@ -35,73 +28,11 @@ public class ActivitySelection {
ti.setItemCount(1);
};
public enum Activity {
NONE(TODOTemplate.class, TODOTemplate.class),
INSTITUTION_LIST(
InstitutionList.class,
ActionPane.class,
new LocTextKey("sebserver.activities.institution")),
INSTITUTION_FORM(
InstitutionForm.class,
ActionPane.class,
new LocTextKey("sebserver.activities.institution")),
USER_ACCOUNT_LIST(
UserAccountList.class,
ActionPane.class,
new LocTextKey("sebserver.activities.useraccount")),
USER_ACCOUNT_FORM(
UserAccountForm.class,
ActionPane.class,
new LocTextKey("sebserver.activities.useraccount")),
// USERS(UserAccountsForm.class, ActionPane.class),
//
// EXAMS(ExamsListPage.class, ActionPane.class),
// SEB_CONFIGS(SEBConfigurationForm.class, ActionPane.class),
// SEB_CONFIG(SEBConfigurationPage.class, ActionPane.class),
// SEB_CONFIG_TEMPLATES(TODOTemplate.class, ActionPane.class),
// MONITORING(MonitoringForm.class, ActionPane.class),
// RUNNING_EXAMS(RunningExamForm.class, ActionPane.class),
// RUNNING_EXAM(RunningExamPage.class, ActionPane.class, AttributeKeys.EXAM_ID),
// LOGS(TODOTemplate.class, ActionPane.class),
;
public final LocTextKey title;
public final Class<? extends TemplateComposer> contentPaneComposer;
public final Class<? extends TemplateComposer> actionPaneComposer;
//public final String modelIdAttribute;
private Activity(
final Class<? extends TemplateComposer> objectPaneComposer,
final Class<? extends TemplateComposer> selectionPaneComposer,
final LocTextKey title) {
this.title = title;
this.contentPaneComposer = objectPaneComposer;
this.actionPaneComposer = selectionPaneComposer;
}
private Activity(
final Class<? extends TemplateComposer> objectPaneComposer,
final Class<? extends TemplateComposer> selectionPaneComposer) {
this.title = null;
this.contentPaneComposer = objectPaneComposer;
this.actionPaneComposer = selectionPaneComposer;
}
public final ActivitySelection createSelection() {
return new ActivitySelection(this);
}
}
public final Activity activity;
final Map<String, String> attributes;
Consumer<TreeItem> expandFunction = EMPTY_FUNCTION;
ActivitySelection(final Activity activity) {
public ActivitySelection(final Activity activity) {
this.activity = activity;
this.attributes = new HashMap<>();
}

View file

@ -8,7 +8,7 @@
package ch.ethz.seb.sebserver.gui.service.page.event;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
/** This Event is used to propagate a user-action to the GUI system.
* Potentially every component can listen to an Event and react on the user-action */

View file

@ -13,7 +13,7 @@ import java.util.function.Predicate;
import org.eclipse.swt.widgets.Widget;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
public interface ActionEventListener extends PageEventListener<ActionEvent> {

View file

@ -27,7 +27,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Service

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.page.impl;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gui.content.LoginPage;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.page.impl;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gui.content.MainPage;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;

View file

@ -36,9 +36,9 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.widget.Message;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
import ch.ethz.seb.sebserver.gui.widget.Message;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component

View file

@ -1,6 +1,6 @@
/*
* 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/.
@ -11,12 +11,17 @@ package ch.ethz.seb.sebserver.gui.service.page.impl;
import javax.servlet.http.HttpSession;
import org.eclipse.rap.rwt.RWT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gui.content.MainPage;
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.Activity;
public final class MainPageState {
private static final Logger log = LoggerFactory.getLogger(MainPageState.class);
public ActivitySelection activitySelection = Activity.NONE.createSelection();
private MainPageState() {
@ -36,7 +41,7 @@ public final class MainPageState {
return mainPageState;
} catch (final Exception e) {
MainPage.log.error("Unexpected error while trying to get MainPageState from user-session");
log.error("Unexpected error while trying to get MainPageState from user-session");
}
return null;

View file

@ -28,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
@ -35,12 +36,11 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.widget.Message;
import ch.ethz.seb.sebserver.gui.widget.Message;
public class PageContextImpl implements PageContext {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.table;
package ch.ethz.seb.sebserver.gui.table;
import java.util.List;
import java.util.function.Function;
@ -14,7 +14,7 @@ import java.util.function.Function;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
public final class ColumnDefinition<ROW extends Entity> {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.table;
package ch.ethz.seb.sebserver.gui.table;
import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY;
@ -35,8 +35,8 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.ImageIcon;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder;
public class EntityTable<ROW extends Entity> extends Composite {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.table;
package ch.ethz.seb.sebserver.gui.table;
import java.util.ArrayList;
import java.util.List;
@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Composite;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
/** <code>
* new TableBuilder<T>(RestCall)

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.table;
package ch.ethz.seb.sebserver.gui.table;
import java.util.Arrays;
import java.util.List;
@ -25,9 +25,9 @@ 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.SingleSelection;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.ImageIcon;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.widget.SingleSelection;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
public class TableFilter<ROW extends Entity> extends Composite {
@ -241,11 +241,11 @@ public class TableFilter<ROW extends Entity> extends Composite {
@Override
FilterComponent build(final Composite parent) {
this.selector = TableFilter.this.entityTable.widgetFactory
.singleSelectionLocalizedSupplier(
.singleSelectionLocalized(
parent,
() -> TableFilter.this.entityTable.widgetFactory
TableFilter.this.entityTable.widgetFactory
.getI18nSupport()
.getLanguageResources());
.localizedLanguageResources());
this.selector.setLayoutData(this.rowData);
return this;
}

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.table;
package ch.ethz.seb.sebserver.gui.table;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
public class TableNavigator extends Composite {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.table;
package ch.ethz.seb.sebserver.gui.table;
public class TableRowAction {

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.widget;
package ch.ethz.seb.sebserver.gui.widget;
import java.io.ByteArrayInputStream;
import java.io.IOException;

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.widget;
package ch.ethz.seb.sebserver.gui.widget;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.graphics.Rectangle;

View file

@ -0,0 +1,128 @@
/*
* 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.widget;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
public class MultiSelection extends Composite implements Selection {
private static final long serialVersionUID = 2730206903047681378L;
private static final String OPTION_VALUE = "OPTION_VALUE";
private final List<Label> labels = new ArrayList<>();
private final List<Label> selected = new ArrayList<>();
public MultiSelection(final Composite parent) {
super(parent, SWT.NONE);
final GridLayout gridLayout = new GridLayout(1, true);
gridLayout.verticalSpacing = 1;
gridLayout.marginLeft = 0;
setLayout(gridLayout);
}
@Override
public void applyNewMapping(final List<Tuple<String>> mapping) {
final String selectionValue = getSelectionValue();
this.selected.clear();
for (final Tuple<String> tuple : mapping) {
final Label label = new Label(this, SWT.NONE);
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
label.setLayoutData(gridData);
label.setData(OPTION_VALUE, tuple._1);
label.setData(RWT.CUSTOM_VARIANT, "selection");
label.setText(" " + tuple._2);
label.addListener(SWT.MouseDown, event -> {
final Label l = (Label) event.widget;
if (this.selected.contains(l)) {
l.setData(RWT.CUSTOM_VARIANT, "selection");
this.selected.remove(l);
} else {
l.setData(RWT.CUSTOM_VARIANT, "selected");
this.selected.add(l);
}
});
}
select(selectionValue);
}
public void selectOne(final String key) {
this.labels.stream()
.filter(label -> key.equals(label.getData(OPTION_VALUE)))
.findFirst()
.ifPresent(label -> {
label.setData(RWT.CUSTOM_VARIANT, "selected");
this.selected.add(label);
});
}
public void deselect(final String key) {
this.selected.stream()
.filter(label -> key.equals(label.getData(OPTION_VALUE)))
.findFirst()
.ifPresent(label -> {
label.setData(RWT.CUSTOM_VARIANT, "selection");
this.selected.remove(label);
});
}
public void deselectAll() {
for (final Label label : this.selected) {
label.setData(RWT.CUSTOM_VARIANT, "selection");
}
this.selected.clear();
}
@Override
public void select(final String keys) {
this.selected.clear();
if (StringUtils.isNotBlank(keys)) {
final List<String> split = Arrays.asList(keys.split(keys, Constants.LIST_SEPARATOR_CHAR));
for (final Label label : this.labels) {
if (split.contains(label.getData(OPTION_VALUE))) {
label.setData(RWT.CUSTOM_VARIANT, "selected");
this.selected.add(label);
}
}
}
}
@Override
public String getSelectionValue() {
if (this.selected.isEmpty()) {
return null;
}
return StringUtils.join(
this.selected
.stream()
.map(label -> (String) label.getData(OPTION_VALUE))
.collect(Collectors.toList()),
Constants.LIST_SEPARATOR_CHAR);
}
@Override
public void clear() {
deselectAll();
}
}

View file

@ -0,0 +1,25 @@
/*
* 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.widget;
import java.util.List;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
public interface Selection {
void applyNewMapping(final List<Tuple<String>> mapping);
void select(final String keys);
String getSelectionValue();
void clear();
}

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.widget;
package ch.ethz.seb.sebserver.gui.widget;
import java.util.ArrayList;
import java.util.List;
@ -18,21 +18,21 @@ import org.eclipse.swt.widgets.Composite;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
public class SingleSelection extends Combo {
public class SingleSelection extends Combo implements Selection {
private static final long serialVersionUID = 6522063655406404279L;
final List<String> valueMapping;
final List<String> keyMapping;
public SingleSelection(final Composite parent, final List<Tuple<String>> mapping) {
public SingleSelection(final Composite parent) {
super(parent, SWT.READ_ONLY);
this.valueMapping = new ArrayList<>();
this.keyMapping = new ArrayList<>();
applyNewMapping(mapping);
}
protected void applyNewMapping(final List<Tuple<String>> mapping) {
@Override
public void applyNewMapping(final List<Tuple<String>> mapping) {
final String selectionValue = getSelectionValue();
this.valueMapping.clear();
this.keyMapping.clear();
@ -46,6 +46,7 @@ public class SingleSelection extends Combo {
select(selectionValue);
}
@Override
public void select(final String key) {
final int selectionindex = this.keyMapping.indexOf(key);
if (selectionindex < 0) {
@ -55,6 +56,7 @@ public class SingleSelection extends Combo {
super.select(selectionindex);
}
@Override
public String getSelectionValue() {
final int selectionindex = super.getSelectionIndex();
if (selectionindex < 0) {
@ -64,6 +66,7 @@ public class SingleSelection extends Combo {
return this.keyMapping.get(selectionindex);
}
@Override
public void clear() {
super.clearSelection();
super.setItems(this.valueMapping.toArray(new String[this.valueMapping.size()]));

View file

@ -6,12 +6,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.widget;
package ch.ethz.seb.sebserver.gui.widget;
import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.*;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
@ -26,7 +25,6 @@ import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
@ -45,16 +43,16 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
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.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.table.TableBuilder;
import ch.ethz.seb.sebserver.gui.table.TableBuilder;
@Lazy
@Service
@ -311,45 +309,24 @@ public class WidgetFactory {
public SingleSelection singleSelectionLocalized(
final Composite parent,
final List<Tuple<String>> items) {
final Supplier<List<Tuple<String>>> itemsSupplier) {
final SingleSelection combo = new SingleSelection(parent, items);
this.injectI18n(combo, combo.valueMapping);
return combo;
final SingleSelection singleSelection = new SingleSelection(parent);
final Consumer<SingleSelection> updateFunction = ss -> ss.applyNewMapping(itemsSupplier.get());
singleSelection.setData(POLYGLOT_WIDGET_FUNCTION_KEY, updateFunction);
updateFunction.accept(singleSelection);
return singleSelection;
}
public SingleSelection singleSelectionLocalizedSupplier(
public MultiSelection multiSelectionLocalized(
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,
final LocTextKey locTextKey,
final int hspan,
final int vspan,
final boolean readonly) {
final ImageUpload imageUpload = imageUploadLocalized(parent, locTextKey, readonly);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan);
imageUpload.setLayoutData(gridData);
imageUpload.setImageBase64(value);
return imageUpload;
final MultiSelection multiSelection = new MultiSelection(parent);
final Consumer<MultiSelection> updateFunction = ss -> ss.applyNewMapping(itemsSupplier.get());
multiSelection.setData(POLYGLOT_WIDGET_FUNCTION_KEY, updateFunction);
updateFunction.accept(multiSelection);
return multiSelection;
}
public ImageUpload imageUploadLocalized(
@ -363,7 +340,11 @@ public class WidgetFactory {
}
public void injectI18n(final ImageUpload imageUpload, final LocTextKey locTextKey) {
final Consumer<ImageUpload> imageUploadFunction = imageUploadFunction(locTextKey, this.i18nSupport);
final Consumer<ImageUpload> imageUploadFunction = iu -> {
if (locTextKey != null) {
iu.setSelectionText(this.i18nSupport.getText(locTextKey));
}
};
imageUpload.setData(POLYGLOT_WIDGET_FUNCTION_KEY, imageUploadFunction);
imageUploadFunction.accept(imageUpload);
}
@ -383,13 +364,22 @@ public class WidgetFactory {
}
public void injectI18n(final Button button, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
final Consumer<Button> buttonFunction = buttonFunction(locTextKey, locToolTipKey, this.i18nSupport);
final Consumer<Button> buttonFunction = b -> {
if (locTextKey != null) {
b.setText(this.i18nSupport.getText(locTextKey));
}
if (locToolTipKey != null) {
b.setToolTipText(this.i18nSupport.getText(locToolTipKey));
}
};
button.setData(POLYGLOT_WIDGET_FUNCTION_KEY, buttonFunction);
buttonFunction.accept(button);
}
public void injectI18n(final Tree tree) {
tree.setData(POLYGLOT_WIDGET_FUNCTION_KEY, treeFunction(this.i18nSupport));
tree.setData(
POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<Tree>) t -> updateLocale(t.getItems(), this.i18nSupport));
}
public void injectI18n(final TreeItem treeItem, final LocTextKey locTextKey) {
@ -398,7 +388,12 @@ public class WidgetFactory {
}
public void injectI18n(final Table table) {
table.setData(POLYGLOT_WIDGET_FUNCTION_KEY, tableFunction(this.i18nSupport));
table.setData(
POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<Table>) t -> {
updateLocale(t.getColumns(), this.i18nSupport);
updateLocale(t.getItems(), this.i18nSupport);
});
}
public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
@ -422,17 +417,15 @@ public class WidgetFactory {
}
}
public void injectI18n(final Combo combo, final List<String> items) {
final Consumer<Combo> comboFunction = comboFunction(items, this.i18nSupport);
combo.setData(POLYGLOT_WIDGET_FUNCTION_KEY, comboFunction);
comboFunction.accept(combo);
}
public void createLanguageSelector(final PageContext composerCtx) {
for (final Locale locale : this.i18nSupport.supportedLanguages()) {
final Label languageSelection = new Label(composerCtx.getParent(), SWT.NONE);
languageSelection.setData(POLYGLOT_WIDGET_FUNCTION_KEY,
langSelectionLabelFunction(locale, this.i18nSupport));
languageSelection.setData(
POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<Label>) label -> label.setVisible(
!this.i18nSupport.getCurrentLocale()
.getLanguage()
.equals(locale.getLanguage())));
languageSelection.setData(RWT.CUSTOM_VARIANT, "header");
languageSelection.setText("| " + locale.getLanguage().toUpperCase());
//languageSelection.updateLocale(this.i18nSupport);
@ -452,38 +445,6 @@ public class WidgetFactory {
}
}
private static Consumer<ImageUpload> imageUploadFunction(
final LocTextKey locTextKey,
final I18nSupport i18nSupport) {
return imageUpload -> {
if (locTextKey != null) {
imageUpload.setSelectionText(i18nSupport.getText(locTextKey));
}
};
}
private static Consumer<Tree> treeFunction(final I18nSupport i18nSupport) {
return tree -> updateLocale(tree.getItems(), i18nSupport);
}
private static Consumer<Table> tableFunction(final I18nSupport i18nSupport) {
return table -> {
updateLocale(table.getColumns(), i18nSupport);
updateLocale(table.getItems(), i18nSupport);
};
}
private static final Consumer<Label> langSelectionLabelFunction(
final Locale locale,
final I18nSupport i18nSupport) {
return label -> label.setVisible(
!i18nSupport.getCurrentLocale()
.getLanguage()
.equals(locale.getLanguage()));
}
private static final Consumer<Label> labelFunction(
final LocTextKey locTextKey,
final LocTextKey locToolTipKey,
@ -511,35 +472,6 @@ public class WidgetFactory {
};
}
private static final Consumer<Combo> comboFunction(
final List<String> items,
final I18nSupport i18nSupport) {
return combo -> {
int i = 0;
final Iterator<String> iterator = items.iterator();
while (iterator.hasNext()) {
combo.setItem(i, i18nSupport.getText(iterator.next()));
i++;
}
};
}
private static final Consumer<Button> buttonFunction(
final LocTextKey locTextKey,
final LocTextKey locToolTipKey,
final I18nSupport i18nSupport) {
return button -> {
if (locTextKey != null) {
button.setText(i18nSupport.getText(locTextKey));
}
if (locToolTipKey != null) {
button.setToolTipText(i18nSupport.getText(locToolTipKey));
}
};
}
private static final void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) {
if (items == null) {
return;

View file

@ -89,6 +89,11 @@ sebserver.institution.form.logoImage=Logo Image
# User Account
################################
sebserver.useraccount.role.SEB_SERVER_ADMIN=SEB Server Administrator
sebserver.useraccount.role.INSTITUTIONAL_ADMIN=Institutional Administrator
sebserver.useraccount.role.EXAM_ADMIN=Exam Administrator
sebserver.useraccount.role.EXAM_SUPPORTER=Exam Supporter
sebserver.useraccount.list.title=User Accounts
sebserver.useraccount.list.column.name=Name
sebserver.useraccount.list.column.username=User Name
@ -114,6 +119,7 @@ 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.roles=User Roles
sebserver.useraccount.form.password=Password
sebserver.useraccount.form.password.retyped=Retyped Password

View file

@ -62,18 +62,29 @@ Label.h3 {
color: #1f407a;
}
/*
Label:hover.imageButton {
background-color: #82BE1E;
background-gradient-color: #82BE1E;
background-image: gradient( linear, left top, left bottom, from( #82BE1E ), to( #82BE1E ) );
}*/
Label:hover.imageButton {
background-color: transparent;
background-repeat: no-repeat;
}
Label.selection {
padding: 4px 6px 3px 6px;
}
Label:hover.selection {
color: #4a4a4a;
background-color: #b5b5b5;
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
padding: 4px 6px 3px 6px;
}
Label.selected {
color: #4a4a4a;
background-color: #b5b5b5;
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
padding: 4px 6px 3px 6px;
}
Composite.bordered {
border: 2px;
}
@ -391,12 +402,12 @@ Tree-RowOverlay:hover {
}
Tree-RowOverlay:selected {
background-color: #D3D9DB;
background-color: #b5b5b5;
color: #1F407A;
}
Tree-RowOverlay:selected:unfocused {
background-color: #D3D9DB;
background-color: #b5b5b5;
color: #1f407a;
}