From e799a0214f651a234a66b276c755401a8b8d3299 Mon Sep 17 00:00:00 2001 From: anhefti Date: Tue, 5 Mar 2019 11:08:50 +0100 Subject: [PATCH] SEBSERV-25 finished table --- .../ch/ethz/seb/sebserver/gbl/model/Page.java | 6 + .../gui/content/InstitutionList.java | 5 +- .../sebserver/gui/content/LmsSetupForm.java | 42 +++++ .../sebserver/gui/content/LmsSetupList.java | 126 +++++++++++++++ .../gui/content/UserAccountForm.java | 43 +++--- .../gui/content/UserAccountList.java | 52 +++++-- .../gui/content/action/ActionDefinition.java | 36 ++--- .../content/action/UserAccountActions.java | 61 -------- .../gui/content/activity/ActivitiesPane.java | 8 + .../gui/service/ResourceService.java | 144 ++++++++++++++++++ .../gui/service/i18n/I18nSupport.java | 49 ------ .../service/i18n/impl/I18nSupportImpl.java | 14 -- .../sebserver/gui/service/page/PageUtils.java | 28 ++-- .../page/impl/ComposerServiceImpl.java | 4 +- .../remote/webservice/api/BuildErrorCall.java | 26 ---- .../webservice/api/lmssetup/GetLmsSetup.java | 37 +++++ .../webservice/api/lmssetup/GetLmsSetups.java | 38 +++++ .../sebserver/gui/table/ColumnDefinition.java | 31 ++-- .../seb/sebserver/gui/table/EntityTable.java | 128 +++++++++------- .../seb/sebserver/gui/table/TableBuilder.java | 21 ++- .../seb/sebserver/gui/table/TableFilter.java | 69 +++++---- .../sebserver/gui/table/TableNavigator.java | 62 +++++--- .../sebserver/gui/widget/MultiSelection.java | 3 +- .../sebserver/gui/widget/WidgetFactory.java | 11 -- src/main/resources/messages.properties | 26 +++- 25 files changed, 723 insertions(+), 347 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java delete mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/content/action/UserAccountActions.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java delete mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/BuildErrorCall.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetup.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetups.java diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java index 0e97a19b..a84318a1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.List; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import ch.ethz.seb.sebserver.gbl.util.Utils; @@ -67,6 +68,11 @@ public final class Page { return this.content; } + @JsonIgnore + public boolean isEmpty() { + return this.content == null || this.content.isEmpty(); + } + @Override public String toString() { return "Page [numberOfPages=" + this.numberOfPages + ", pageNumber=" + this.pageNumber + ", pageSize=" diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java index 31940f29..a281abbf 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java @@ -57,6 +57,7 @@ public class InstitutionList implements TemplateComposer { // table final EntityTable table = this.widgetFactory.entityTableBuilder(this.restService.getRestCall(GetInstitutions.class)) + .withEmptyMessage(new LocTextKey("sebserver.institution.list.empty")) .withPaging(3) .withColumn(new ColumnDefinition<>( Domain.INSTITUTION.ATTR_NAME, @@ -88,11 +89,11 @@ public class InstitutionList implements TemplateComposer { .createAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) .withSelect(table::getSelection, Action.applySingleSelection("sebserver.institution.info.pleaseSelect")) - .publish() + .publishIf(() -> table.hasAnyContent()) .createAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) .withSelect(table::getSelection, Action.applySingleSelection("sebserver.institution.info.pleaseSelect")) - .publishIf(instGrant::m); + .publishIf(() -> instGrant.m() && table.hasAnyContent()); ; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java new file mode 100644 index 00000000..9f949675 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupForm.java @@ -0,0 +1,42 @@ +/* + * 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; + +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.form.PageFormService; +import ch.ethz.seb.sebserver.gui.service.ResourceService; +import ch.ethz.seb.sebserver.gui.service.page.PageContext; +import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; + +@Lazy +@Component +@GuiProfile +public class LmsSetupForm implements TemplateComposer { + + private final PageFormService pageFormService; + private final ResourceService resourceService; + + protected LmsSetupForm( + final PageFormService pageFormService, + final ResourceService resourceService) { + + this.pageFormService = pageFormService; + this.resourceService = resourceService; + } + + @Override + public void compose(final PageContext pageContext) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java new file mode 100644 index 00000000..b497da96 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java @@ -0,0 +1,126 @@ +/* + * 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; + +import java.util.function.Function; + +import org.eclipse.swt.widgets.Composite; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; +import ch.ethz.seb.sebserver.gbl.model.user.UserRole; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.ResourceService; +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.PageContext; +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.api.lmssetup.GetLmsSetups; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; +import ch.ethz.seb.sebserver.gui.table.EntityTable; +import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; + +@Lazy +@Component +@GuiProfile +public class LmsSetupList implements TemplateComposer { + + private final WidgetFactory widgetFactory; + private final ResourceService resourceService; + private final int pageSize; + + protected LmsSetupList( + final WidgetFactory widgetFactory, + final ResourceService resourceService, + @Value("${sebserver.gui.list.page.size}") final Integer pageSize) { + + this.widgetFactory = widgetFactory; + this.resourceService = resourceService; + this.pageSize = (pageSize != null) ? pageSize : 20; + } + + @Override + public void compose(final PageContext pageContext) { + final CurrentUser currentUser = this.resourceService.getCurrentUser(); + final RestService restService = this.resourceService.getRestService(); + final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); + + // content page layout with title + final Composite content = this.widgetFactory.defaultPageLayout( + pageContext.getParent(), + new LocTextKey("sebserver.lmssetup.list.title")); + + final boolean isSEBAdmin = currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); + + // table + final EntityTable table = + this.widgetFactory.entityTableBuilder(restService.getRestCall(GetLmsSetups.class)) + .withEmptyMessage(new LocTextKey("sebserver.lmssetup.list.empty")) + .withPaging(this.pageSize) + .withColumnIf(() -> isSEBAdmin, + new ColumnDefinition<>( + Domain.LMS_SETUP.ATTR_INSTITUTION_ID, + new LocTextKey("sebserver.lmssetup.list.column.institution"), + lmsSetupInstitutionNameFunction(this.resourceService), + new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + Domain.USER.ATTR_INSTITUTION_ID, + this.resourceService::institutionResource), + false)) + .withColumn(new ColumnDefinition<>( + Domain.LMS_SETUP.ATTR_NAME, + new LocTextKey("sebserver.lmssetup.list.column.name"), + entity -> entity.name, + (isSEBAdmin) + ? new TableFilterAttribute(CriteriaType.TEXT, Domain.LMS_SETUP.ATTR_NAME) + : null, + true)) + .withColumn(new ColumnDefinition<>( + Domain.LMS_SETUP.ATTR_LMS_TYPE, + new LocTextKey("sebserver.lmssetup.list.column.type"), + this::lmsSetupTypeName, + (isSEBAdmin) + ? new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + Domain.LMS_SETUP.ATTR_LMS_TYPE, + this.resourceService::lmsTypeResources) + : null, + false, true)) + .withColumn(new ColumnDefinition<>( + Domain.LMS_SETUP.ATTR_ACTIVE, + new LocTextKey("sebserver.lmssetup.list.column.active"), + entity -> entity.active, + true)) + .compose(content); + + } + + private String lmsSetupTypeName(final LmsSetup lmsSetup) { + if (lmsSetup.lmsType == null) { + return Constants.EMPTY_NOTE; + } + + return this.resourceService.getI18nSupport() + .getText("sebserver.lmssetup.type." + lmsSetup.lmsType.name()); + } + + private static Function lmsSetupInstitutionNameFunction(final ResourceService resourceService) { + final Function institutionNameFunction = resourceService.getInstitutionNameFunction(); + return lmsSetup -> institutionNameFunction.apply(String.valueOf(lmsSetup.institutionId)); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java index d830e4d9..36cdfc35 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountForm.java @@ -33,6 +33,7 @@ import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; 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.ResourceService; 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; @@ -55,24 +56,24 @@ public class UserAccountForm implements TemplateComposer { private static final Logger log = LoggerFactory.getLogger(UserAccountForm.class); private final PageFormService pageFormService; - private final RestService restService; - private final CurrentUser currentUser; + private final ResourceService resourceService; protected UserAccountForm( final PageFormService pageFormService, - final RestService restService, - final CurrentUser currentUser) { + final ResourceService resourceService) { this.pageFormService = pageFormService; - this.restService = restService; - this.currentUser = currentUser; + this.resourceService = resourceService; } @Override public void compose(final PageContext pageContext) { - - final UserInfo user = this.currentUser.get(); + final CurrentUser currentUser = this.resourceService.getCurrentUser(); + final RestService restService = this.resourceService.getRestService(); final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory(); + + final UserInfo user = currentUser.get(); + final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey parentEntityKey = pageContext.getParentEntityKey(); final BooleanSupplier isNew = () -> entityKey == null; @@ -86,7 +87,7 @@ public class UserAccountForm implements TemplateComposer { (parentEntityKey != null) ? Long.valueOf(parentEntityKey.modelId) : user.institutionId) - : this.restService + : restService .getBuilder(GetUserAccount.class) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .call() @@ -101,11 +102,11 @@ public class UserAccountForm implements TemplateComposer { } final boolean ownAccount = user.uuid.equals(userAccount.getModelId()); - final EntityGrantCheck userGrantCheck = this.currentUser.entityGrantCheck(userAccount); + final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(userAccount); final boolean writeGrant = userGrantCheck.w(); final boolean modifyGrant = userGrantCheck.m(); // modifying an UserAccount is not possible if the root institution is inactive - final boolean istitutionActive = this.restService.getBuilder(GetInstitution.class) + final boolean istitutionActive = restService.getBuilder(GetInstitution.class) .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId())) .call() .map(inst -> inst.active) @@ -142,7 +143,7 @@ public class UserAccountForm implements TemplateComposer { Domain.USER.ATTR_INSTITUTION_ID, "sebserver.useraccount.form.institution", String.valueOf(userAccount.getInstitutionId()), - () -> PageUtils.getInstitutionSelectionResource(this.restService)) + () -> this.resourceService.institutionResource()) .withCondition(isSEBAdmin) .readonlyIf(isNotNew)) .addField(FormBuilder.text( @@ -161,17 +162,17 @@ public class UserAccountForm implements TemplateComposer { Domain.USER.ATTR_LANGUAGE, "sebserver.useraccount.form.language", userAccount.getLanguage().getLanguage(), - widgetFactory.getI18nSupport().localizedLanguageResources())) + this.resourceService::languageResources)) .addField(FormBuilder.singleSelection( Domain.USER.ATTR_TIMEZONE, "sebserver.useraccount.form.timezone", userAccount.getTimeZone().getID(), - widgetFactory.getI18nSupport().localizedTimeZoneResources())) + this.resourceService::timeZoneResources)) .addField(FormBuilder.multiSelection( USER_ROLE.REFERENCE_NAME, "sebserver.useraccount.form.roles", StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR), - widgetFactory.getI18nSupport().localizedUserRoleResources()) + this.resourceService::userRoleResources) .withCondition(() -> modifyGrant) .visibleIf(writeGrant)) .addField(FormBuilder.text( @@ -185,8 +186,8 @@ public class UserAccountForm implements TemplateComposer { .asPasswordField() .withCondition(isNew)) .buildFor((entityKey == null) - ? this.restService.getRestCall(NewUserAccount.class) - : this.restService.getRestCall(SaveUserAccount.class)); + ? restService.getRestCall(NewUserAccount.class) + : restService.getRestCall(SaveUserAccount.class)); // propagate content actions to action-pane @@ -204,19 +205,19 @@ public class UserAccountForm implements TemplateComposer { .publishIf(() -> modifyGrant && readonly && istitutionActive && userAccount.isActive()) .createAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE) - .withExec(Action.activation(this.restService, false)) - .withConfirm(PageUtils.confirmDeactivation(userAccount, this.restService)) + .withExec(Action.activation(restService, false)) + .withConfirm(PageUtils.confirmDeactivation(userAccount, restService)) .publishIf(() -> writeGrant && readonly && istitutionActive && userAccount.isActive()) .createAction(ActionDefinition.USER_ACCOUNT_ACTIVATE) - .withExec(Action.activation(this.restService, true)) + .withExec(Action.activation(restService, true)) .publishIf(() -> writeGrant && readonly && istitutionActive && !userAccount.isActive()) .createAction(ActionDefinition.USER_ACCOUNT_SAVE) .withExec(action -> { final Action postChanges = formHandle.postChanges(action); if (ownAccount) { - this.currentUser.refresh(); + currentUser.refresh(); pageContext.forwardToMainPage(); } return postChanges; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java index a1edfee8..a4b4aac9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java @@ -8,16 +8,22 @@ package ch.ethz.seb.sebserver.gui.content; +import java.util.function.BooleanSupplier; +import java.util.function.Function; + import org.eclipse.swt.widgets.Composite; import org.springframework.beans.factory.annotation.Value; 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.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; +import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; +import ch.ethz.seb.sebserver.gui.service.ResourceService; 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; @@ -38,33 +44,45 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; public class UserAccountList implements TemplateComposer { private final WidgetFactory widgetFactory; - private final RestService restService; - private final CurrentUser currentUser; + private final ResourceService resourceService; private final int pageSize; protected UserAccountList( final WidgetFactory widgetFactory, - final RestService restService, - final CurrentUser currentUser, + final ResourceService resourceService, @Value("${sebserver.gui.list.page.size}") final Integer pageSize) { this.widgetFactory = widgetFactory; - this.restService = restService; - this.currentUser = currentUser; + this.resourceService = resourceService; this.pageSize = (pageSize != null) ? pageSize : 20; } @Override public void compose(final PageContext pageContext) { + final CurrentUser currentUser = this.resourceService.getCurrentUser(); + final RestService restService = this.resourceService.getRestService(); // content page layout with title final Composite content = this.widgetFactory.defaultPageLayout( pageContext.getParent(), new LocTextKey("sebserver.useraccount.list.title")); + final BooleanSupplier isSEBAdmin = () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); + // table final EntityTable table = - this.widgetFactory.entityTableBuilder(this.restService.getRestCall(GetUserAccounts.class)) + this.widgetFactory.entityTableBuilder(restService.getRestCall(GetUserAccounts.class)) + .withEmptyMessage(new LocTextKey("sebserver.useraccount.list.empty")) .withPaging(this.pageSize) + .withColumnIf(isSEBAdmin, + new ColumnDefinition<>( + Domain.USER.ATTR_INSTITUTION_ID, + new LocTextKey("sebserver.useraccount.list.column.institution"), + userInstitutionNameFunction(this.resourceService), + new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + Domain.USER.ATTR_INSTITUTION_ID, + this.resourceService::institutionResource), + false)) .withColumn(new ColumnDefinition<>( Domain.USER.ATTR_NAME, new LocTextKey("sebserver.useraccount.list.column.name"), @@ -87,7 +105,10 @@ public class UserAccountList implements TemplateComposer { Domain.USER.ATTR_LANGUAGE, new LocTextKey("sebserver.useraccount.list.column.language"), this::getLocaleDisplayText, - new TableFilterAttribute(CriteriaType.COUNTRY_SELECTION, Domain.USER.ATTR_LANGUAGE), + new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + Domain.USER.ATTR_LANGUAGE, + this.resourceService::languageResources), true, true)) .withColumn(new ColumnDefinition<>( Domain.USER.ATTR_ACTIVE, @@ -97,25 +118,30 @@ public class UserAccountList implements TemplateComposer { .compose(content); // propagate content actions to action-pane - final GrantCheck userGrant = this.currentUser.grantCheck(EntityType.USER); + final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER); pageContext.clearEntityKeys() .createAction(ActionDefinition.USER_ACCOUNT_NEW) .publishIf(userGrant::w) - .createAction(ActionDefinition.USER_ACCOUNT_VIEW) + .createAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) .withSelect(table::getSelection, Action.applySingleSelection("sebserver.useraccount.info.pleaseSelect")) - .publish() + .publishIf(() -> table.hasAnyContent()) .createAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST) .withSelect(table::getSelection, Action.applySingleSelection("sebserver.useraccount.info.pleaseSelect")) - .publishIf(userGrant::m); + .publishIf(() -> userGrant.m() && table.hasAnyContent()); } private String getLocaleDisplayText(final UserInfo userInfo) { return (userInfo.language != null) ? userInfo.language.getDisplayLanguage(this.widgetFactory.getI18nSupport().getCurrentLocale()) - : null; + : Constants.EMPTY_NOTE; + } + + private static Function userInstitutionNameFunction(final ResourceService resourceService) { + final Function institutionNameFunction = resourceService.getInstitutionNameFunction(); + return userInfo -> institutionNameFunction.apply(String.valueOf(userInfo.institutionId)); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index f042e00b..75a96a7d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -10,6 +10,8 @@ package ch.ethz.seb.sebserver.gui.content.action; import ch.ethz.seb.sebserver.gui.content.InstitutionForm; import ch.ethz.seb.sebserver.gui.content.InstitutionList; +import ch.ethz.seb.sebserver.gui.content.LmsSetupForm; +import ch.ethz.seb.sebserver.gui.content.LmsSetupList; import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm; import ch.ethz.seb.sebserver.gui.content.UserAccountForm; import ch.ethz.seb.sebserver.gui.content.UserAccountList; @@ -17,6 +19,8 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; +/** Enumeration of static action data for each action within the SEB Server GUI */ +// TODO add category to allow easy positioning of actions later public enum ActionDefinition { INSTITUTION_VIEW_LIST( @@ -36,43 +40,36 @@ public enum ActionDefinition { ImageIcon.SHOW, InstitutionForm.class, INSTITUTION_VIEW_LIST), - INSTITUTION_MODIFY_FROM_LIST( new LocTextKey("sebserver.institution.action.list.modify"), ImageIcon.EDIT, InstitutionForm.class, INSTITUTION_VIEW_LIST, false), - INSTITUTION_MODIFY( new LocTextKey("sebserver.institution.action.modify"), ImageIcon.EDIT, InstitutionForm.class, INSTITUTION_VIEW_LIST, false), - INSTITUTION_CANCEL_MODIFY( new LocTextKey("sebserver.overall.action.modify.cancel"), ImageIcon.CANCEL, InstitutionForm.class, INSTITUTION_VIEW_LIST), - INSTITUTION_SAVE( new LocTextKey("sebserver.institution.action.save"), ImageIcon.SAVE, InstitutionForm.class, INSTITUTION_VIEW_LIST), - INSTITUTION_ACTIVATE( new LocTextKey("sebserver.institution.action.activate"), ImageIcon.INACTIVE, InstitutionForm.class, INSTITUTION_VIEW_LIST), - INSTITUTION_DEACTIVATE( new LocTextKey("sebserver.institution.action.deactivate"), ImageIcon.ACTIVE, InstitutionForm.class, INSTITUTION_VIEW_LIST), - INSTITUTION_DELETE( new LocTextKey("sebserver.institution.action.modify"), ImageIcon.DELETE, @@ -91,55 +88,46 @@ public enum ActionDefinition { ImageIcon.NEW, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST, false), - - USER_ACCOUNT_VIEW( + USER_ACCOUNT_VIEW_FROM_LIST( new LocTextKey("sebserver.useraccount.action.view"), ImageIcon.SHOW, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST), - USER_ACCOUNT_MODIFY_FROM_LIST( new LocTextKey("sebserver.useraccount.action.list.modify"), ImageIcon.EDIT, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST, false), - USER_ACCOUNT_MODIFY( new LocTextKey("sebserver.useraccount.action.modify"), ImageIcon.EDIT, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST, false), - USER_ACCOUNT_CANCEL_MODIFY( new LocTextKey("sebserver.overall.action.modify.cancel"), ImageIcon.CANCEL, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST), - USER_ACCOUNT_SAVE( new LocTextKey("sebserver.useraccount.action.save"), ImageIcon.SAVE, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST), - USER_ACCOUNT_ACTIVATE( new LocTextKey("sebserver.useraccount.action.activate"), ImageIcon.INACTIVE, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST), - USER_ACCOUNT_DEACTIVATE( new LocTextKey("sebserver.useraccount.action.deactivate"), ImageIcon.ACTIVE, UserAccountForm.class, USER_ACCOUNT_VIEW_LIST), - USER_ACCOUNT_DELETE( new LocTextKey("sebserver.useraccount.action.modify"), ImageIcon.DELETE, UserAccountList.class, USER_ACCOUNT_VIEW_LIST), - USER_ACCOUNT_CHANGE_PASSOWRD( new LocTextKey("sebserver.useraccount.action.change.password"), ImageIcon.EDIT, @@ -151,13 +139,21 @@ public enum ActionDefinition { UserAccountForm.class, USER_ACCOUNT_VIEW_LIST), - ; + LMS_SETUP_VIEW_LIST( + new LocTextKey("sebserver.lmssetup.list.title"), + LmsSetupList.class), + LMS_SETUP_VIEW_FORM( + new LocTextKey("sebserver.useraccount.action.form"), + LmsSetupForm.class, + USER_ACCOUNT_VIEW_LIST), + ; public final LocTextKey title; public final ImageIcon icon; public final Class contentPaneComposer; public final Class actionPaneComposer; public final ActionDefinition activityAlias; + public final String category; public final boolean readonly; private ActionDefinition( @@ -169,6 +165,7 @@ public enum ActionDefinition { this.contentPaneComposer = contentPaneComposer; this.actionPaneComposer = ActionPane.class; this.activityAlias = null; + this.category = null; this.readonly = true; } @@ -182,6 +179,7 @@ public enum ActionDefinition { this.contentPaneComposer = contentPaneComposer; this.actionPaneComposer = ActionPane.class; this.activityAlias = activityAlias; + this.category = null; this.readonly = true; } @@ -196,6 +194,7 @@ public enum ActionDefinition { this.contentPaneComposer = contentPaneComposer; this.actionPaneComposer = ActionPane.class; this.activityAlias = activityAlias; + this.category = null; this.readonly = true; } @@ -211,6 +210,7 @@ public enum ActionDefinition { this.contentPaneComposer = contentPaneComposer; this.actionPaneComposer = ActionPane.class; this.activityAlias = activityAlias; + this.category = null; this.readonly = readonly; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/UserAccountActions.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/UserAccountActions.java deleted file mode 100644 index d535edf7..00000000 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/UserAccountActions.java +++ /dev/null @@ -1,61 +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.content.action; - -public final class UserAccountActions { - -// public static Action newUserAccount(final Action action) { -// return goToUserAccount(action, null, true); -// } -// -// public static Action viewUserAccountFromList(final Action action) { -// return fromSelection(action, false); -// } -// -// public static Action editUserAccountFromList(final Action action) { -// return fromSelection(action, true); -// } -// -// public static Action editUserAccount(final Action action) { -// return goToUserAccount(action, null, true); -// } -// -// public static Action cancelEditUserAccount(final Action action) { -// if (action.pageContext().getEntityKey() == null) { -// final Action toList = action.pageContext().createAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST); -// action.pageContext().publishPageEvent(new ActionEvent(toList, false)); -// return toList; -// } else { -// return goToUserAccount(action, null, false); -// } -// } -// -// private static Action fromSelection(final Action action, final boolean edit) { -// final Collection selection = action.getSelectionSupplier().get(); -// if (selection.isEmpty()) { -// throw new PageMessageException("sebserver.useraccount.info.pleaseSelect"); -// } -// -// return goToUserAccount(action, selection.iterator().next(), edit); -// } -// -// private static Action goToUserAccount( -// final Action action, -// final String modelId, -// final boolean edit) { -// -// action.withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit)); -// if (modelId != null) { -// action.withEntity(new EntityKey(modelId, EntityType.USER)); -// } -// -// return action; -// } - -} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java index 4b65c406..f71b372b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java @@ -117,6 +117,14 @@ public class ActivitiesPane implements TemplateComposer { .withAttribute(AttributeKeys.READ_ONLY, "true")); } + // LMS Setup + final TreeItem userAccounts = this.widgetFactory.treeItemLocalized( + navigation, + ActionDefinition.LMS_SETUP_VIEW_LIST.title); + injectActivitySelection( + userAccounts, + pageContext.createAction(ActionDefinition.LMS_SETUP_VIEW_LIST)); + navigation.addListener(SWT.Selection, event -> handleSelection(pageContext, event)); navigation.setData( PageEventListener.LISTENER_ATTRIBUTE_KEY, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java new file mode 100644 index 00000000..0f6a67d2 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java @@ -0,0 +1,144 @@ +/* + * 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; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTimeZone; +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.Domain; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; +import ch.ethz.seb.sebserver.gbl.model.user.UserRole; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gbl.util.Tuple; +import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; + +@Lazy +@Service +@GuiProfile +public class ResourceService { + + private final I18nSupport i18nSupport; + private final RestService restService; + private final CurrentUser currentUser; + + protected ResourceService( + final I18nSupport i18nSupport, + final RestService restService, + final CurrentUser currentUser) { + + this.i18nSupport = i18nSupport; + this.restService = restService; + this.currentUser = currentUser; + } + + public I18nSupport getI18nSupport() { + return this.i18nSupport; + } + + public RestService getRestService() { + return this.restService; + } + + public CurrentUser getCurrentUser() { + return this.currentUser; + } + + public Supplier>> localizedResourceSupplier(final List> source) { + return () -> source.stream() + .map(tuple -> new Tuple<>(tuple._1, this.i18nSupport.getText(tuple._2))) + .collect(Collectors.toList()); + } + + public List> lmsTypeResources() { + return Arrays.asList(LmsType.values()) + .stream() + .map(lmsType -> new Tuple<>( + lmsType.name(), + this.i18nSupport.getText("sebserver.lmssetup.type." + lmsType.name()))) + .collect(Collectors.toList()); + } + + public List> userRoleResources() { + return UserRole.publicRolesForUser(this.currentUser.get()) + .stream() + .map(ur -> new Tuple<>( + ur.name(), + this.i18nSupport.getText("sebserver.useraccount.role." + ur.name()))) + .collect(Collectors.toList()); + } + + public List> institutionResource() { + return this.restService.getBuilder(GetInstitutionNames.class) + .withQueryParam(Domain.INSTITUTION.ATTR_ACTIVE, "true") + .call() + .getOr(Collections.emptyList()) + .stream() + .map(entityName -> new Tuple<>(entityName.modelId, entityName.name)) + .collect(Collectors.toList()); + } + + public Function getInstitutionNameFunction() { + + final Map idNameMap = this.restService.getBuilder(GetInstitutionNames.class) + .withQueryParam(Domain.INSTITUTION.ATTR_ACTIVE, "true") + .call() + .getOr(Collections.emptyList()) + .stream() + .collect(Collectors.toMap(e -> e.modelId, e -> e.name)); + + return id -> { + if (!idNameMap.containsKey(id)) { + return Constants.EMPTY_NOTE; + } + return idNameMap.get(id); + }; + } + + /** 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 */ + public List> languageResources() { + final Locale currentLocale = this.i18nSupport.getCurrentLocale(); + return this.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 List> timeZoneResources() { + final Locale currentLocale = this.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/i18n/I18nSupport.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java index 26fd23ad..940d7722 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,16 +9,9 @@ package ch.ethz.seb.sebserver.gui.service.i18n; import java.util.Collection; -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.util.Tuple; public interface I18nSupport { @@ -79,46 +72,4 @@ public interface I18nSupport { * @return the text in current language parsed from localized text */ String getText(String key, Locale locale, String def, Object... args); - default Supplier>> localizedResourceSupplier(final List> source) { - return () -> source.stream() - .map(tuple -> new Tuple<>(tuple._1, getText(tuple._2))) - .collect(Collectors.toList()); - } - - default Supplier>> localizedLanguageResources() { - return () -> getLanguageResources(this); - } - - default Supplier>> localizedTimeZoneResources() { - return () -> getTimeZoneResources(this); - } - - Supplier>> localizedUserRoleResources(); - - /** 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> 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> 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/i18n/impl/I18nSupportImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/impl/I18nSupportImpl.java index f2727aee..ab550f4e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/impl/I18nSupportImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/impl/I18nSupportImpl.java @@ -10,10 +10,7 @@ package ch.ethz.seb.sebserver.gui.service.i18n.impl; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.Locale; -import java.util.function.Supplier; -import java.util.stream.Collectors; import org.eclipse.rap.rwt.RWT; import org.joda.time.DateTime; @@ -26,8 +23,6 @@ import org.springframework.context.MessageSource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import ch.ethz.seb.sebserver.gbl.model.user.UserRole; -import ch.ethz.seb.sebserver.gbl.util.Tuple; 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.remote.webservice.auth.CurrentUser; @@ -133,13 +128,4 @@ public class I18nSupportImpl implements I18nSupport { return this.messageSource.getMessage(key, args, def, locale); } - @Override - public Supplier>> localizedUserRoleResources() { - final List> roles = UserRole.publicRolesForUser(this.currentUser.get()) - .stream() - .map(ur -> new Tuple<>(ur.name(), "sebserver.useraccount.role." + ur.name())) - .collect(Collectors.toList()); - return localizedResourceSupplier(roles); - } - } 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 index c588c6fc..9b7a5645 100644 --- 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 @@ -8,30 +8,36 @@ 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.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; 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.Domain; 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 void clearComposite(final Composite parent) { + if (parent == null) { + return; + } + + for (final Control control : parent.getChildren()) { + control.dispose(); + } + } + public static final Supplier confirmDeactivation( final Entity entity, final RestService restService) { @@ -56,14 +62,4 @@ public final class PageUtils { }; } - public static List> getInstitutionSelectionResource(final RestService restService) { - return restService.getBuilder(GetInstitutionNames.class) - .withQueryParam(Domain.INSTITUTION.ATTR_ACTIVE, "true") - .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/impl/ComposerServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java index b947eda9..412d50b9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java @@ -24,9 +24,9 @@ import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.page.ComposerService; 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.PageUtils; 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.widget.WidgetFactory; @Lazy @Service @@ -113,7 +113,7 @@ public class ComposerServiceImpl implements ComposerService { if (composer.validate(pageContext)) { - WidgetFactory.clearComposite(pageContext.getParent()); + PageUtils.clearComposite(pageContext.getParent()); try { composer.compose(pageContext); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/BuildErrorCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/BuildErrorCall.java deleted file mode 100644 index 10e1c42e..00000000 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/BuildErrorCall.java +++ /dev/null @@ -1,26 +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.remote.webservice.api; - -import ch.ethz.seb.sebserver.gbl.util.Result; - -public class BuildErrorCall extends RestCall { - - private final Throwable error; - - protected BuildErrorCall(final Throwable error) { - super(null, null, null, null); - this.error = error; - } - - @Override - protected Result exchange(final RestCallBuilder builder) { - return Result.ofError(this.error); - } -} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetup.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetup.java new file mode 100644 index 00000000..7a19e3a7 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetup.java @@ -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.service.remote.webservice.api.lmssetup; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetLmsSetup extends RestCall { + + protected GetLmsSetup() { + super( + new TypeReference() { + }, + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.LMS_SETUP_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetups.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetups.java new file mode 100644 index 00000000..1491b366 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/lmssetup/GetLmsSetups.java @@ -0,0 +1,38 @@ +/* + * 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.remote.webservice.api.lmssetup; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetLmsSetups extends RestCall> { + + protected GetLmsSetups() { + super( + new TypeReference>() { + }, + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.LMS_SETUP_ENDPOINT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/ColumnDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/ColumnDefinition.java index 3cb05099..3a05f0ee 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/ColumnDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/ColumnDefinition.java @@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.gui.table; import java.util.List; import java.util.function.Function; +import java.util.function.Supplier; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.util.Tuple; @@ -22,7 +23,7 @@ public final class ColumnDefinition { final LocTextKey displayName; final LocTextKey tooltip; final int widthPercent; - final Function valueSupplier; + final Function valueSupplier; final boolean sortable; final TableFilterAttribute filterAttribute; final boolean localized; @@ -51,7 +52,7 @@ public final class ColumnDefinition { public ColumnDefinition( final String columnName, final LocTextKey displayName, - final Function valueSupplier, + final Function valueSupplier, final boolean sortable) { this(columnName, displayName, null, -1, valueSupplier, null, sortable, false); @@ -60,7 +61,7 @@ public final class ColumnDefinition { public ColumnDefinition( final String columnName, final LocTextKey displayName, - final Function valueSupplier, + final Function valueSupplier, final boolean sortable, final boolean localized) { @@ -70,7 +71,7 @@ public final class ColumnDefinition { public ColumnDefinition( final String columnName, final LocTextKey displayName, - final Function valueSupplier, + final Function valueSupplier, final TableFilterAttribute tableFilterAttribute, final boolean sortable) { @@ -80,7 +81,7 @@ public final class ColumnDefinition { public ColumnDefinition( final String columnName, final LocTextKey displayName, - final Function valueSupplier, + final Function valueSupplier, final TableFilterAttribute tableFilterAttribute, final boolean sortable, final boolean localized) { @@ -93,7 +94,7 @@ public final class ColumnDefinition { final LocTextKey displayName, final LocTextKey tooltip, final int widthPercent, - final Function valueSupplier, + final Function valueSupplier, final TableFilterAttribute filterAttribute, final boolean sortable, final boolean localized) { @@ -113,28 +114,30 @@ public final class ColumnDefinition { public final CriteriaType type; public final String columnName; public final String initValue; - public final List> selectionResource; + public final Supplier>> resourceSupplier; + + public TableFilterAttribute(final CriteriaType type, final String columnName) { + this(type, columnName, "", null); + } public TableFilterAttribute( final CriteriaType type, - final String columnName) { + final String columnName, + final Supplier>> resourceSupplier) { - this.type = type; - this.columnName = columnName; - this.initValue = ""; - this.selectionResource = null; + this(type, columnName, "", resourceSupplier); } public TableFilterAttribute( final CriteriaType type, final String columnName, final String initValue, - final List> selectionResource) { + final Supplier>> resourceSupplier) { this.type = type; this.columnName = columnName; this.initValue = initValue; - this.selectionResource = selectionResource; + this.resourceSupplier = resourceSupplier; } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java index 5c249993..8364e45f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java @@ -35,6 +35,7 @@ import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; @@ -52,6 +53,7 @@ public class EntityTable { final List> columns; final List actions; + final LocTextKey emptyMessage; final Composite composite; private final TableFilter filter; @@ -71,39 +73,46 @@ public class EntityTable { final WidgetFactory widgetFactory, final List> columns, final List actions, - final int pageSize) { + final int pageSize, + final LocTextKey emptyMessage) { this.composite = new Composite(parent, type); this.widgetFactory = widgetFactory; this.restCall = restCall; this.columns = Utils.immutableListOf(columns); this.actions = Utils.immutableListOf(actions); + this.emptyMessage = emptyMessage; - this.composite.setLayout(new GridLayout()); + final GridLayout layout = new GridLayout(); + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + this.composite.setLayout(layout); GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true); - - gridData.heightHint = (pageSize + 1) * 40; + gridData.heightHint = (pageSize + 2) * 40; this.composite.setLayoutData(gridData); +// TODO just for debugging, remove when tested +// this.composite.setBackground(new Color(parent.getDisplay(), new RGB(0, 200, 0))); + this.pageSize = pageSize; - this.filter = columns - .stream() - .map(column -> column.filterAttribute) - .filter(Objects::nonNull) - .findFirst() - .isPresent() ? new TableFilter<>(this) : null; + this.filter = + columns + .stream() + .map(column -> column.filterAttribute) + .filter(Objects::nonNull) + .findFirst() + .isPresent() ? new TableFilter<>(this) : null; this.table = widgetFactory.tableLocalized(this.composite); final GridLayout gridLayout = new GridLayout(columns.size(), true); this.table.setLayout(gridLayout); - gridData = new GridData(SWT.FILL, SWT.CENTER, true, false); - gridData.heightHint = (pageSize + 1) * 27; + gridData = new GridData(SWT.FILL, SWT.TOP, true, false); this.table.setLayoutData(gridData); this.table.addListener(SWT.Resize, this::adaptColumnWidth); @SuppressWarnings("unchecked") final Consumer locFunction = (Consumer
) this.table.getData(POLYGLOT_WIDGET_FUNCTION_KEY); final Consumer
newLocFunction = t -> { - updateValues(); + updateValues(this); locFunction.accept(t); }; this.table.setData(POLYGLOT_WIDGET_FUNCTION_KEY, newLocFunction); @@ -121,6 +130,10 @@ public class EntityTable { this.sortOrder); } + public boolean hasAnyContent() { + return this.table.getItemCount() > 0; + } + public void setPageSize(final int pageSize) { this.pageSize = pageSize; updateTableRows( @@ -251,6 +264,19 @@ public class EntityTable { } private Page createTableRowsFromPage(final Page page) { + if (page.isEmpty()) { + final GridData gridData = (GridData) this.table.getLayoutData(); + gridData.heightHint = 30; + return page; + } + + final GridData gridData = (GridData) this.table.getLayoutData(); + if (page.numberOfPages > 1) { + gridData.heightHint = (this.pageSize + 1) * 27; + } else { + gridData.heightHint = (page.content.size() + 1) * 27; + } + for (final ROW row : page.content) { final TableItem item = new TableItem(this.table, SWT.NONE); item.setData(TABLE_ROW_DATA, row); @@ -267,41 +293,6 @@ public class EntityTable { return page; } - private void updateValues() { - final TableItem[] items = this.table.getItems(); - final TableColumn[] columns = this.table.getColumns(); - for (int i = 0; i < columns.length; i++) { - final ColumnDefinition columnDefinition = this.columns.get(i); - if (columnDefinition.localized) { - for (int j = 0; j < items.length; j++) { - @SuppressWarnings("unchecked") - final ROW rowData = (ROW) items[j].getData(TABLE_ROW_DATA); - setValueToCell(items[j], i, columnDefinition.valueSupplier.apply(rowData)); - } - } - } - } - - private void setValueToCell(final TableItem item, final int index, final Object value) { - if (value instanceof Boolean) { - addBooleanCell(item, index, value); - } else { - if (value != null) { - item.setText(index, String.valueOf(value)); - } else { - item.setText(index, Constants.EMPTY_NOTE); - } - } - } - - private void addBooleanCell(final TableItem item, final int index, final Object value) { - if ((Boolean) value) { - item.setImage(index, ImageIcon.ACTIVE.getImage(item.getDisplay())); - } else { - item.setImage(index, ImageIcon.INACTIVE.getImage(item.getDisplay())); - } - } - private void adaptColumnWidth(final Event event) { try { final int currentTableWidth = this.table.getParent().getClientArea().width; @@ -323,8 +314,8 @@ public class EntityTable { } // NOTE this.layout() triggers the navigation to disappear unexpectedly!? - this.table.layout(true, true); - + //this.table.layout(true, true); + //this.composite.layout(true, true); } catch (final Exception e) { log.warn("Failed to adaptColumnWidth: ", e); } @@ -339,7 +330,7 @@ public class EntityTable { this.table.indexOf(tableColumn), tableColumn.getWidth())) { - this.composite.layout(true, true); + //this.composite.layout(true, true); } } } @@ -353,4 +344,39 @@ public class EntityTable { return getRowData(item).getEntityKey(); } + private static void updateValues(final EntityTable table) { + final TableItem[] items = table.table.getItems(); + final TableColumn[] columns = table.table.getColumns(); + for (int i = 0; i < columns.length; i++) { + final ColumnDefinition columnDefinition = table.columns.get(i); + if (columnDefinition.localized) { + for (int j = 0; j < items.length; j++) { + @SuppressWarnings("unchecked") + final ROW rowData = (ROW) items[j].getData(TABLE_ROW_DATA); + setValueToCell(items[j], i, columnDefinition.valueSupplier.apply(rowData)); + } + } + } + } + + private static void setValueToCell(final TableItem item, final int index, final Object value) { + if (value instanceof Boolean) { + addBooleanCell(item, index, value); + } else { + if (value != null) { + item.setText(index, String.valueOf(value)); + } else { + item.setText(index, Constants.EMPTY_NOTE); + } + } + } + + private static void addBooleanCell(final TableItem item, final int index, final Object value) { + if ((Boolean) value) { + item.setImage(index, ImageIcon.ACTIVE.getImage(item.getDisplay())); + } else { + item.setImage(index, ImageIcon.INACTIVE.getImage(item.getDisplay())); + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java index 4356876e..4becf9be 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java @@ -10,12 +10,14 @@ package ch.ethz.seb.sebserver.gui.table; import java.util.ArrayList; import java.util.List; +import java.util.function.BooleanSupplier; import org.eclipse.swt.SWT; 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.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -40,6 +42,7 @@ public class TableBuilder { final RestCall> restCall; final List> columns = new ArrayList<>(); final List actions = new ArrayList<>(); + LocTextKey emptyMessage; private int pageSize = -1; private int type = SWT.NONE; @@ -52,6 +55,11 @@ public class TableBuilder { this.restCall = restCall; } + public TableBuilder withEmptyMessage(final LocTextKey emptyMessage) { + this.emptyMessage = emptyMessage; + return this; + } + public TableBuilder withPaging(final int pageSize) { this.pageSize = pageSize; return this; @@ -62,6 +70,16 @@ public class TableBuilder { return this; } + public TableBuilder withColumnIf( + final BooleanSupplier condition, + final ColumnDefinition columnDefinition) { + + if (condition != null && condition.getAsBoolean()) { + this.columns.add(columnDefinition); + } + return this; + } + public TableBuilder withAction(final TableRowAction action) { this.actions.add(action); return this; @@ -80,7 +98,8 @@ public class TableBuilder { this.widgetFactory, this.columns, this.actions, - this.pageSize); + this.pageSize, + this.emptyMessage); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java index 315a85ca..cac1773d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java @@ -8,6 +8,7 @@ package ch.ethz.seb.sebserver.gui.table; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -34,13 +35,12 @@ public class TableFilter { public static enum CriteriaType { TEXT, SINGLE_SELECTION, - COUNTRY_SELECTION, DATE } private final Composite composite; private final EntityTable entityTable; - private final List components; + private final List components = new ArrayList<>(); TableFilter(final EntityTable entityTable) { this.composite = new Composite(entityTable.composite, SWT.NONE); @@ -51,22 +51,11 @@ public class TableFilter { layout.wrap = false; this.composite.setLayout(layout); +// TODO just for debugging, remove when tested +// this.composite.setBackground(new Color(entityTable.composite.getDisplay(), new RGB(0, 0, 200))); + this.entityTable = entityTable; - this.components = entityTable.columns - .stream() - .map(column -> column.filterAttribute) - //.filter(Objects::nonNull) - .map(this::createFilterComponent) - .map(comp -> comp.build(this.composite)) - .map(comp -> comp.reset()) - .collect(Collectors.toList()); - - final FilterComponent lastComp = this.components.get(this.components.size() - 1); - if (lastComp instanceof TableFilter.NullFilter) { - this.components.remove(lastComp); - } - - addActions(); + buildComponents(); } public MultiValueMap getFilterParameter() { @@ -86,6 +75,24 @@ public class TableFilter { .forEach(comp -> comp.reset()); } + private void buildComponents() { + this.components.clear(); + this.components.addAll(this.entityTable.columns + .stream() + .map(column -> column.filterAttribute) + .map(this::createFilterComponent) + .map(comp -> comp.build(this.composite)) + .map(comp -> comp.reset()) + .collect(Collectors.toList())); + + final FilterComponent lastComp = this.components.get(this.components.size() - 1); + if (lastComp instanceof TableFilter.NullFilter) { + this.components.remove(lastComp); + } + + addActions(); + } + private FilterComponent createFilterComponent(final TableFilterAttribute attribute) { if (attribute == null) { return new NullFilter(); @@ -94,8 +101,8 @@ public class TableFilter { switch (attribute.type) { case TEXT: return new TextFilter(attribute); - case COUNTRY_SELECTION: - return new LanguageFilter(attribute); + case SINGLE_SELECTION: + return new Selection(attribute); default: throw new IllegalArgumentException("Unsupported FilterAttributeType: " + attribute.type); } @@ -103,7 +110,11 @@ public class TableFilter { boolean adaptColumnWidth(final int columnIndex, final int width) { if (columnIndex < this.components.size()) { - return this.components.get(columnIndex).adaptWidth(width); + final boolean adaptWidth = this.components.get(columnIndex).adaptWidth(width); + if (adaptWidth) { + this.composite.layout(); + } + return adaptWidth; } return false; @@ -229,11 +240,11 @@ public class TableFilter { } - private class LanguageFilter extends FilterComponent { + private class Selection extends FilterComponent { - private SingleSelection selector; + protected SingleSelection selector; - LanguageFilter(final TableFilterAttribute attribute) { + Selection(final TableFilterAttribute attribute) { super(attribute); } @@ -242,9 +253,7 @@ public class TableFilter { this.selector = TableFilter.this.entityTable.widgetFactory .singleSelectionLocalized( parent, - TableFilter.this.entityTable.widgetFactory - .getI18nSupport() - .localizedLanguageResources()); + this.attribute.resourceSupplier); this.selector.setLayoutData(this.rowData); return this; } @@ -265,5 +274,13 @@ public class TableFilter { return null; } + + @Override + boolean adaptWidth(final int width) { + // NOTE: for some unknown reason RWT acts differently on width-property for text inputs and selectors + // this is to adjust selection filter criteria to the list column width + return super.adaptWidth(width + 25); + } } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java index 1b6e3d37..e26ec885 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableNavigator.java @@ -17,7 +17,8 @@ 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.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.service.page.PageUtils; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; public class TableNavigator { @@ -28,7 +29,10 @@ public class TableNavigator { TableNavigator(final EntityTable entityTable) { this.composite = new Composite(entityTable.composite, SWT.NONE); - this.composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + this.composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); + +// TODO just for debugging, remove when tested +// this.composite.setBackground(new Color(entityTable.composite.getDisplay(), new RGB(200, 0, 0))); final GridLayout layout = new GridLayout(3, true); layout.marginLeft = 20; @@ -39,7 +43,18 @@ public class TableNavigator { public Page update(final Page pageData) { // clear all - WidgetFactory.clearComposite(this.composite); + PageUtils.clearComposite(this.composite); + + if (pageData.isEmpty()) { + // show empty message + if (this.entityTable.emptyMessage != null) { + this.entityTable.widgetFactory.labelLocalized( + this.composite, + CustomVariant.TEXT_H3, + this.entityTable.emptyMessage); + } + return pageData; + } final int pageNumber = pageData.getPageNumber(); final int numberOfPages = pageData.getNumberOfPages(); @@ -47,15 +62,14 @@ public class TableNavigator { createPagingHeader(pageNumber, numberOfPages); final Composite numNav = new Composite(this.composite, SWT.NONE); - numNav.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + final GridData gridData = new GridData(SWT.CENTER, SWT.TOP, true, false); + numNav.setLayoutData(gridData); final RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); - rowLayout.spacing = 5; + numNav.setLayout(rowLayout); if (numberOfPages > 1) { - if (pageNumber > 1) { - createRewardLabel(pageNumber, numNav); - } + createBackwardLabel(pageNumber > 1, pageNumber, numNav); for (int i = pageNumber - PAGE_NAV_SIZE; i < pageNumber + PAGE_NAV_SIZE; i++) { if (i >= 1 && i <= numberOfPages) { @@ -63,9 +77,7 @@ public class TableNavigator { } } - if (pageNumber < numberOfPages) { - createForwardLabel(pageNumber, numNav); - } + createForwardLabel(pageNumber < numberOfPages, pageNumber, numNav); } return pageData; @@ -89,7 +101,11 @@ public class TableNavigator { } } - private void createForwardLabel(final int pageNumber, final Composite parent) { + private void createForwardLabel( + final boolean visible, + final int pageNumber, + final Composite parent) { + final Label forward = new Label(parent, SWT.NONE); forward.setText(">"); forward.setData(RWT.CUSTOM_VARIANT, "action"); @@ -98,13 +114,21 @@ public class TableNavigator { }); } - private void createRewardLabel(final int pageNumber, final Composite parent) { - final Label reward = new Label(parent, SWT.NONE); - reward.setText("<"); - reward.setData(RWT.CUSTOM_VARIANT, "action"); - reward.addListener(SWT.MouseDown, event -> { - this.entityTable.selectPage(pageNumber - 1); - }); + private void createBackwardLabel( + final boolean visible, + final int pageNumber, + final Composite parent) { + + final Label backward = new Label(parent, SWT.NONE); + backward.setText("<"); + backward.setData(RWT.CUSTOM_VARIANT, "action"); + if (visible) { + backward.addListener(SWT.MouseDown, event -> { + this.entityTable.selectPage(pageNumber - 1); + }); + } else { + backward.setVisible(false); + } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java index 81c358f6..742eafcb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/MultiSelection.java @@ -23,6 +23,7 @@ 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.service.page.PageUtils; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; public class MultiSelection extends Composite implements Selection { @@ -48,7 +49,7 @@ public class MultiSelection extends Composite implements Selection { final String selectionValue = getSelectionValue(); this.selected.clear(); this.labels.clear(); - WidgetFactory.clearComposite(this); + PageUtils.clearComposite(this); for (final Tuple tuple : mapping) { final Label label = new Label(this, SWT.NONE); final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java index 48f6d75a..117fa460 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java @@ -25,7 +25,6 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; @@ -431,16 +430,6 @@ public class WidgetFactory { } } - public static void clearComposite(final Composite parent) { - if (parent == null) { - return; - } - - for (final Control control : parent.getChildren()) { - control.dispose(); - } - } - private static final Consumer