From 884f9c78e00bb189f579a9f0d7fa0cb04b6a4cb6 Mon Sep 17 00:00:00 2001 From: anhefti Date: Thu, 5 Mar 2020 16:05:56 +0100 Subject: [PATCH] code cleanup --- .../seb/sebserver/gui/content/ExamForm.java | 12 +- .../seb/sebserver/gui/content/ExamList.java | 8 +- .../sebserver/gui/content/LmsSetupList.java | 4 +- .../seb/sebserver/gui/content/LoginPage.java | 397 +++--- .../seb/sebserver/gui/content/MainPage.java | 368 +++--- .../gui/content/QuizDiscoveryList.java | 4 +- .../sebserver/gui/content/RegisterPage.java | 4 +- .../gui/content/SebClientConfigList.java | 4 +- .../gui/content/SebExamConfigImportPopup.java | 13 +- .../gui/content/SebExamConfigList.java | 4 +- .../gui/content/SebExamConfigPropForm.java | 4 +- .../content/SebExamConfigSettingsForm.java | 2 +- .../gui/content/action/ActionCategory.java | 82 +- .../gui/content/action/ActionDefinition.java | 2 +- .../gui/content/action/ActionPane.java | 31 +- .../gui/content/activity/ActivitiesPane.java | 1170 ++++++++--------- .../content/activity/ActivityDefinition.java | 84 +- .../activity/PageStateDefinitionImpl.java | 4 +- .../gui/form/ThresholdListBuilder.java | 1 - .../examconfig/ExamConfigurationService.java | 218 +-- .../impl/AbstractTableFieldBuilder.java | 674 +++++----- .../impl/CellFieldBuilderAdapter.java | 448 +++---- .../examconfig/impl/CheckBoxBuilder.java | 268 ++-- .../impl/CompositeTableFieldBuilder.java | 540 ++++---- .../impl/ExamConfigurationServiceImpl.java | 837 ++++++------ .../impl/InlineTableFieldBuilder.java | 262 ++-- .../impl/InputFieldBuilderSupplier.java | 93 +- .../service/examconfig/impl/LabelBuilder.java | 172 +-- .../examconfig/impl/PasswordFieldBuilder.java | 2 +- .../impl/SelectionFieldBuilder.java | 149 ++- .../examconfig/impl/TableFieldBuilder.java | 450 ++++--- .../examconfig/impl/TableRowFormBuilder.java | 322 +++-- .../service/examconfig/impl/ViewContext.java | 498 ++++--- .../examconfig/impl/ViewGridBuilder.java | 426 +++--- .../impl/rules/BrowserViewModeRule.java | 152 ++- .../gui/service/i18n/I18nSupport.java | 28 +- .../gui/service/i18n/PolyglotPageService.java | 86 +- .../service/i18n/impl/I18nSupportImpl.java | 371 +++--- .../i18n/impl/PolyglotPageServiceImpl.java | 12 - .../page/impl/ComposerServiceImpl.java | 404 +++--- 40 files changed, 4320 insertions(+), 4290 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java index 95c309cf..2718f4a9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java @@ -101,15 +101,15 @@ public class ExamForm implements TemplateComposer { new LocTextKey("sebserver.exam.form.status"); private static final LocTextKey FORM_TYPE_TEXT_KEY = new LocTextKey("sebserver.exam.form.type"); - private static final LocTextKey FORM_ENDTIME_TEXT_KEY = + private static final LocTextKey FORM_END_TIME_TEXT_KEY = new LocTextKey("sebserver.exam.form.endtime"); - private static final LocTextKey FORM_STARTTIME_TEXT_KEY = + private static final LocTextKey FORM_START_TIME_TEXT_KEY = new LocTextKey("sebserver.exam.form.starttime"); private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY = new LocTextKey("sebserver.exam.form.description"); private static final LocTextKey FORM_NAME_TEXT_KEY = new LocTextKey("sebserver.exam.form.name"); - private static final LocTextKey FORM_QUIZID_TEXT_KEY = + private static final LocTextKey FORM_QUIZ_ID_TEXT_KEY = new LocTextKey("sebserver.exam.form.quizid"); private static final LocTextKey FORM_QUIZ_URL_TEXT_KEY = new LocTextKey("sebserver.exam.form.quizurl"); @@ -285,14 +285,14 @@ public class ExamForm implements TemplateComposer { .addField(FormBuilder.text( QuizData.QUIZ_ATTR_START_TIME, - FORM_STARTTIME_TEXT_KEY, + FORM_START_TIME_TEXT_KEY, i18nSupport.formatDisplayDateWithTimeZone(exam.startTime)) .readonly(true) .withInputSpan(3) .withEmptyCellSeparation(false)) .addField(FormBuilder.text( QuizData.QUIZ_ATTR_END_TIME, - FORM_ENDTIME_TEXT_KEY, + FORM_END_TIME_TEXT_KEY, i18nSupport.formatDisplayDateWithTimeZone(exam.endTime)) .readonly(true) .withInputSpan(3) @@ -300,7 +300,7 @@ public class ExamForm implements TemplateComposer { .addField(FormBuilder.text( Domain.EXAM.ATTR_EXTERNAL_ID, - FORM_QUIZID_TEXT_KEY, + FORM_QUIZ_ID_TEXT_KEY, exam.externalId) .readonly(true) .withEmptyCellSeparation(false)) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java index 634296df..dcdfa841 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java @@ -62,11 +62,11 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; @GuiProfile public class ExamList implements TemplateComposer { - static final String EXAM_LIST_COLUMN_STARTTIME = + static final String EXAM_LIST_COLUMN_START_TIME = "sebserver.exam.list.column.starttime"; static final LocTextKey PAGE_TITLE_KEY = new LocTextKey("sebserver.exam.list.title"); - static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = + static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION = new LocTextKey("sebserver.exam.list.action.no.modify.privilege"); final static LocTextKey EMPTY_SELECTION_TEXT_KEY = new LocTextKey("sebserver.exam.info.pleaseSelect"); @@ -175,7 +175,7 @@ public class ExamList implements TemplateComposer { .withColumn(new ColumnDefinition<>( QuizData.QUIZ_ATTR_START_TIME, new LocTextKey( - EXAM_LIST_COLUMN_STARTTIME, + EXAM_LIST_COLUMN_START_TIME, i18nSupport.getUsersTimeZoneTitleSuffix()), Exam::getStartTime) .withFilter(new TableFilterAttribute( @@ -213,7 +213,7 @@ public class ExamList implements TemplateComposer { .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) .withSelect( - table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), action -> modifyExam(action, table), EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> userGrant.im() && table.hasAnyContent(), false); 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 index afd7f843..49ceb0f9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java @@ -46,7 +46,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @GuiProfile public class LmsSetupList implements TemplateComposer { - private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = + private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION = new LocTextKey("sebserver.lmssetup.list.action.no.modify.privilege"); private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = new LocTextKey("sebserver.lmssetup.info.pleaseSelect"); @@ -173,7 +173,7 @@ public class LmsSetupList implements TemplateComposer { .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST) .withSelect( - table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> userGrant.im() && table.hasAnyContent(), false) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java index b6d0648d..8c4134bd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LoginPage.java @@ -1,201 +1,196 @@ -/* - * 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.apache.commons.lang3.BooleanUtils; -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.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.MessageBox; -import org.eclipse.swt.widgets.Text; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -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.service.i18n.I18nSupport; -import ch.ethz.seb.sebserver.gui.service.page.PageContext; -import ch.ethz.seb.sebserver.gui.service.page.PageService; -import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; -import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultRegisterPage; -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.widget.Message; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; - -@Lazy -@Component -@GuiProfile -public class LoginPage implements TemplateComposer { - - private static final Logger log = LoggerFactory.getLogger(LoginPage.class); - - private final PageService pageService; - private final AuthorizationContextHolder authorizationContextHolder; - private final WidgetFactory widgetFactory; - private final I18nSupport i18nSupport; - private final DefaultRegisterPage defaultRegisterPage; - private final boolean registreringEnabled; - - public LoginPage( - final PageService pageService, - final DefaultRegisterPage defaultRegisterPage, - @Value("${sebserver.gui.self-registering:false}") final Boolean registreringEnabled) { - - this.pageService = pageService; - this.authorizationContextHolder = pageService.getAuthorizationContextHolder(); - this.widgetFactory = pageService.getWidgetFactory(); - this.i18nSupport = pageService.getI18nSupport(); - this.defaultRegisterPage = defaultRegisterPage; - this.registreringEnabled = BooleanUtils.toBoolean(registreringEnabled); - } - - @Override - public void compose(final PageContext pageContext) { - final Composite parent = pageContext.getParent(); - WidgetFactory.setTestId(parent, "login-page"); - WidgetFactory.setARIARole(parent, "composite"); - - final Composite loginGroup = new Composite(parent, SWT.NONE); - final GridLayout rowLayout = new GridLayout(); - rowLayout.marginWidth = 20; - rowLayout.marginRight = 100; - loginGroup.setLayout(rowLayout); - loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key); - - final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username"); - name.setLayoutData(new GridData(300, -1)); - name.setAlignment(SWT.BOTTOM); - final Text loginName = this.widgetFactory.textInput(loginGroup); - loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); - GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); - gridData.verticalIndent = 10; - final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd"); - pwd.setLayoutData(gridData); - final Text loginPassword = this.widgetFactory.passwordInput(loginGroup); - loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); - - final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder - .getAuthorizationContext(RWT.getUISession().getHttpSession()); - - final Composite buttons = new Composite(loginGroup, SWT.NONE); - buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - buttons.setLayout(new GridLayout(2, false)); - buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key); - - final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login"); - gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); - gridData.verticalIndent = 10; - loginButton.setLayoutData(gridData); - loginButton.addListener(SWT.Selection, event -> { - login( - pageContext, - loginName.getText(), - loginPassword.getText(), - authorizationContext); - }); - loginName.addListener(SWT.KeyDown, event -> { - if (event.character == '\n' || event.character == '\r') { - if (StringUtils.isNotBlank(loginPassword.getText())) { - login( - pageContext, - loginName.getText(), - loginPassword.getText(), - authorizationContext); - } else { - loginPassword.setFocus(); - } - } - }); - loginPassword.addListener(SWT.KeyDown, event -> { - if (event.character == '\n' || event.character == '\r') { - if (StringUtils.isNotBlank(loginName.getText())) { - login( - pageContext, - loginName.getText(), - loginPassword.getText(), - authorizationContext); - } else { - loginName.setFocus(); - } - } - }); - - if (this.registreringEnabled) { - final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register"); - gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); - gridData.verticalIndent = 10; - registerButton.setLayoutData(gridData); - registerButton.addListener(SWT.Selection, event -> { - pageContext.forwardToPage(this.defaultRegisterPage); - }); - } - } - - private void login( - final PageContext pageContext, - final String loginName, - final CharSequence loginPassword, - final SEBServerAuthorizationContext authorizationContext) { - - final String username = loginName; - try { - - final boolean loggedIn = authorizationContext.login( - username, - loginPassword); - - if (loggedIn) { - // Set users locale on page after successful login - try { - RWT.getUISession() - .getHttpSession() - .setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, authorizationContext - .getLoggedInUser() - .getOrThrow().language); - - } catch (final IllegalStateException e) { - log.error("Set current locale for session failed: ", e); - } - - RWT.setLocale(this.i18nSupport.getUsersFormatLocale()); - - pageContext.forwardToMainPage(); - - } else { - loginError(pageContext, "sebserver.login.failed.message"); - } - } catch (final Exception e) { - log.error("Unexpected error while trying to login with user: {}", username, e); - loginError(pageContext, "Unexpected Error. Please call an Administrator"); - } - } - - private void loginError( - final PageContext pageContext, - final String message) { - - this.pageService.logout(pageContext); - final MessageBox error = new Message( - pageContext.getShell(), - this.i18nSupport.getText("sebserver.login.failed.title"), - this.i18nSupport.getText(message, message), - SWT.ERROR, - this.i18nSupport); - error.open(null); - } - -} +/* + * 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.apache.commons.lang3.BooleanUtils; +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.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Text; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +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.service.i18n.I18nSupport; +import ch.ethz.seb.sebserver.gui.service.page.PageContext; +import ch.ethz.seb.sebserver.gui.service.page.PageService; +import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; +import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultRegisterPage; +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.widget.Message; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; + +@Lazy +@Component +@GuiProfile +public class LoginPage implements TemplateComposer { + + private static final Logger log = LoggerFactory.getLogger(LoginPage.class); + + private final PageService pageService; + private final AuthorizationContextHolder authorizationContextHolder; + private final WidgetFactory widgetFactory; + private final I18nSupport i18nSupport; + private final DefaultRegisterPage defaultRegisterPage; + private final boolean registeringEnabled; + + public LoginPage( + final PageService pageService, + final DefaultRegisterPage defaultRegisterPage, + @Value("${sebserver.gui.self-registering:false}") final Boolean registeringEnabled) { + + this.pageService = pageService; + this.authorizationContextHolder = pageService.getAuthorizationContextHolder(); + this.widgetFactory = pageService.getWidgetFactory(); + this.i18nSupport = pageService.getI18nSupport(); + this.defaultRegisterPage = defaultRegisterPage; + this.registeringEnabled = BooleanUtils.toBoolean(registeringEnabled); + } + + @Override + public void compose(final PageContext pageContext) { + final Composite parent = pageContext.getParent(); + WidgetFactory.setTestId(parent, "login-page"); + WidgetFactory.setARIARole(parent, "composite"); + + final Composite loginGroup = new Composite(parent, SWT.NONE); + final GridLayout rowLayout = new GridLayout(); + rowLayout.marginWidth = 20; + rowLayout.marginRight = 100; + loginGroup.setLayout(rowLayout); + loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key); + + final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username"); + name.setLayoutData(new GridData(300, -1)); + name.setAlignment(SWT.BOTTOM); + final Text loginName = this.widgetFactory.textInput(loginGroup); + loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); + gridData.verticalIndent = 10; + final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd"); + pwd.setLayoutData(gridData); + final Text loginPassword = this.widgetFactory.passwordInput(loginGroup); + loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + + final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder + .getAuthorizationContext(RWT.getUISession().getHttpSession()); + + final Composite buttons = new Composite(loginGroup, SWT.NONE); + buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + buttons.setLayout(new GridLayout(2, false)); + buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key); + + final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login"); + gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); + gridData.verticalIndent = 10; + loginButton.setLayoutData(gridData); + loginButton.addListener(SWT.Selection, event -> login( + pageContext, + loginName.getText(), + loginPassword.getText(), + authorizationContext)); + loginName.addListener(SWT.KeyDown, event -> { + if (event.character == '\n' || event.character == '\r') { + if (StringUtils.isNotBlank(loginPassword.getText())) { + login( + pageContext, + loginName.getText(), + loginPassword.getText(), + authorizationContext); + } else { + loginPassword.setFocus(); + } + } + }); + loginPassword.addListener(SWT.KeyDown, event -> { + if (event.character == '\n' || event.character == '\r') { + if (StringUtils.isNotBlank(loginName.getText())) { + login( + pageContext, + loginName.getText(), + loginPassword.getText(), + authorizationContext); + } else { + loginName.setFocus(); + } + } + }); + + if (this.registeringEnabled) { + final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register"); + gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); + gridData.verticalIndent = 10; + registerButton.setLayoutData(gridData); + registerButton.addListener(SWT.Selection, event -> pageContext.forwardToPage(this.defaultRegisterPage)); + } + } + + private void login( + final PageContext pageContext, + final String loginName, + final CharSequence loginPassword, + final SEBServerAuthorizationContext authorizationContext) { + + try { + + final boolean loggedIn = authorizationContext.login( + loginName, + loginPassword); + + if (loggedIn) { + // Set users locale on page after successful login + try { + RWT.getUISession() + .getHttpSession() + .setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, authorizationContext + .getLoggedInUser() + .getOrThrow().language); + + } catch (final IllegalStateException e) { + log.error("Set current locale for session failed: ", e); + } + + RWT.setLocale(this.i18nSupport.getUsersFormatLocale()); + + pageContext.forwardToMainPage(); + + } else { + loginError(pageContext, "sebserver.login.failed.message"); + } + } catch (final Exception e) { + log.error("Unexpected error while trying to login with user: {}", loginName, e); + loginError(pageContext, "Unexpected Error. Please call an Administrator"); + } + } + + private void loginError( + final PageContext pageContext, + final String message) { + + this.pageService.logout(pageContext); + final MessageBox error = new Message( + pageContext.getShell(), + this.i18nSupport.getText("sebserver.login.failed.title"), + this.i18nSupport.getText(message, message), + SWT.ERROR, + this.i18nSupport); + error.open(null); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java index 786593b0..05c3e434 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MainPage.java @@ -1,184 +1,184 @@ -/* - * 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.Consumer; - -import org.eclipse.rap.rwt.RWT; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.SashForm; -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.slf4j.Logger; -import org.slf4j.LoggerFactory; -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.i18n.PolyglotPageService; -import ch.ethz.seb.sebserver.gui.service.page.PageContext; -import ch.ethz.seb.sebserver.gui.service.page.PageService; -import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; -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.PageEventListener; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; - -@Lazy -@Component -@GuiProfile -public class MainPage implements TemplateComposer { - - static final Logger log = LoggerFactory.getLogger(MainPage.class); - - private static final int ACTIVITY_PANE_WEIGHT = 18; - private static final int CONTENT_PANE_WEIGHT = 65; - private static final int ACTION_PANE_WEIGHT = 20; - private static final int[] DEFAULT_SASH_WEIGHTS = new int[] { - ACTIVITY_PANE_WEIGHT, - CONTENT_PANE_WEIGHT, - ACTION_PANE_WEIGHT - }; - private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 }; - - private final WidgetFactory widgetFactory; - private final PolyglotPageService polyglotPageService; - - public MainPage( - final WidgetFactory widgetFactory, - final PolyglotPageService polyglotPageService) { - - this.widgetFactory = widgetFactory; - this.polyglotPageService = polyglotPageService; - } - - @Override - public void compose(final PageContext pageContext) { - - final Composite parent = pageContext.getParent(); - parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - WidgetFactory.setTestId(parent, "main-page"); - - final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL); - final GridLayout gridLayout = new GridLayout(); - - mainSash.setLayout(gridLayout); - mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - final Composite nav = new Composite(mainSash, SWT.NONE); - nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - final GridLayout navLayout = new GridLayout(); - navLayout.marginHeight = 20; - navLayout.marginWidth = 0; - nav.setLayout(navLayout); - - final Composite content = PageService.createManagedVScrolledComposite( - mainSash, - scrolledComposite -> { - final Composite result = new Composite(scrolledComposite, SWT.NONE); - result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - final GridLayout contentOuterlayout = new GridLayout(); - contentOuterlayout.marginHeight = 0; - contentOuterlayout.marginWidth = 0; - result.setLayout(contentOuterlayout); - return result; - }, - false); - - final Label toggleView = this.widgetFactory.imageButton( - ImageIcon.MAXIMIZE, - content, - new LocTextKey("sebserver.mainpage.maximize.tooltip"), - event -> { - final Label ib = (Label) event.widget; - if ((Boolean) ib.getData("fullScreen")) { - mainSash.setWeights(DEFAULT_SASH_WEIGHTS); - ib.setData("fullScreen", false); - ib.setImage(WidgetFactory.ImageIcon.MAXIMIZE.getImage(ib.getDisplay())); - this.polyglotPageService.injectI18n( - ib, - null, - new LocTextKey("sebserver.mainpage.maximize.tooltip")); - } else { - mainSash.setWeights(OPENED_SASH_WEIGHTS); - ib.setData("fullScreen", true); - ib.setImage(WidgetFactory.ImageIcon.MINIMIZE.getImage(ib.getDisplay())); - this.polyglotPageService.injectI18n( - ib, - null, - new LocTextKey("sebserver.mainpage.minimize.tooltip")); - } - }); - final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false); - toggleView.setLayoutData(gridData); - toggleView.setData("fullScreen", false); - - final Composite contentObjects = new Composite(content, SWT.NONE); - contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - final GridLayout contentObjectslayout = new GridLayout(); - contentObjectslayout.marginHeight = 0; - contentObjectslayout.marginWidth = 0; - contentObjects.setLayout(contentObjectslayout); - contentObjects.setData( - PageEventListener.LISTENER_ATTRIBUTE_KEY, - new ContentActionEventListener(event -> pageContext - .composerService() - .compose( - event.action.definition.targetState.contentPaneComposer(), - event.action.pageContext().copyOf(contentObjects)), - 2)); - - final Composite actionPane = new Composite(mainSash, SWT.NONE); - actionPane.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - final GridLayout actionPaneGrid = new GridLayout(); - actionPane.setLayout(actionPaneGrid); - actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane"); - actionPane.setData( - PageEventListener.LISTENER_ATTRIBUTE_KEY, - new ContentActionEventListener(event -> pageContext - .composerService() - .compose( - event.action.definition.targetState.actionPaneComposer(), - event.action.pageContext().copyOf(actionPane)), - 1)); - - pageContext.composerService().compose( - ActivitiesPane.class, - pageContext.copyOf(nav)); - - mainSash.setWeights(DEFAULT_SASH_WEIGHTS); - } - - private static final class ContentActionEventListener implements ActionEventListener { - - private final int priority; - private final Consumer apply; - - protected ContentActionEventListener(final Consumer apply, final int priority) { - this.apply = apply; - this.priority = priority; - } - - @Override - public int priority() { - return this.priority; - } - - @Override - public void notify(final ActionEvent event) { - this.apply.accept(event); - } - } - -} +/* + * 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.Consumer; + +import org.eclipse.rap.rwt.RWT; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.i18n.PolyglotPageService; +import ch.ethz.seb.sebserver.gui.service.page.PageContext; +import ch.ethz.seb.sebserver.gui.service.page.PageService; +import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; +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.PageEventListener; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; + +@Lazy +@Component +@GuiProfile +public class MainPage implements TemplateComposer { + + static final Logger log = LoggerFactory.getLogger(MainPage.class); + + private static final int ACTIVITY_PANE_WEIGHT = 18; + private static final int CONTENT_PANE_WEIGHT = 65; + private static final int ACTION_PANE_WEIGHT = 20; + private static final int[] DEFAULT_SASH_WEIGHTS = new int[] { + ACTIVITY_PANE_WEIGHT, + CONTENT_PANE_WEIGHT, + ACTION_PANE_WEIGHT + }; + private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 }; + + private final WidgetFactory widgetFactory; + private final PolyglotPageService polyglotPageService; + + public MainPage( + final WidgetFactory widgetFactory, + final PolyglotPageService polyglotPageService) { + + this.widgetFactory = widgetFactory; + this.polyglotPageService = polyglotPageService; + } + + @Override + public void compose(final PageContext pageContext) { + + final Composite parent = pageContext.getParent(); + parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + WidgetFactory.setTestId(parent, "main-page"); + + final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL); + final GridLayout gridLayout = new GridLayout(); + + mainSash.setLayout(gridLayout); + mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + final Composite nav = new Composite(mainSash, SWT.NONE); + nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + final GridLayout navLayout = new GridLayout(); + navLayout.marginHeight = 20; + navLayout.marginWidth = 0; + nav.setLayout(navLayout); + + final Composite content = PageService.createManagedVScrolledComposite( + mainSash, + scrolledComposite -> { + final Composite result = new Composite(scrolledComposite, SWT.NONE); + result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + final GridLayout contentOuterLayout = new GridLayout(); + contentOuterLayout.marginHeight = 0; + contentOuterLayout.marginWidth = 0; + result.setLayout(contentOuterLayout); + return result; + }, + false); + + final Label toggleView = this.widgetFactory.imageButton( + ImageIcon.MAXIMIZE, + content, + new LocTextKey("sebserver.mainpage.maximize.tooltip"), + event -> { + final Label ib = (Label) event.widget; + if ((Boolean) ib.getData("fullScreen")) { + mainSash.setWeights(DEFAULT_SASH_WEIGHTS); + ib.setData("fullScreen", false); + ib.setImage(WidgetFactory.ImageIcon.MAXIMIZE.getImage(ib.getDisplay())); + this.polyglotPageService.injectI18n( + ib, + null, + new LocTextKey("sebserver.mainpage.maximize.tooltip")); + } else { + mainSash.setWeights(OPENED_SASH_WEIGHTS); + ib.setData("fullScreen", true); + ib.setImage(WidgetFactory.ImageIcon.MINIMIZE.getImage(ib.getDisplay())); + this.polyglotPageService.injectI18n( + ib, + null, + new LocTextKey("sebserver.mainpage.minimize.tooltip")); + } + }); + final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false); + toggleView.setLayoutData(gridData); + toggleView.setData("fullScreen", false); + + final Composite contentObjects = new Composite(content, SWT.NONE); + contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + final GridLayout contentObjectsLayout = new GridLayout(); + contentObjectsLayout.marginHeight = 0; + contentObjectsLayout.marginWidth = 0; + contentObjects.setLayout(contentObjectsLayout); + contentObjects.setData( + PageEventListener.LISTENER_ATTRIBUTE_KEY, + new ContentActionEventListener(event -> pageContext + .composerService() + .compose( + event.action.definition.targetState.contentPaneComposer(), + event.action.pageContext().copyOf(contentObjects)), + 2)); + + final Composite actionPane = new Composite(mainSash, SWT.NONE); + actionPane.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + final GridLayout actionPaneGrid = new GridLayout(); + actionPane.setLayout(actionPaneGrid); + actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane"); + actionPane.setData( + PageEventListener.LISTENER_ATTRIBUTE_KEY, + new ContentActionEventListener(event -> pageContext + .composerService() + .compose( + event.action.definition.targetState.actionPaneComposer(), + event.action.pageContext().copyOf(actionPane)), + 1)); + + pageContext.composerService().compose( + ActivitiesPane.class, + pageContext.copyOf(nav)); + + mainSash.setWeights(DEFAULT_SASH_WEIGHTS); + } + + private static final class ContentActionEventListener implements ActionEventListener { + + private final int priority; + private final Consumer apply; + + protected ContentActionEventListener(final Consumer apply, final int priority) { + this.apply = apply; + this.priority = priority; + } + + @Override + public int priority() { + return this.priority; + } + + @Override + public void notify(final ActionEvent event) { + this.apply.accept(event); + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java index 18d69c43..48f3fae0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizDiscoveryList.java @@ -240,8 +240,8 @@ public class QuizDiscoveryList implements TemplateComposer { } private static Function quizDataLmsSetupNameFunction(final ResourceService resourceService) { - return quizzData -> resourceService.getLmsSetupNameFunction() - .apply(String.valueOf(quizzData.lmsSetupId)); + return quizData -> resourceService.getLmsSetupNameFunction() + .apply(String.valueOf(quizData.lmsSetupId)); } private PageAction importQuizData(final PageAction action, final EntityTable table) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java index 0bc75e92..07f2648e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java @@ -247,9 +247,7 @@ public class RegisterPage implements TemplateComposer { gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); gridData.verticalIndent = 10; cancelButton.setLayoutData(gridData); - cancelButton.addListener(SWT.Selection, event -> { - pageContext.forwardToLoginPage(); - }); + cancelButton.addListener(SWT.Selection, event -> pageContext.forwardToLoginPage()); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebClientConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebClientConfigList.java index c1d55c51..885e7180 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebClientConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebClientConfigList.java @@ -48,7 +48,7 @@ import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; @GuiProfile public class SebClientConfigList implements TemplateComposer { - private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = + private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION = new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege"); private static final LocTextKey EMPTY_LIST_TEXT_KEY = new LocTextKey("sebserver.clientconfig.list.empty"); @@ -176,7 +176,7 @@ public class SebClientConfigList implements TemplateComposer { .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST) .withSelect( - table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImportPopup.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImportPopup.java index c2efff12..74bd8e10 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImportPopup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigImportPopup.java @@ -81,7 +81,7 @@ final class SebExamConfigImportPopup { }; } - private static final boolean doImport( + private static boolean doImport( final PageService pageService, final FormHandle formHandle, final boolean newConfig) { @@ -93,7 +93,7 @@ final class SebExamConfigImportPopup { final PageContext context = formHandle.getContext(); // Ad-hoc field validation - formHandle.process(name -> true, field -> field.resetError()); + formHandle.process(name -> true, Form.FormFieldAccessor::resetError); final String fieldValue = form.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_NAME); if (StringUtils.isBlank(fieldValue)) { form.setFieldError( @@ -116,7 +116,7 @@ final class SebExamConfigImportPopup { return false; } - if (fieldControl != null && fieldControl instanceof FileUploadSelection) { + if (fieldControl instanceof FileUploadSelection) { final FileUploadSelection fileUpload = (FileUploadSelection) fieldControl; final InputStream inputStream = fileUpload.getInputStream(); if (inputStream != null) { @@ -162,7 +162,6 @@ final class SebExamConfigImportPopup { new ActionEvent(action), action.pageContext()); } - return true; } else { final Exception error = configuration.getError(); if (error instanceof RestCallError) { @@ -188,12 +187,12 @@ final class SebExamConfigImportPopup { SebExamConfigPropForm.FORM_TITLE, configuration.getError()); - return true; } + return true; } else { formHandle.getContext().publishPageMessage( new LocTextKey("sebserver.error.unexpected"), - new LocTextKey("Please selecte a valid SEB Exam Configuration File")); + new LocTextKey("Please select a valid SEB Exam Configuration File")); } } @@ -271,7 +270,7 @@ final class SebExamConfigImportPopup { void cancelUpload() { if (this.form != null) { final Control fieldControl = this.form.getFieldInput(API.IMPORT_FILE_ATTR_NAME); - if (fieldControl != null && fieldControl instanceof FileUploadSelection) { + if (fieldControl instanceof FileUploadSelection) { ((FileUploadSelection) fieldControl).close(); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java index 6d923b73..d370917a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigList.java @@ -43,7 +43,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @GuiProfile public class SebExamConfigList implements TemplateComposer { - private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = + private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION = new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege"); private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY = new LocTextKey("sebserver.examconfig.list.empty"); @@ -165,7 +165,7 @@ public class SebExamConfigList implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .withSelect( - configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), + configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java index 58670ccf..053220dd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java @@ -265,7 +265,7 @@ public class SebExamConfigPropForm implements TemplateComposer { .noEventPropagation() .publishIf(() -> modifyGrant && isReadonly) - .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE) + .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE) .withEntityKey(entityKey) .withExec(SebExamConfigCreationPopup.configCreationFunction( this.pageService, @@ -313,7 +313,7 @@ public class SebExamConfigPropForm implements TemplateComposer { .withColumn(new ColumnDefinition<>( QuizData.QUIZ_ATTR_START_TIME, new LocTextKey( - ExamList.EXAM_LIST_COLUMN_STARTTIME, + ExamList.EXAM_LIST_COLUMN_START_TIME, this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()), ExamConfigurationMap::getExamStartTime)) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigSettingsForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigSettingsForm.java index 861c6a0f..2da530b5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigSettingsForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigSettingsForm.java @@ -190,7 +190,7 @@ public class SebExamConfigSettingsForm implements TemplateComposer { .ignoreMoveAwayFromEdit() .publishIf(() -> examConfigGrant.iw() && !readonly) - .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE) + .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE) .withEntityKey(entityKey) .withExec(SebExamConfigCreationPopup.configCreationFunction( this.pageService, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java index ef198c48..13dc826e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java @@ -1,41 +1,41 @@ -/* - * 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; - -import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; - -public enum ActionCategory { - FORM(null, 0), - INSTITUTION_LIST(new LocTextKey("sebserver.institution.list.actions"), 1), - USER_ACCOUNT_LIST(new LocTextKey("sebserver.useraccount.list.actions"), 1), - LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1), - QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1), - EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1), - EXAM_CONFIG_MAPPING_LIST(new LocTextKey("sebserver.exam.configuration.list.actions"), 1), - INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2), - SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1), - SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1), - SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1), - SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1), - RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1), - CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1), - LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1), - LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1), - VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0), - FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50); - - public final LocTextKey title; - public final int slotPosition; - - private ActionCategory(final LocTextKey title, final int slotPosition) { - this.title = title; - this.slotPosition = slotPosition; - } - -} +/* + * 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; + +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; + +public enum ActionCategory { + FORM(null, 0), + INSTITUTION_LIST(new LocTextKey("sebserver.institution.list.actions"), 1), + USER_ACCOUNT_LIST(new LocTextKey("sebserver.useraccount.list.actions"), 1), + LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1), + QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1), + EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1), + EXAM_CONFIG_MAPPING_LIST(new LocTextKey("sebserver.exam.configuration.list.actions"), 1), + INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2), + SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1), + SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1), + SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1), + SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1), + RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1), + CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1), + LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1), + LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1), + VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0), + FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50); + + public final LocTextKey title; + public final int slotPosition; + + ActionCategory(final LocTextKey title, final int slotPosition) { + this.title = title; + this.slotPosition = slotPosition; + } + +} 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 cee362d8..b04b4234 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 @@ -467,7 +467,7 @@ public enum ActionDefinition { new LocTextKey("sebserver.examconfig.action.copy"), ImageIcon.COPY, ActionCategory.FORM), - SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE( + SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE( new LocTextKey("sebserver.examconfig.action.copy-as-template"), ImageIcon.TEMPLATE, ActionCategory.FORM), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java index 8016f417..bdcc7287 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionPane.java @@ -8,10 +8,17 @@ package ch.ethz.seb.sebserver.gui.content.action; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - +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.PageService; +import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; +import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEventListener; +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.page.impl.PageAction; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import org.apache.commons.lang3.StringUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.template.ImageCell; @@ -31,19 +38,9 @@ import org.eclipse.swt.widgets.TreeItem; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -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.PageService; -import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; -import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEvent; -import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEventListener; -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.page.impl.PageAction; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; @Lazy @Component 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 38ba8538..b9f33e03 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 @@ -1,586 +1,584 @@ -/* - * 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.content.activity; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.BooleanUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; - -import ch.ethz.seb.sebserver.gbl.api.EntityType; -import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; -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.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.PageService; -import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; -import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; -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.PageEventListener; -import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; -import ch.ethz.seb.sebserver.gui.service.page.impl.PageState; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; - -@Lazy -@Component -public class ActivitiesPane implements TemplateComposer { - - private static final String SKIP_EXPAND = "SKIP_EXPAND"; - - private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION"; - private static final LocTextKey TITLE_KEY = new LocTextKey("sebserver.activitiespane.title"); - - private final WidgetFactory widgetFactory; - private final CurrentUser currentUser; - private final PageService pageService; - - public ActivitiesPane( - final CurrentUser currentUser, - final PageService pageService) { - - this.widgetFactory = pageService.getWidgetFactory(); - this.currentUser = currentUser; - this.pageService = pageService; - } - - @Override - public void compose(final PageContext pageContext) { - final UserInfo userInfo = this.currentUser - .getOrHandleError(t -> this.pageService.logoutOnError(t, pageContext)); - - final boolean isSupporterOnly = userInfo.hasRole(UserRole.EXAM_SUPPORTER) && - !userInfo.hasAnyRole(UserRole.EXAM_ADMIN, UserRole.INSTITUTIONAL_ADMIN, UserRole.SEB_SERVER_ADMIN); - - if (this.pageService.getI18nSupport().hasText(TITLE_KEY)) { - final Label activities = this.widgetFactory.labelLocalized( - pageContext.getParent(), - CustomVariant.TEXT_H2, - TITLE_KEY); - final GridData activitiesGridData = new GridData(SWT.FILL, SWT.TOP, true, false); - activitiesGridData.horizontalIndent = 20; - activities.setLayoutData(activitiesGridData); - } - - final Tree navigation = this.widgetFactory.treeLocalized( - pageContext.getParent(), - SWT.SINGLE | SWT.FULL_SELECTION); - final GridData navigationGridData = new GridData(SWT.FILL, SWT.FILL, true, true); - //navigationGridData.horizontalIndent = 10; - navigation.setLayoutData(navigationGridData); - - final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext); - - //-------------------------------------------------------------------------------------- - // ---- SEB ADMIN ---------------------------------------------------------------------- - - final boolean isServerOrInstAdmin = this.currentUser.get() - .hasAnyRole(UserRole.SEB_SERVER_ADMIN, UserRole.INSTITUTIONAL_ADMIN); - - // SEB Server Administration - final TreeItem sebadmin = this.widgetFactory.treeItemLocalized( - navigation, - ActivityDefinition.SEB_ADMINISTRATION.displayName); - - // Institution - // If current user has SEB Server Admin role, show the Institution list - if (userInfo.hasRole(UserRole.SEB_SERVER_ADMIN)) { - // institutions (list) as root - final TreeItem institutions = this.widgetFactory.treeItemLocalized( - sebadmin, - ActivityDefinition.INSTITUTION.displayName); - injectActivitySelection( - institutions, - actionBuilder - .newAction(ActionDefinition.INSTITUTION_VIEW_LIST) - .create()); - - } else if (userInfo.hasRole(UserRole.INSTITUTIONAL_ADMIN)) { - // otherwise show the form of the institution for current user - final TreeItem institutions = this.widgetFactory.treeItemLocalized( - sebadmin, - ActivityDefinition.INSTITUTION.displayName); - injectActivitySelection( - institutions, - actionBuilder.newAction(ActionDefinition.INSTITUTION_VIEW_FORM) - .withEntityKey(userInfo.institutionId, EntityType.INSTITUTION) - .withAttribute(AttributeKeys.READ_ONLY, "true") - .create()); - } - - // User Account - // if current user has role seb-server admin or institutional-admin, show list - if (isServerOrInstAdmin) { - - final TreeItem userAccounts = this.widgetFactory.treeItemLocalized( - sebadmin, - ActivityDefinition.USER_ACCOUNT.displayName); - injectActivitySelection( - userAccounts, - actionBuilder - .newAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST) - .create()); - } else { - // otherwise show the user account form for current user - final TreeItem userAccounts = this.widgetFactory.treeItemLocalized( - navigation, - ActivityDefinition.USER_ACCOUNT.displayName); - injectActivitySelection( - userAccounts, - actionBuilder.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FORM) - .withEntityKey(this.currentUser.get().getEntityKey()) - .withAttribute(AttributeKeys.READ_ONLY, "true") - .create()); - } - - // User Activity Logs - final boolean viewUserActivityLogs = this.currentUser.hasInstitutionalPrivilege( - PrivilegeType.READ, - EntityType.USER_ACTIVITY_LOG); - if (viewUserActivityLogs) { - final TreeItem activityLogs = this.widgetFactory.treeItemLocalized( - sebadmin, - ActivityDefinition.USER_ACTIVITY_LOGS.displayName); - injectActivitySelection( - activityLogs, - actionBuilder - .newAction(ActionDefinition.LOGS_USER_ACTIVITY_LIST) - .create()); - } - - if (sebadmin.getItemCount() > 0) { - sebadmin.setExpanded(this.currentUser.get().hasAnyRole( - UserRole.SEB_SERVER_ADMIN, - UserRole.INSTITUTIONAL_ADMIN)); - } else { - sebadmin.dispose(); - } - - // ---- SEB ADMIN ---------------------------------------------------------------------- - //-------------------------------------------------------------------------------------- - - //-------------------------------------------------------------------------------------- - // ---- SEB CONFIGURATION -------------------------------------------------------------- - - // SEB Configurations - final boolean clientConfigRead = this.currentUser.hasInstitutionalPrivilege( - PrivilegeType.READ, - EntityType.SEB_CLIENT_CONFIGURATION); - final boolean examConfigRead = this.currentUser.hasInstitutionalPrivilege( - PrivilegeType.READ, - EntityType.CONFIGURATION_NODE); - - if ((clientConfigRead || examConfigRead) && !isSupporterOnly) { - final TreeItem sebConfigs = this.widgetFactory.treeItemLocalized( - navigation, - ActivityDefinition.SEB_CONFIGURATION.displayName); - - // SEB Client Config - if (clientConfigRead) { - final TreeItem clientConfig = this.widgetFactory.treeItemLocalized( - sebConfigs, - ActivityDefinition.SEB_CLIENT_CONFIG.displayName); - injectActivitySelection( - clientConfig, - actionBuilder - .newAction(ActionDefinition.SEB_CLIENT_CONFIG_LIST) - .create()); - } - - // SEB Exam Config - if (examConfigRead) { - final TreeItem examConfig = this.widgetFactory.treeItemLocalized( - sebConfigs, - ActivityDefinition.SEB_EXAM_CONFIG.displayName); - injectActivitySelection( - examConfig, - actionBuilder - .newAction(ActionDefinition.SEB_EXAM_CONFIG_LIST) - .create()); - } - - // SEB Exam Config Template - if (examConfigRead) { - final TreeItem examConfigTemplate = this.widgetFactory.treeItemLocalized( - sebConfigs, - ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE.displayName); - injectActivitySelection( - examConfigTemplate, - actionBuilder - .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_LIST) - .create()); - } - - sebConfigs.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)); - } - - // ---- SEB CONFIGURATION -------------------------------------------------------------- - //-------------------------------------------------------------------------------------- - - //-------------------------------------------------------------------------------------- - // ---- EXAM ADMINISTRATION ------------------------------------------------------------ - - final boolean lmsRead = this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.LMS_SETUP); - final boolean examRead = userInfo.hasAnyRole(UserRole.EXAM_SUPPORTER, UserRole.EXAM_ADMIN) || - this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.EXAM); - final boolean examWrite = this.currentUser.hasInstitutionalPrivilege(PrivilegeType.WRITE, EntityType.EXAM); - - // Exam Administration - final TreeItem examadmin = this.widgetFactory.treeItemLocalized( - navigation, - ActivityDefinition.EXAM_ADMINISTRATION.displayName); - - if (examRead || lmsRead) { - // LMS Setup - if (lmsRead && !isSupporterOnly) { - final TreeItem lmsSetup = this.widgetFactory.treeItemLocalized( - examadmin, - ActivityDefinition.LMS_SETUP.displayName); - injectActivitySelection( - lmsSetup, - actionBuilder - .newAction(ActionDefinition.LMS_SETUP_VIEW_LIST) - .create()); - } - - if (examRead) { - - if (examWrite) { - // Quiz Discovery - final TreeItem quizDiscovery = this.widgetFactory.treeItemLocalized( - examadmin, - ActivityDefinition.QUIZ_DISCOVERY.displayName); - injectActivitySelection( - quizDiscovery, - actionBuilder - .newAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST) - .create()); - } - - // Exam - final TreeItem exam = this.widgetFactory.treeItemLocalized( - examadmin, - ActivityDefinition.EXAM.displayName); - injectActivitySelection( - exam, - actionBuilder - .newAction(ActionDefinition.EXAM_VIEW_LIST) - .create()); - } - - examadmin.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)); - } - - // ---- EXAM ADMINISTRATION ------------------------------------------------------------ - //-------------------------------------------------------------------------------------- - - //-------------------------------------------------------------------------------------- - // ---- MONITORING --------------------------------------------------------------------- - - final boolean isSupporter = this.currentUser.get().hasAnyRole(UserRole.EXAM_SUPPORTER); - final boolean viewSebClientLogs = this.currentUser.hasInstitutionalPrivilege( - PrivilegeType.READ, - EntityType.EXAM) || - this.currentUser.get().hasRole(UserRole.EXAM_SUPPORTER); - - if (isSupporter || viewSebClientLogs) { - // Monitoring - final TreeItem monitoring = this.widgetFactory.treeItemLocalized( - navigation, - ActivityDefinition.MONITORING.displayName); - - // Monitoring exams - if (isSupporter) { - final TreeItem clientConfig = this.widgetFactory.treeItemLocalized( - monitoring, - ActivityDefinition.MONITORING_EXAMS.displayName); - injectActivitySelection( - clientConfig, - actionBuilder - .newAction(ActionDefinition.RUNNING_EXAM_VIEW_LIST) - .create()); - } - - // SEB Client Logs - if (viewSebClientLogs) { - final TreeItem sebLogs = (isSupporter) - ? this.widgetFactory.treeItemLocalized( - monitoring, - ActivityDefinition.SEB_CLIENT_LOGS.displayName) - : this.widgetFactory.treeItemLocalized( - navigation, - ActivityDefinition.SEB_CLIENT_LOGS.displayName); - injectActivitySelection( - sebLogs, - actionBuilder - .newAction(ActionDefinition.LOGS_SEB_CLIENT) - .create()); - } - - if (monitoring.getItemCount() > 0) { - monitoring.setExpanded( - this.currentUser - .get() - .hasAnyRole(UserRole.EXAM_SUPPORTER)); - } else { - monitoring.dispose(); - } - } - - // ---- MONITORING --------------------------------------------------------------------- - //-------------------------------------------------------------------------------------- - - // register page listener and initialize navigation data - navigation.addListener(SWT.Selection, event -> handleSelection(pageContext, event)); - navigation.addListener(SWT.Expand, event -> { - final TreeItem item = (TreeItem) event.item; - selectCurrentItem(navigation, item); - }); - navigation.addListener(SWT.Collapse, event -> { - final Tree tree = (Tree) event.widget; - tree.setData(SKIP_EXPAND, true); - }); - navigation.addListener(SWT.MouseUp, event -> { - final Tree tree = (Tree) event.widget; - final TreeItem[] selection = tree.getSelection(); - if (ArrayUtils.isNotEmpty(selection)) { - final TreeItem item = selection[0]; - final boolean skipExpand = BooleanUtils.isTrue((Boolean) tree.getData(SKIP_EXPAND)); - if (item.getItemCount() > 0 && !item.getExpanded() && !skipExpand) { - item.setExpanded(true); - handleParentSelection(tree, item); - } - } - tree.setData(SKIP_EXPAND, false); - }); - navigation.setData( - PageEventListener.LISTENER_ATTRIBUTE_KEY, - new ActivitiesActionEventListener(navigation)); - - // page-selection on (re)load - final PageState state = this.pageService.getCurrentState(); - if (state == null) { - final TreeItem item = getDefaultSelectionFor(navigation, this.currentUser); - final TreeItem actionItem = getActionItem(item); - final PageAction activityAction = getActivitySelection(actionItem); - this.pageService.executePageAction(activityAction); - } else { - final TreeItem item = findItemByActionDefinition( - navigation.getItems(), - state.activityAnchor()); - if (item != null) { - final PageAction action = getActivitySelection(item); - this.pageService.executePageAction(action, result -> { - navigation.select(item); - }); - } - } - } - - private TreeItem getDefaultSelectionFor(final Tree navigation, final CurrentUser currentUser2) { - if (this.currentUser.get().hasAnyRole(UserRole.SEB_SERVER_ADMIN, UserRole.INSTITUTIONAL_ADMIN)) { - return navigation.getItem(0); - } else if (this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)) { - return findItemByActionDefinition( - navigation.getItems(), - ActivityDefinition.SEB_EXAM_CONFIG); - } else if (this.currentUser.get().hasAnyRole(UserRole.EXAM_SUPPORTER)) { - return findItemByActionDefinition( - navigation.getItems(), - ActivityDefinition.MONITORING_EXAMS); - } else { - return navigation.getItem(0); - } - } - - private void selectCurrentItem(final Tree navigation, final TreeItem item) { - final PageState currentState = this.pageService.getCurrentState(); - if (currentState == null) { - return; - } - final TreeItem currentItem = findItemByActionDefinition( - item.getItems(), - currentState.definition.activityAnchor()); - if (currentItem != null) { - navigation.select(currentItem); - } - } - - private void handleSelection(final PageContext composerCtx, final Event event) { - final Tree tree = (Tree) event.widget; - final TreeItem treeItem = (TreeItem) event.item; - - if (treeItem.getItemCount() > 0 && !treeItem.getExpanded()) { - return; - } - - final PageAction action = getActivitySelection(treeItem); - // if there is no form action associated with the treeItem and the treeItem has sub items, toggle the item state - if (action == null) { - handleParentSelection(tree, treeItem); - return; - } - - final PageState currentState = this.pageService.getCurrentState(); - if (currentState != null && currentState.definition == action.definition.targetState) { - return; - } - - this.pageService.executePageAction( - action, - resultAction -> { - if (resultAction.hasError()) { - tree.deselect(treeItem); - if (currentState != null) { - final TreeItem item = findItemByActionDefinition( - tree.getItems(), - currentState.activityAnchor()); - if (item != null) { - tree.select(item); - } - } - } - }); - } - - private void handleParentSelection(final Tree tree, final TreeItem treeItem) { - if (treeItem.getItemCount() > 0) { - final PageState currentState = this.pageService.getCurrentState(); - final TreeItem currentSelection = findItemByActionDefinition( - tree.getItems(), - currentState.activityAnchor()); - if (currentSelection != null) { - if (isInSubTree(treeItem, currentSelection)) { - tree.setSelection(currentSelection); - } else { - selectFirstChild(tree, treeItem); - } - } else { - tree.deselectAll(); - } - } - - tree.layout(); - } - - private void selectFirstChild(final Tree tree, final TreeItem treeItem) { - final TreeItem actionItem = ActivitiesPane.getActionItem(treeItem); - final PageAction activitySelection = getActivitySelection(actionItem); - this.pageService.executePageAction(activitySelection, result -> { - if (!result.hasError()) { - tree.setSelection(actionItem); - } - }); - } - - private static final boolean isInSubTree(final TreeItem treeItem, final TreeItem currentSelection) { - if (treeItem == null) { - return false; - } - - final TreeItem[] items = treeItem.getItems(); - if (ArrayUtils.isEmpty(items)) { - return false; - } - - for (final TreeItem item : items) { - if (item.equals(currentSelection)) { - return true; - } - } - - return false; - } - - private static final TreeItem findItemByActionDefinition( - final TreeItem[] items, - final Activity activity) { - - if (items == null) { - return null; - } - - for (final TreeItem item : items) { - final PageAction action = getActivitySelection(item); - if (action == null) { - if (item.getItemCount() > 0) { - final TreeItem found = findItemByActionDefinition(item.getItems(), activity); - if (found != null) { - return found; - } - } - continue; - } - - final Activity activityAnchor = action.definition.targetState.activityAnchor(); - if (activityAnchor.name().equals(activity.name())) { - return item; - } - - final TreeItem _item = findItemByActionDefinition(item.getItems(), activity); - if (_item != null) { - return _item; - } - } - - return null; - } - - private static final TreeItem getActionItem(final TreeItem item) { - final PageAction action = (PageAction) item.getData(ATTR_ACTIVITY_SELECTION); - if (action == null && item.getItemCount() > 0) { - final TreeItem firstChild = item.getItem(0); - if (firstChild != null) { - return firstChild; - } - } - - return item; - } - - private static final PageAction getActivitySelection(final TreeItem item) { - return (PageAction) item.getData(ATTR_ACTIVITY_SELECTION); - } - - private final static void injectActivitySelection(final TreeItem item, final PageAction action) { - item.setData(ATTR_ACTIVITY_SELECTION, action); - } - - private static final class ActivitiesActionEventListener implements ActionEventListener { - private final Tree navigation; - - private ActivitiesActionEventListener(final Tree navigation) { - this.navigation = navigation; - } - - @Override - public void notify(final ActionEvent event) { - final TreeItem item = findItemByActionDefinition( - this.navigation.getItems(), - event.action.definition.targetState.activityAnchor()); - if (item != null) { - this.navigation.deselectAll(); - this.navigation.select(item); - } - } - } - -} +/* + * 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.content.activity; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; +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.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.PageService; +import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; +import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; +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.PageEventListener; +import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; +import ch.ethz.seb.sebserver.gui.service.page.impl.PageState; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; + +@Lazy +@Component +public class ActivitiesPane implements TemplateComposer { + + private static final String SKIP_EXPAND = "SKIP_EXPAND"; + + private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION"; + private static final LocTextKey TITLE_KEY = new LocTextKey("sebserver.activitiespane.title"); + + private final WidgetFactory widgetFactory; + private final CurrentUser currentUser; + private final PageService pageService; + + public ActivitiesPane( + final CurrentUser currentUser, + final PageService pageService) { + + this.widgetFactory = pageService.getWidgetFactory(); + this.currentUser = currentUser; + this.pageService = pageService; + } + + @Override + public void compose(final PageContext pageContext) { + final UserInfo userInfo = this.currentUser + .getOrHandleError(t -> this.pageService.logoutOnError(t, pageContext)); + + final boolean isSupporterOnly = userInfo.hasRole(UserRole.EXAM_SUPPORTER) && + !userInfo.hasAnyRole(UserRole.EXAM_ADMIN, UserRole.INSTITUTIONAL_ADMIN, UserRole.SEB_SERVER_ADMIN); + + if (this.pageService.getI18nSupport().hasText(TITLE_KEY)) { + final Label activities = this.widgetFactory.labelLocalized( + pageContext.getParent(), + CustomVariant.TEXT_H2, + TITLE_KEY); + final GridData activitiesGridData = new GridData(SWT.FILL, SWT.TOP, true, false); + activitiesGridData.horizontalIndent = 20; + activities.setLayoutData(activitiesGridData); + } + + final Tree navigation = this.widgetFactory.treeLocalized( + pageContext.getParent(), + SWT.SINGLE | SWT.FULL_SELECTION); + final GridData navigationGridData = new GridData(SWT.FILL, SWT.FILL, true, true); + //navigationGridData.horizontalIndent = 10; + navigation.setLayoutData(navigationGridData); + + final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext); + + //-------------------------------------------------------------------------------------- + // ---- SEB ADMIN ---------------------------------------------------------------------- + + final boolean isServerOrInstAdmin = this.currentUser.get() + .hasAnyRole(UserRole.SEB_SERVER_ADMIN, UserRole.INSTITUTIONAL_ADMIN); + + // SEB Server Administration + final TreeItem sebAdmin = this.widgetFactory.treeItemLocalized( + navigation, + ActivityDefinition.SEB_ADMINISTRATION.displayName); + + // Institution + // If current user has SEB Server Admin role, show the Institution list + if (userInfo.hasRole(UserRole.SEB_SERVER_ADMIN)) { + // institutions (list) as root + final TreeItem institutions = this.widgetFactory.treeItemLocalized( + sebAdmin, + ActivityDefinition.INSTITUTION.displayName); + injectActivitySelection( + institutions, + actionBuilder + .newAction(ActionDefinition.INSTITUTION_VIEW_LIST) + .create()); + + } else if (userInfo.hasRole(UserRole.INSTITUTIONAL_ADMIN)) { + // otherwise show the form of the institution for current user + final TreeItem institutions = this.widgetFactory.treeItemLocalized( + sebAdmin, + ActivityDefinition.INSTITUTION.displayName); + injectActivitySelection( + institutions, + actionBuilder.newAction(ActionDefinition.INSTITUTION_VIEW_FORM) + .withEntityKey(userInfo.institutionId, EntityType.INSTITUTION) + .withAttribute(AttributeKeys.READ_ONLY, "true") + .create()); + } + + // User Account + // if current user has role seb-server admin or institutional-admin, show list + if (isServerOrInstAdmin) { + + final TreeItem userAccounts = this.widgetFactory.treeItemLocalized( + sebAdmin, + ActivityDefinition.USER_ACCOUNT.displayName); + injectActivitySelection( + userAccounts, + actionBuilder + .newAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST) + .create()); + } else { + // otherwise show the user account form for current user + final TreeItem userAccounts = this.widgetFactory.treeItemLocalized( + navigation, + ActivityDefinition.USER_ACCOUNT.displayName); + injectActivitySelection( + userAccounts, + actionBuilder.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FORM) + .withEntityKey(this.currentUser.get().getEntityKey()) + .withAttribute(AttributeKeys.READ_ONLY, "true") + .create()); + } + + // User Activity Logs + final boolean viewUserActivityLogs = this.currentUser.hasInstitutionalPrivilege( + PrivilegeType.READ, + EntityType.USER_ACTIVITY_LOG); + if (viewUserActivityLogs) { + final TreeItem activityLogs = this.widgetFactory.treeItemLocalized( + sebAdmin, + ActivityDefinition.USER_ACTIVITY_LOGS.displayName); + injectActivitySelection( + activityLogs, + actionBuilder + .newAction(ActionDefinition.LOGS_USER_ACTIVITY_LIST) + .create()); + } + + if (sebAdmin.getItemCount() > 0) { + sebAdmin.setExpanded(this.currentUser.get().hasAnyRole( + UserRole.SEB_SERVER_ADMIN, + UserRole.INSTITUTIONAL_ADMIN)); + } else { + sebAdmin.dispose(); + } + + // ---- SEB ADMIN ---------------------------------------------------------------------- + //-------------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------------- + // ---- SEB CONFIGURATION -------------------------------------------------------------- + + // SEB Configurations + final boolean clientConfigRead = this.currentUser.hasInstitutionalPrivilege( + PrivilegeType.READ, + EntityType.SEB_CLIENT_CONFIGURATION); + final boolean examConfigRead = this.currentUser.hasInstitutionalPrivilege( + PrivilegeType.READ, + EntityType.CONFIGURATION_NODE); + + if ((clientConfigRead || examConfigRead) && !isSupporterOnly) { + final TreeItem sebConfigs = this.widgetFactory.treeItemLocalized( + navigation, + ActivityDefinition.SEB_CONFIGURATION.displayName); + + // SEB Client Config + if (clientConfigRead) { + final TreeItem clientConfig = this.widgetFactory.treeItemLocalized( + sebConfigs, + ActivityDefinition.SEB_CLIENT_CONFIG.displayName); + injectActivitySelection( + clientConfig, + actionBuilder + .newAction(ActionDefinition.SEB_CLIENT_CONFIG_LIST) + .create()); + } + + // SEB Exam Config + if (examConfigRead) { + final TreeItem examConfig = this.widgetFactory.treeItemLocalized( + sebConfigs, + ActivityDefinition.SEB_EXAM_CONFIG.displayName); + injectActivitySelection( + examConfig, + actionBuilder + .newAction(ActionDefinition.SEB_EXAM_CONFIG_LIST) + .create()); + } + + // SEB Exam Config Template + if (examConfigRead) { + final TreeItem examConfigTemplate = this.widgetFactory.treeItemLocalized( + sebConfigs, + ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE.displayName); + injectActivitySelection( + examConfigTemplate, + actionBuilder + .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_LIST) + .create()); + } + + sebConfigs.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)); + } + + // ---- SEB CONFIGURATION -------------------------------------------------------------- + //-------------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------------- + // ---- EXAM ADMINISTRATION ------------------------------------------------------------ + + final boolean lmsRead = this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.LMS_SETUP); + final boolean examRead = userInfo.hasAnyRole(UserRole.EXAM_SUPPORTER, UserRole.EXAM_ADMIN) || + this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.EXAM); + final boolean examWrite = this.currentUser.hasInstitutionalPrivilege(PrivilegeType.WRITE, EntityType.EXAM); + + // Exam Administration + final TreeItem examAdmin = this.widgetFactory.treeItemLocalized( + navigation, + ActivityDefinition.EXAM_ADMINISTRATION.displayName); + + if (examRead || lmsRead) { + // LMS Setup + if (lmsRead && !isSupporterOnly) { + final TreeItem lmsSetup = this.widgetFactory.treeItemLocalized( + examAdmin, + ActivityDefinition.LMS_SETUP.displayName); + injectActivitySelection( + lmsSetup, + actionBuilder + .newAction(ActionDefinition.LMS_SETUP_VIEW_LIST) + .create()); + } + + if (examRead) { + + if (examWrite) { + // Quiz Discovery + final TreeItem quizDiscovery = this.widgetFactory.treeItemLocalized( + examAdmin, + ActivityDefinition.QUIZ_DISCOVERY.displayName); + injectActivitySelection( + quizDiscovery, + actionBuilder + .newAction(ActionDefinition.QUIZ_DISCOVERY_VIEW_LIST) + .create()); + } + + // Exam + final TreeItem exam = this.widgetFactory.treeItemLocalized( + examAdmin, + ActivityDefinition.EXAM.displayName); + injectActivitySelection( + exam, + actionBuilder + .newAction(ActionDefinition.EXAM_VIEW_LIST) + .create()); + } + + examAdmin.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)); + } + + // ---- EXAM ADMINISTRATION ------------------------------------------------------------ + //-------------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------------- + // ---- MONITORING --------------------------------------------------------------------- + + final boolean isSupporter = this.currentUser.get().hasAnyRole(UserRole.EXAM_SUPPORTER); + final boolean viewSebClientLogs = this.currentUser.hasInstitutionalPrivilege( + PrivilegeType.READ, + EntityType.EXAM) || + this.currentUser.get().hasRole(UserRole.EXAM_SUPPORTER); + + if (isSupporter || viewSebClientLogs) { + // Monitoring + final TreeItem monitoring = this.widgetFactory.treeItemLocalized( + navigation, + ActivityDefinition.MONITORING.displayName); + + // Monitoring exams + if (isSupporter) { + final TreeItem clientConfig = this.widgetFactory.treeItemLocalized( + monitoring, + ActivityDefinition.MONITORING_EXAMS.displayName); + injectActivitySelection( + clientConfig, + actionBuilder + .newAction(ActionDefinition.RUNNING_EXAM_VIEW_LIST) + .create()); + } + + // SEB Client Logs + if (viewSebClientLogs) { + final TreeItem sebLogs = (isSupporter) + ? this.widgetFactory.treeItemLocalized( + monitoring, + ActivityDefinition.SEB_CLIENT_LOGS.displayName) + : this.widgetFactory.treeItemLocalized( + navigation, + ActivityDefinition.SEB_CLIENT_LOGS.displayName); + injectActivitySelection( + sebLogs, + actionBuilder + .newAction(ActionDefinition.LOGS_SEB_CLIENT) + .create()); + } + + if (monitoring.getItemCount() > 0) { + monitoring.setExpanded( + this.currentUser + .get() + .hasAnyRole(UserRole.EXAM_SUPPORTER)); + } else { + monitoring.dispose(); + } + } + + // ---- MONITORING --------------------------------------------------------------------- + //-------------------------------------------------------------------------------------- + + // register page listener and initialize navigation data + navigation.addListener(SWT.Selection, event -> handleSelection(pageContext, event)); + navigation.addListener(SWT.Expand, event -> { + final TreeItem item = (TreeItem) event.item; + selectCurrentItem(navigation, item); + }); + navigation.addListener(SWT.Collapse, event -> { + final Tree tree = (Tree) event.widget; + tree.setData(SKIP_EXPAND, true); + }); + navigation.addListener(SWT.MouseUp, event -> { + final Tree tree = (Tree) event.widget; + final TreeItem[] selection = tree.getSelection(); + if (ArrayUtils.isNotEmpty(selection)) { + final TreeItem item = selection[0]; + final boolean skipExpand = BooleanUtils.isTrue((Boolean) tree.getData(SKIP_EXPAND)); + if (item.getItemCount() > 0 && !item.getExpanded() && !skipExpand) { + item.setExpanded(true); + handleParentSelection(tree, item); + } + } + tree.setData(SKIP_EXPAND, false); + }); + navigation.setData( + PageEventListener.LISTENER_ATTRIBUTE_KEY, + new ActivitiesActionEventListener(navigation)); + + // page-selection on (re)load + final PageState state = this.pageService.getCurrentState(); + if (state == null) { + final TreeItem item = getDefaultSelectionFor(navigation, this.currentUser); + final TreeItem actionItem = getActionItem(item); + final PageAction activityAction = getActivitySelection(actionItem); + this.pageService.executePageAction(activityAction); + } else { + final TreeItem item = findItemByActionDefinition( + navigation.getItems(), + state.activityAnchor()); + if (item != null) { + final PageAction action = getActivitySelection(item); + this.pageService.executePageAction(action, result -> navigation.select(item)); + } + } + } + + private TreeItem getDefaultSelectionFor(final Tree navigation, final CurrentUser currentUser2) { + if (this.currentUser.get().hasAnyRole(UserRole.SEB_SERVER_ADMIN, UserRole.INSTITUTIONAL_ADMIN)) { + return navigation.getItem(0); + } else if (this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)) { + return findItemByActionDefinition( + navigation.getItems(), + ActivityDefinition.SEB_EXAM_CONFIG); + } else if (this.currentUser.get().hasAnyRole(UserRole.EXAM_SUPPORTER)) { + return findItemByActionDefinition( + navigation.getItems(), + ActivityDefinition.MONITORING_EXAMS); + } else { + return navigation.getItem(0); + } + } + + private void selectCurrentItem(final Tree navigation, final TreeItem item) { + final PageState currentState = this.pageService.getCurrentState(); + if (currentState == null) { + return; + } + final TreeItem currentItem = findItemByActionDefinition( + item.getItems(), + currentState.definition.activityAnchor()); + if (currentItem != null) { + navigation.select(currentItem); + } + } + + private void handleSelection(final PageContext composerCtx, final Event event) { + final Tree tree = (Tree) event.widget; + final TreeItem treeItem = (TreeItem) event.item; + + if (treeItem.getItemCount() > 0 && !treeItem.getExpanded()) { + return; + } + + final PageAction action = getActivitySelection(treeItem); + // if there is no form action associated with the treeItem and the treeItem has sub items, toggle the item state + if (action == null) { + handleParentSelection(tree, treeItem); + return; + } + + final PageState currentState = this.pageService.getCurrentState(); + if (currentState != null && currentState.definition == action.definition.targetState) { + return; + } + + this.pageService.executePageAction( + action, + resultAction -> { + if (resultAction.hasError()) { + tree.deselect(treeItem); + if (currentState != null) { + final TreeItem item = findItemByActionDefinition( + tree.getItems(), + currentState.activityAnchor()); + if (item != null) { + tree.select(item); + } + } + } + }); + } + + private void handleParentSelection(final Tree tree, final TreeItem treeItem) { + if (treeItem.getItemCount() > 0) { + final PageState currentState = this.pageService.getCurrentState(); + final TreeItem currentSelection = findItemByActionDefinition( + tree.getItems(), + currentState.activityAnchor()); + if (currentSelection != null) { + if (isInSubTree(treeItem, currentSelection)) { + tree.setSelection(currentSelection); + } else { + selectFirstChild(tree, treeItem); + } + } else { + tree.deselectAll(); + } + } + + tree.layout(); + } + + private void selectFirstChild(final Tree tree, final TreeItem treeItem) { + final TreeItem actionItem = ActivitiesPane.getActionItem(treeItem); + final PageAction activitySelection = getActivitySelection(actionItem); + this.pageService.executePageAction(activitySelection, result -> { + if (!result.hasError()) { + tree.setSelection(actionItem); + } + }); + } + + private static boolean isInSubTree(final TreeItem treeItem, final TreeItem currentSelection) { + if (treeItem == null) { + return false; + } + + final TreeItem[] items = treeItem.getItems(); + if (ArrayUtils.isEmpty(items)) { + return false; + } + + for (final TreeItem item : items) { + if (item.equals(currentSelection)) { + return true; + } + } + + return false; + } + + private static TreeItem findItemByActionDefinition( + final TreeItem[] items, + final Activity activity) { + + if (items == null) { + return null; + } + + for (final TreeItem item : items) { + final PageAction action = getActivitySelection(item); + if (action == null) { + if (item.getItemCount() > 0) { + final TreeItem found = findItemByActionDefinition(item.getItems(), activity); + if (found != null) { + return found; + } + } + continue; + } + + final Activity activityAnchor = action.definition.targetState.activityAnchor(); + if (activityAnchor.name().equals(activity.name())) { + return item; + } + + final TreeItem _item = findItemByActionDefinition(item.getItems(), activity); + if (_item != null) { + return _item; + } + } + + return null; + } + + private static TreeItem getActionItem(final TreeItem item) { + final PageAction action = (PageAction) item.getData(ATTR_ACTIVITY_SELECTION); + if (action == null && item.getItemCount() > 0) { + final TreeItem firstChild = item.getItem(0); + if (firstChild != null) { + return firstChild; + } + } + + return item; + } + + private static PageAction getActivitySelection(final TreeItem item) { + return (PageAction) item.getData(ATTR_ACTIVITY_SELECTION); + } + + private static void injectActivitySelection(final TreeItem item, final PageAction action) { + item.setData(ATTR_ACTIVITY_SELECTION, action); + } + + private static final class ActivitiesActionEventListener implements ActionEventListener { + private final Tree navigation; + + private ActivitiesActionEventListener(final Tree navigation) { + this.navigation = navigation; + } + + @Override + public void notify(final ActionEvent event) { + final TreeItem item = findItemByActionDefinition( + this.navigation.getItems(), + event.action.definition.targetState.activityAnchor()); + if (item != null) { + this.navigation.deselectAll(); + this.navigation.select(item); + } + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java index af5a0420..da54ed76 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java @@ -1,42 +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.activity; - -import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; -import ch.ethz.seb.sebserver.gui.service.page.Activity; - -public enum ActivityDefinition implements Activity { - SEB_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.serveradmin")), - INSTITUTION(new LocTextKey("sebserver.institution.action.list")), - USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")), - USER_ACTIVITY_LOGS(new LocTextKey("sebserver.logs.activity.userlogs")), - LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")), - QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")), - EXAM_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.examadmin")), - EXAM(new LocTextKey("sebserver.exam.action.list")), - SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")), - SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")), - SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")), - SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")), - MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")), - MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")), - SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs")); - - public final LocTextKey displayName; - - private ActivityDefinition(final LocTextKey displayName) { - this.displayName = displayName; - } - - @Override - public LocTextKey displayName() { - return this.displayName; - } - -} +/* + * 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.service.i18n.LocTextKey; +import ch.ethz.seb.sebserver.gui.service.page.Activity; + +public enum ActivityDefinition implements Activity { + SEB_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.serveradmin")), + INSTITUTION(new LocTextKey("sebserver.institution.action.list")), + USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")), + USER_ACTIVITY_LOGS(new LocTextKey("sebserver.logs.activity.userlogs")), + LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")), + QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")), + EXAM_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.examadmin")), + EXAM(new LocTextKey("sebserver.exam.action.list")), + SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")), + SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")), + SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")), + SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")), + MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")), + MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")), + SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs")); + + public final LocTextKey displayName; + + ActivityDefinition(final LocTextKey displayName) { + this.displayName = displayName; + } + + @Override + public LocTextKey displayName() { + return this.displayName; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java index c242cf22..eaf2ff84 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java @@ -94,7 +94,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition { public final Class actionPaneComposer; public final Activity activityAnchor; - private PageStateDefinitionImpl( + PageStateDefinitionImpl( final Type type, final Class contentPaneComposer, final Activity activityAnchor) { @@ -102,7 +102,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition { this(type, contentPaneComposer, ActionPane.class, activityAnchor); } - private PageStateDefinitionImpl( + PageStateDefinitionImpl( final Type type, final Class contentPaneComposer, final Class actionPaneComposer, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java index f0bf4fae..683da3a7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/ThresholdListBuilder.java @@ -44,7 +44,6 @@ public class ThresholdListBuilder extends FieldBuilder> { final Control titleLabel = createTitleLabel(builder.formParent, builder, this); if (builder.readonly || this.readonly) { // No read-only view needed for this so far? - return; } else { final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java index 93579253..01646ec3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java @@ -1,109 +1,109 @@ -/* - * 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.examconfig; - -import java.util.Collection; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; -import org.eclipse.swt.widgets.Composite; - -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; -import ch.ethz.seb.sebserver.gbl.util.Result; -import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; -import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; -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.impl.PageAction; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; - -public interface ExamConfigurationService { - - public static final String ATTRIBUTE_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.label."; - public static final String GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group."; - public static final String TOOL_TIP_SUFFIX = ".tooltip"; - public static final String TABLE_ROW_TITLE_SUFFIX = ".row.title"; - - WidgetFactory getWidgetFactory(); - - InputFieldBuilder getInputFieldBuilder( - ConfigurationAttribute attribute, - Orientation orientation); - - Result getAttributes(Long templateId); - - Result getAttributes( - final TemplateAttribute attribute, - final Orientation defaultOrientation); - - List getViews(AttributeMapping allAttributes); - - ViewContext createViewContext( - PageContext pageContext, - Configuration configuration, - View view, - AttributeMapping attributeMapping, - int rows, - boolean readonly); - - Composite createViewGrid( - Composite parent, - ViewContext viewContext); - - void initInputFieldValues( - Long configurationId, - Collection viewContexts); - - PageAction resetToDefaults(PageAction action); - - PageAction removeFromView(PageAction action); - - PageAction attachToDefaultView(final PageAction action); - - static String attributeNameKey(final ConfigurationAttribute attribute) { - if (attribute == null) { - return null; - } - - return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name; - } - - static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) { - if (attribute == null) { - return null; - } - - return new LocTextKey(attributeNameKey(attribute)); - } - - static LocTextKey getToolTipKey( - final ConfigurationAttribute attribute, - final I18nSupport i18nSupport) { - - final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX; - if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) { - return null; - } else { - return new LocTextKey(attributeNameKey); - } - } - - static LocTextKey getTablePopupTitleKey( - final ConfigurationAttribute attribute, - final I18nSupport i18nSupport) { - - return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX); - } - -} +/* + * 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.examconfig; + +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.swt.widgets.Composite; + +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; +import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; +import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; +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.impl.PageAction; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; + +public interface ExamConfigurationService { + + String ATTRIBUTE_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.label."; + String GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group."; + String TOOL_TIP_SUFFIX = ".tooltip"; + String TABLE_ROW_TITLE_SUFFIX = ".row.title"; + + WidgetFactory getWidgetFactory(); + + InputFieldBuilder getInputFieldBuilder( + ConfigurationAttribute attribute, + Orientation orientation); + + Result getAttributes(Long templateId); + + Result getAttributes( + final TemplateAttribute attribute, + final Orientation defaultOrientation); + + List getViews(AttributeMapping allAttributes); + + ViewContext createViewContext( + PageContext pageContext, + Configuration configuration, + View view, + AttributeMapping attributeMapping, + int rows, + boolean readonly); + + Composite createViewGrid( + Composite parent, + ViewContext viewContext); + + void initInputFieldValues( + Long configurationId, + Collection viewContexts); + + PageAction resetToDefaults(PageAction action); + + PageAction removeFromView(PageAction action); + + PageAction attachToDefaultView(final PageAction action); + + static String attributeNameKey(final ConfigurationAttribute attribute) { + if (attribute == null) { + return null; + } + + return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name; + } + + static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) { + if (attribute == null) { + return null; + } + + return new LocTextKey(attributeNameKey(attribute)); + } + + static LocTextKey getToolTipKey( + final ConfigurationAttribute attribute, + final I18nSupport i18nSupport) { + + final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX; + if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) { + return null; + } else { + return new LocTextKey(attributeNameKey); + } + } + + static LocTextKey getTablePopupTitleKey( + final ConfigurationAttribute attribute, + final I18nSupport i18nSupport) { + + return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractTableFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractTableFieldBuilder.java index 1383a786..cb7cb3e6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractTableFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractTableFieldBuilder.java @@ -1,338 +1,336 @@ -/* - * 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.examconfig.impl; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.BooleanUtils; -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.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ch.ethz.seb.sebserver.gbl.Constants; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; -import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; -import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; - -public abstract class AbstractTableFieldBuilder implements InputFieldBuilder { - - private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class); - - private static final int ROW_HEIGHT = 20; - private static final int NAV_HEIGHT = 40; - private static final int TABLE_WIDTH_SPACE = 50; - - protected final RestService restService; - protected final WidgetFactory widgetFactory; - protected InputFieldBuilderSupplier inputFieldBuilderSupplier; - - protected AbstractTableFieldBuilder( - final RestService restService, - final WidgetFactory widgetFactory) { - - this.restService = restService; - this.widgetFactory = widgetFactory; - } - - @Override - public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) { - this.inputFieldBuilderSupplier = inputFieldBuilderSupplier; - } - - protected Table createTable(final Composite parent, final TableContext tableContext) { - final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL); - table.setLayout(new GridLayout()); - final GridData gridData = new GridData( - SWT.FILL, SWT.FILL, - true, false, - tableContext.orientation.width(), - tableContext.orientation.height()); - - gridData.heightHint = tableContext.orientation.height() * ROW_HEIGHT + NAV_HEIGHT; - table.setLayoutData(gridData); - table.setHeaderVisible(true); - table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext)); - return table; - } - - protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) { - final TableContext tableContext = new TableContext( - this.inputFieldBuilderSupplier, - this.widgetFactory, - attribute, - viewContext); - return tableContext; - } - - protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) { - table.addListener(SWT.MouseDoubleClick, event -> { - final int selectionIndex = table.getSelectionIndex(); - if (selectionIndex >= 0) { - tableField.openForm(selectionIndex); - } - }); - } - - protected void adaptColumnWidth( - final Table table, - final TableContext tableContext) { - - try { - final boolean readonly = tableContext.getViewContext().readonly; - final int currentTableWidth = table.getClientArea().width - TABLE_WIDTH_SPACE; - final TableColumn[] columns = table.getColumns(); - final List orientations = tableContext - .getColumnAttributes() - .stream() - .map(attr -> tableContext.getOrientation(attr.id)) - .collect(Collectors.toList()); - final Integer div = orientations - .stream() - .map(o -> o.width) - .reduce(0, (acc, val) -> acc + val); - final int widthUnit = currentTableWidth / div; - for (int i = 0; i < columns.length - ((readonly) ? 0 : 2); i++) { - columns[i].setWidth(widthUnit * orientations.get(i).width); - } - } catch (final Exception e) { - log.warn("Failed to adaptColumnWidth: ", e); - } - } - - protected static void setValueToCell( - final TableContext tableContext, - final TableItem item, - final int cellIndex, - final ConfigurationAttribute attribute, - final TableValue tableValue) { - - switch (attribute.type) { - case CHECKBOX: { - item.setImage( - cellIndex, - (BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null)) - ? ImageIcon.YES.getImage(item.getDisplay()) - : ImageIcon.NO.getImage(item.getDisplay())); - break; - } - case SINGLE_SELECTION: { - final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + - attribute.getName() + "." + - tableValue.value; - item.setText( - cellIndex, - tableContext.i18nSupport().getText(key, getValue(attribute, tableValue))); - break; - } - default: { - item.setText(cellIndex, getValue(attribute, tableValue)); - break; - } - } - } - - private static String getValue( - final ConfigurationAttribute attribute, - final TableValue tableValue) { - - if (tableValue == null) { - if (StringUtils.isBlank(attribute.defaultValue)) { - return Constants.EMPTY_NOTE; - } else { - return attribute.defaultValue; - } - } else { - if (StringUtils.isBlank(tableValue.value)) { - return Constants.EMPTY_NOTE; - } else { - return tableValue.value; - } - } - } - - static abstract class AbstractTableInputField extends AbstractInputField { - - protected final TableContext tableContext; - - protected AbstractTableInputField( - final ConfigurationAttribute attribute, - final Orientation orientation, - final Table control, - final Label errorLabel, - final TableContext tableContext) { - - super(attribute, orientation, control, errorLabel); - this.tableContext = tableContext; - } - - @Override - public ConfigurationValue initValue(final Collection values) { - clearTable(); - // get all child values as TableValues - final List tableValues = getChildValues( - this.tableContext, - this.attribute, - values); - - initValue(tableValues); - return null; - } - - abstract void initValue(final List tableValues); - - abstract void openForm(final int selectionIndex); - - abstract void applyTableRowValues(final int index); - - protected List getChildValues( - final TableContext tableContext, - final ConfigurationAttribute attribute, - final Collection values) { - - return values.stream() - .filter(v -> isChildValue(tableContext, attribute, v)) - .map(TableValue::of) - .collect(Collectors.toList()); - } - - protected boolean isChildValue( - final TableContext tableContext, - final ConfigurationAttribute attribute, - final ConfigurationValue value) { - - if (!tableContext.getViewContext().attributeMapping.attributeIdMapping - .containsKey(value.attributeId)) { - - return false; - } - - ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId); - if (attr == null) { - return false; - } - while (attr.parentId != null) { - if (attribute.id.equals(attr.parentId)) { - return true; - } - attr = tableContext.getAttribute(attr.parentId); - } - - return false; - } - - protected Map> createRowIndexMap(final List tableValues) { - final Map> indexMapping = new HashMap<>(); - for (final TableValue tableValue : tableValues) { - final Map rowValues = indexMapping.computeIfAbsent( - tableValue.listIndex, - key -> new HashMap<>()); - rowValues.put(tableValue.attributeId, tableValue); - } - return indexMapping; - } - - protected void valuesFromIndexMap( - final List> values, - final Map> indexMapping) { - - values.clear(); - final List rows = new ArrayList<>(indexMapping.keySet()); - rows.sort((i1, i2) -> i1.compareTo(i2)); - rows - .stream() - .forEach(i -> { - final Map rowValues = indexMapping.get(i); - values.add(rowValues); - }); - } - - protected void applyFormValues( - final List> values, - final Map rowValues, - final int index) { - - if (!values.isEmpty()) { - values.remove(index); - values.add(index, rowValues); - applyTableRowValues(index); - } - - // send values to web-service - this.tableContext.getValueChangeListener() - .tableChanged(extractTableValue(values)); - } - - protected ConfigurationTableValues extractTableValue(final List> values) { - final List collect = values - .stream() - .flatMap(map -> map.values().stream()) - .collect(Collectors.toList()); - - return new ConfigurationTableValues( - this.tableContext.getInstitutionId(), - this.tableContext.getConfigurationId(), - this.attribute.id, - collect); - } - - @Override - public void setDefaultValue() { - // NOTE this just empty the list for now - // TODO do we need default values for lists? - clearTable(); - final List values = new ArrayList<>(); - this.tableContext.getValueChangeListener().tableChanged( - new ConfigurationTableValues( - this.tableContext.getInstitutionId(), - this.tableContext.getConfigurationId(), - this.attribute.id, - values)); - } - - void clearTable() { - this.control.setSelection(-1); - if (this.control.getItemCount() > 0) { - for (final TableItem item : this.control.getItems()) { - item.dispose(); - } - } - } - - @Override - protected void setValueToControl(final String value) { - throw new UnsupportedOperationException(); - } - - @Override - public String getValue() { - throw new UnsupportedOperationException(); - } - } - -} +/* + * 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.examconfig.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.BooleanUtils; +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.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; +import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; + +public abstract class AbstractTableFieldBuilder implements InputFieldBuilder { + + private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class); + + private static final int ROW_HEIGHT = 20; + private static final int NAV_HEIGHT = 40; + private static final int TABLE_WIDTH_SPACE = 50; + + protected final RestService restService; + protected final WidgetFactory widgetFactory; + protected InputFieldBuilderSupplier inputFieldBuilderSupplier; + + protected AbstractTableFieldBuilder( + final RestService restService, + final WidgetFactory widgetFactory) { + + this.restService = restService; + this.widgetFactory = widgetFactory; + } + + @Override + public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) { + this.inputFieldBuilderSupplier = inputFieldBuilderSupplier; + } + + protected Table createTable(final Composite parent, final TableContext tableContext) { + final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL); + table.setLayout(new GridLayout()); + final GridData gridData = new GridData( + SWT.FILL, SWT.FILL, + true, false, + tableContext.orientation.width(), + tableContext.orientation.height()); + + gridData.heightHint = tableContext.orientation.height() * ROW_HEIGHT + NAV_HEIGHT; + table.setLayoutData(gridData); + table.setHeaderVisible(true); + table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext)); + return table; + } + + protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) { + return new TableContext( + this.inputFieldBuilderSupplier, + this.widgetFactory, + attribute, + viewContext); + } + + protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) { + table.addListener(SWT.MouseDoubleClick, event -> { + final int selectionIndex = table.getSelectionIndex(); + if (selectionIndex >= 0) { + tableField.openForm(selectionIndex); + } + }); + } + + protected void adaptColumnWidth( + final Table table, + final TableContext tableContext) { + + try { + final boolean readonly = tableContext.getViewContext().readonly; + final int currentTableWidth = table.getClientArea().width - TABLE_WIDTH_SPACE; + final TableColumn[] columns = table.getColumns(); + final List orientations = tableContext + .getColumnAttributes() + .stream() + .map(attr -> tableContext.getOrientation(attr.id)) + .collect(Collectors.toList()); + final Integer div = orientations + .stream() + .map(o -> o.width) + .reduce(0, Integer::sum); + final int widthUnit = currentTableWidth / div; + for (int i = 0; i < columns.length - ((readonly) ? 0 : 2); i++) { + columns[i].setWidth(widthUnit * orientations.get(i).width); + } + } catch (final Exception e) { + log.warn("Failed to adaptColumnWidth: ", e); + } + } + + protected static void setValueToCell( + final TableContext tableContext, + final TableItem item, + final int cellIndex, + final ConfigurationAttribute attribute, + final TableValue tableValue) { + + switch (attribute.type) { + case CHECKBOX: { + item.setImage( + cellIndex, + (BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null)) + ? ImageIcon.YES.getImage(item.getDisplay()) + : ImageIcon.NO.getImage(item.getDisplay())); + break; + } + case SINGLE_SELECTION: { + final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + + attribute.getName() + "." + + tableValue.value; + item.setText( + cellIndex, + tableContext.i18nSupport().getText(key, getValue(attribute, tableValue))); + break; + } + default: { + item.setText(cellIndex, getValue(attribute, tableValue)); + break; + } + } + } + + private static String getValue( + final ConfigurationAttribute attribute, + final TableValue tableValue) { + + if (tableValue == null) { + if (StringUtils.isBlank(attribute.defaultValue)) { + return Constants.EMPTY_NOTE; + } else { + return attribute.defaultValue; + } + } else { + if (StringUtils.isBlank(tableValue.value)) { + return Constants.EMPTY_NOTE; + } else { + return tableValue.value; + } + } + } + + static abstract class AbstractTableInputField extends AbstractInputField
{ + + protected final TableContext tableContext; + + protected AbstractTableInputField( + final ConfigurationAttribute attribute, + final Orientation orientation, + final Table control, + final Label errorLabel, + final TableContext tableContext) { + + super(attribute, orientation, control, errorLabel); + this.tableContext = tableContext; + } + + @Override + public ConfigurationValue initValue(final Collection values) { + clearTable(); + // get all child values as TableValues + final List tableValues = getChildValues( + this.tableContext, + this.attribute, + values); + + initValue(tableValues); + return null; + } + + abstract void initValue(final List tableValues); + + abstract void openForm(final int selectionIndex); + + abstract void applyTableRowValues(final int index); + + protected List getChildValues( + final TableContext tableContext, + final ConfigurationAttribute attribute, + final Collection values) { + + return values.stream() + .filter(v -> isChildValue(tableContext, attribute, v)) + .map(TableValue::of) + .collect(Collectors.toList()); + } + + protected boolean isChildValue( + final TableContext tableContext, + final ConfigurationAttribute attribute, + final ConfigurationValue value) { + + if (!tableContext.getViewContext().attributeMapping.attributeIdMapping + .containsKey(value.attributeId)) { + + return false; + } + + ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId); + if (attr == null) { + return false; + } + while (attr.parentId != null) { + if (attribute.id.equals(attr.parentId)) { + return true; + } + attr = tableContext.getAttribute(attr.parentId); + } + + return false; + } + + protected Map> createRowIndexMap(final List tableValues) { + final Map> indexMapping = new HashMap<>(); + for (final TableValue tableValue : tableValues) { + final Map rowValues = indexMapping.computeIfAbsent( + tableValue.listIndex, + key -> new HashMap<>()); + rowValues.put(tableValue.attributeId, tableValue); + } + return indexMapping; + } + + protected void valuesFromIndexMap( + final List> values, + final Map> indexMapping) { + + values.clear(); + final List rows = new ArrayList<>(indexMapping.keySet()); + rows.sort(Integer::compareTo); + rows + .forEach(i -> { + final Map rowValues = indexMapping.get(i); + values.add(rowValues); + }); + } + + protected void applyFormValues( + final List> values, + final Map rowValues, + final int index) { + + if (!values.isEmpty()) { + values.remove(index); + values.add(index, rowValues); + applyTableRowValues(index); + } + + // send values to web-service + this.tableContext.getValueChangeListener() + .tableChanged(extractTableValue(values)); + } + + protected ConfigurationTableValues extractTableValue(final List> values) { + final List collect = values + .stream() + .flatMap(map -> map.values().stream()) + .collect(Collectors.toList()); + + return new ConfigurationTableValues( + this.tableContext.getInstitutionId(), + this.tableContext.getConfigurationId(), + this.attribute.id, + collect); + } + + @Override + public void setDefaultValue() { + // NOTE this just empty the list for now + // TODO do we need default values for lists? + clearTable(); + final List values = new ArrayList<>(); + this.tableContext.getValueChangeListener().tableChanged( + new ConfigurationTableValues( + this.tableContext.getInstitutionId(), + this.tableContext.getConfigurationId(), + this.attribute.id, + values)); + } + + void clearTable() { + this.control.setSelection(-1); + if (this.control.getItemCount() > 0) { + for (final TableItem item : this.control.getItems()) { + item.dispose(); + } + } + } + + @Override + protected void setValueToControl(final String value) { + throw new UnsupportedOperationException(); + } + + @Override + public String getValue() { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java index 5ff3cbcd..1d23c220 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java @@ -1,225 +1,225 @@ -/* - * 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.examconfig.impl; - -import java.util.Collection; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; - -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; -import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; -import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; -import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; -import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; - -interface CellFieldBuilderAdapter { - - static CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() { - @Override - public void createCell(final ViewGridBuilder builder) { - } - - @Override - public String toString() { - return "[DUMMY]"; - } - }; - - void createCell(ViewGridBuilder builder); - - default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { - } - - static CellFieldBuilderAdapter fieldBuilderAdapter( - final InputFieldBuilder inputFieldBuilder, - final ConfigurationAttribute attribute) { - - return new CellFieldBuilderAdapter() { - @Override - public void createCell(final ViewGridBuilder builder) { - - final InputField inputField = inputFieldBuilder.createInputField( - builder.parent, - attribute, - builder.viewContext); - - if (inputField != null) { - builder.viewContext.registerInputField(inputField); - } - } - - @Override - public String toString() { - return "[FIELD]"; - } - }; - } - - static CellFieldBuilderAdapter labelBuilder( - final ConfigurationAttribute attribute, - final Orientation orientation) { - - return new CellFieldBuilderAdapter() { - - private int span = 1; - - @Override - public void createCell(final ViewGridBuilder builder) { - - final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); - final Label label = widgetFactory.labelLocalized( - builder.parent, - new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name, - attribute.name)); - - final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); - switch (orientation.title) { - case LEFT: - case RIGHT: { - label.setAlignment(SWT.LEFT); - gridData.verticalIndent = 5; - break; - } - case RIGHT_SPAN: - case LEFT_SPAN: { - label.setAlignment(SWT.LEFT); - gridData.horizontalSpan = (span > 1) ? span : orientation.width; - gridData.verticalIndent = 5; - break; - } - case TOP: { - gridData.horizontalSpan = orientation.width; - gridData.verticalAlignment = SWT.BOTTOM; - break; - } - - default: { - label.setAlignment(SWT.LEFT); - break; - } - } - label.setLayoutData(gridData); - label.pack(); - } - - @Override - public void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { - if (grid[y][x] != this) { - return; - } - if (orientation.title == TitleOrientation.LEFT_SPAN) { - int xpos = x - 1; - while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) { - grid[y][xpos] = this; - grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER; - this.span++; - xpos--; - } - } - } - - @Override - public String toString() { - return "[LABEL]"; - } - }; - } - - static CellFieldBuilderAdapter passwordConfirmLabel( - final ConfigurationAttribute attribute, - final Orientation orientation) { - - return new CellFieldBuilderAdapter() { - @Override - public void createCell(final ViewGridBuilder builder) { - final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); - final Label label = widgetFactory.labelLocalized( - builder.parent, - new LocTextKey( - ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name - + ".confirm")); - final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); - label.setAlignment(SWT.LEFT); - gridData.verticalIndent = 20; - label.setLayoutData(gridData); - } - - @Override - public String toString() { - return "[PASSWORD CONFIRM LABEL]"; - } - }; - } - - static class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter { - - final Collection orientationsOfGroup; - - int x = 100; - int y = 100; - int width = 1; - int height = 1; - - GroupCellFieldBuilderAdapter(final Collection orientationsOfGroup) { - this.orientationsOfGroup = orientationsOfGroup; - - for (final Orientation o : this.orientationsOfGroup) { - final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0); - this.x = (xpos < this.x) ? xpos : this.x; - final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0); - this.y = (ypos < this.y) ? ypos : this.y; - this.width = (this.width < o.xpos() + o.width()) ? o.xpos() + o.width() : this.width; - this.height = (this.height < o.ypos() + o.height()) ? o.ypos() + o.height() : this.height; - } - - this.width = this.width - this.x; - this.height = this.height - this.y + 1; - } - - @Override - public void createCell(final ViewGridBuilder builder) { - final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); - final Orientation o = this.orientationsOfGroup.stream().findFirst().get(); - final LocTextKey groupLabelKey = new LocTextKey( - ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + - o.groupId, - o.groupId); - final LocTextKey groupTooltipKey = new LocTextKey( - ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + - o.groupId + - ExamConfigurationService.TOOL_TIP_SUFFIX, - o.groupId); - - final Group group = widgetFactory.groupLocalized( - builder.parent, - this.width, - groupLabelKey, - groupTooltipKey); - group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height)); - - final ViewGridBuilder groupBuilder = new ViewGridBuilder( - group, - builder.viewContext, - this, - builder.examConfigurationService); - - for (final Orientation orientation : this.orientationsOfGroup) { - final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId); - groupBuilder.add(attribute); - } - groupBuilder.compose(); - } - } +/* + * 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.examconfig.impl; + +import java.util.Collection; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; + +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; +import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; +import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; +import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; + +interface CellFieldBuilderAdapter { + + CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + } + + @Override + public String toString() { + return "[DUMMY]"; + } + }; + + void createCell(ViewGridBuilder builder); + + default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { + } + + static CellFieldBuilderAdapter fieldBuilderAdapter( + final InputFieldBuilder inputFieldBuilder, + final ConfigurationAttribute attribute) { + + return new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + + final InputField inputField = inputFieldBuilder.createInputField( + builder.parent, + attribute, + builder.viewContext); + + if (inputField != null) { + builder.viewContext.registerInputField(inputField); + } + } + + @Override + public String toString() { + return "[FIELD]"; + } + }; + } + + static CellFieldBuilderAdapter labelBuilder( + final ConfigurationAttribute attribute, + final Orientation orientation) { + + return new CellFieldBuilderAdapter() { + + private int span = 1; + + @Override + public void createCell(final ViewGridBuilder builder) { + + final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); + final Label label = widgetFactory.labelLocalized( + builder.parent, + new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name, + attribute.name)); + + final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); + switch (orientation.title) { + case LEFT: + case RIGHT: { + label.setAlignment(SWT.LEFT); + gridData.verticalIndent = 5; + break; + } + case RIGHT_SPAN: + case LEFT_SPAN: { + label.setAlignment(SWT.LEFT); + gridData.horizontalSpan = (span > 1) ? span : orientation.width; + gridData.verticalIndent = 5; + break; + } + case TOP: { + gridData.horizontalSpan = orientation.width; + gridData.verticalAlignment = SWT.BOTTOM; + break; + } + + default: { + label.setAlignment(SWT.LEFT); + break; + } + } + label.setLayoutData(gridData); + label.pack(); + } + + @Override + public void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { + if (grid[y][x] != this) { + return; + } + if (orientation.title == TitleOrientation.LEFT_SPAN) { + int xpos = x - 1; + while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) { + grid[y][xpos] = this; + grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER; + this.span++; + xpos--; + } + } + } + + @Override + public String toString() { + return "[LABEL]"; + } + }; + } + + static CellFieldBuilderAdapter passwordConfirmLabel( + final ConfigurationAttribute attribute, + final Orientation orientation) { + + return new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); + final Label label = widgetFactory.labelLocalized( + builder.parent, + new LocTextKey( + ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + + ".confirm")); + final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); + label.setAlignment(SWT.LEFT); + gridData.verticalIndent = 20; + label.setLayoutData(gridData); + } + + @Override + public String toString() { + return "[PASSWORD CONFIRM LABEL]"; + } + }; + } + + class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter { + + final Collection orientationsOfGroup; + + int x = 100; + int y = 100; + int width = 1; + int height = 1; + + GroupCellFieldBuilderAdapter(final Collection orientationsOfGroup) { + this.orientationsOfGroup = orientationsOfGroup; + + for (final Orientation o : this.orientationsOfGroup) { + final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0); + this.x = Math.min(xpos, this.x); + final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0); + this.y = Math.min(ypos, this.y); + this.width = Math.max(this.width, o.xpos() + o.width()); + this.height = Math.max(this.height, o.ypos() + o.height()); + } + + this.width = this.width - this.x; + this.height = this.height - this.y + 1; + } + + @Override + public void createCell(final ViewGridBuilder builder) { + final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); + final Orientation o = this.orientationsOfGroup.stream().findFirst().orElse(null); + final LocTextKey groupLabelKey = new LocTextKey( + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + + o.groupId, + o.groupId); + final LocTextKey groupTooltipKey = new LocTextKey( + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + + o.groupId + + ExamConfigurationService.TOOL_TIP_SUFFIX, + o.groupId); + + final Group group = widgetFactory.groupLocalized( + builder.parent, + this.width, + groupLabelKey, + groupTooltipKey); + group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height)); + + final ViewGridBuilder groupBuilder = new ViewGridBuilder( + group, + builder.viewContext, + this, + builder.examConfigurationService); + + for (final Orientation orientation : this.orientationsOfGroup) { + final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId); + groupBuilder.add(attribute); + } + groupBuilder.compose(); + } + } } \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java index 2107cda8..aa50dce3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java @@ -1,134 +1,134 @@ -/* - * 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.examconfig.impl; - -import java.util.Objects; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -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.sebconfig.AttributeType; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; -import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; -import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; -import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; -import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; -import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; -import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; - -@Lazy -@Component -@GuiProfile -public class CheckBoxBuilder implements InputFieldBuilder { - - private final WidgetFactory widgetFactory; - - protected CheckBoxBuilder(final WidgetFactory widgetFactory) { - this.widgetFactory = widgetFactory; - } - - @Override - public boolean builderFor( - final ConfigurationAttribute attribute, - final Orientation orientation) { - - if (attribute == null) { - return false; - } - - return attribute.type == AttributeType.CHECKBOX; - } - - @Override - public InputField createInputField( - final Composite parent, - final ConfigurationAttribute attribute, - final ViewContext viewContext) { - - Objects.requireNonNull(parent); - Objects.requireNonNull(attribute); - Objects.requireNonNull(viewContext); - - final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); - final Orientation orientation = viewContext - .getOrientation(attribute.id); - final Composite innerGrid = InputFieldBuilder - .createInnerGrid(parent, attribute, orientation); - - final Button checkbox = this.widgetFactory.buttonLocalized( - innerGrid, - SWT.CHECK, - (orientation.title == TitleOrientation.NONE) - ? ExamConfigurationService.attributeNameLocKey(attribute) - : null, - ExamConfigurationService.getToolTipKey(attribute, i18nSupport)); - - final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); - gridData.verticalIndent = 0; - checkbox.setLayoutData(gridData); - - final CheckboxField checkboxField = new CheckboxField( - attribute, - viewContext.getOrientation(attribute.id), - checkbox); - - if (viewContext.readonly) { - checkbox.setEnabled(false); - } else { - checkbox.addListener( - SWT.Selection, - event -> viewContext.getValueChangeListener().valueChanged( - viewContext, - attribute, - checkboxField.getValue(), - checkboxField.listIndex)); - } - - return checkboxField; - } - - static final class CheckboxField extends AbstractInputField