code cleanup

This commit is contained in:
anhefti 2020-03-05 16:05:56 +01:00
parent df884bd8d2
commit 884f9c78e0
40 changed files with 4320 additions and 4290 deletions

View file

@ -101,15 +101,15 @@ public class ExamForm implements TemplateComposer {
new LocTextKey("sebserver.exam.form.status"); new LocTextKey("sebserver.exam.form.status");
private static final LocTextKey FORM_TYPE_TEXT_KEY = private static final LocTextKey FORM_TYPE_TEXT_KEY =
new LocTextKey("sebserver.exam.form.type"); 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"); 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"); new LocTextKey("sebserver.exam.form.starttime");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY = private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.exam.form.description"); new LocTextKey("sebserver.exam.form.description");
private static final LocTextKey FORM_NAME_TEXT_KEY = private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.exam.form.name"); 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"); new LocTextKey("sebserver.exam.form.quizid");
private static final LocTextKey FORM_QUIZ_URL_TEXT_KEY = private static final LocTextKey FORM_QUIZ_URL_TEXT_KEY =
new LocTextKey("sebserver.exam.form.quizurl"); new LocTextKey("sebserver.exam.form.quizurl");
@ -285,14 +285,14 @@ public class ExamForm implements TemplateComposer {
.addField(FormBuilder.text( .addField(FormBuilder.text(
QuizData.QUIZ_ATTR_START_TIME, QuizData.QUIZ_ATTR_START_TIME,
FORM_STARTTIME_TEXT_KEY, FORM_START_TIME_TEXT_KEY,
i18nSupport.formatDisplayDateWithTimeZone(exam.startTime)) i18nSupport.formatDisplayDateWithTimeZone(exam.startTime))
.readonly(true) .readonly(true)
.withInputSpan(3) .withInputSpan(3)
.withEmptyCellSeparation(false)) .withEmptyCellSeparation(false))
.addField(FormBuilder.text( .addField(FormBuilder.text(
QuizData.QUIZ_ATTR_END_TIME, QuizData.QUIZ_ATTR_END_TIME,
FORM_ENDTIME_TEXT_KEY, FORM_END_TIME_TEXT_KEY,
i18nSupport.formatDisplayDateWithTimeZone(exam.endTime)) i18nSupport.formatDisplayDateWithTimeZone(exam.endTime))
.readonly(true) .readonly(true)
.withInputSpan(3) .withInputSpan(3)
@ -300,7 +300,7 @@ public class ExamForm implements TemplateComposer {
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.EXAM.ATTR_EXTERNAL_ID, Domain.EXAM.ATTR_EXTERNAL_ID,
FORM_QUIZID_TEXT_KEY, FORM_QUIZ_ID_TEXT_KEY,
exam.externalId) exam.externalId)
.readonly(true) .readonly(true)
.withEmptyCellSeparation(false)) .withEmptyCellSeparation(false))

View file

@ -62,11 +62,11 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@GuiProfile @GuiProfile
public class ExamList implements TemplateComposer { 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"; "sebserver.exam.list.column.starttime";
static final LocTextKey PAGE_TITLE_KEY = static final LocTextKey PAGE_TITLE_KEY =
new LocTextKey("sebserver.exam.list.title"); 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"); new LocTextKey("sebserver.exam.list.action.no.modify.privilege");
final static LocTextKey EMPTY_SELECTION_TEXT_KEY = final static LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.exam.info.pleaseSelect"); new LocTextKey("sebserver.exam.info.pleaseSelect");
@ -175,7 +175,7 @@ public class ExamList implements TemplateComposer {
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_START_TIME, QuizData.QUIZ_ATTR_START_TIME,
new LocTextKey( new LocTextKey(
EXAM_LIST_COLUMN_STARTTIME, EXAM_LIST_COLUMN_START_TIME,
i18nSupport.getUsersTimeZoneTitleSuffix()), i18nSupport.getUsersTimeZoneTitleSuffix()),
Exam::getStartTime) Exam::getStartTime)
.withFilter(new TableFilterAttribute( .withFilter(new TableFilterAttribute(
@ -213,7 +213,7 @@ public class ExamList implements TemplateComposer {
.newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST)
.withSelect( .withSelect(
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
action -> modifyExam(action, table), action -> modifyExam(action, table),
EMPTY_SELECTION_TEXT_KEY) EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> userGrant.im() && table.hasAnyContent(), false); .publishIf(() -> userGrant.im() && table.hasAnyContent(), false);

View file

@ -46,7 +46,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class LmsSetupList implements TemplateComposer { 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"); new LocTextKey("sebserver.lmssetup.list.action.no.modify.privilege");
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.lmssetup.info.pleaseSelect"); new LocTextKey("sebserver.lmssetup.info.pleaseSelect");
@ -173,7 +173,7 @@ public class LmsSetupList implements TemplateComposer {
.newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST) .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST)
.withSelect( .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) PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> userGrant.im() && table.hasAnyContent(), false) .publishIf(() -> userGrant.im() && table.hasAnyContent(), false)

View file

@ -1,201 +1,196 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Text;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; 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.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; 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.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultRegisterPage; 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.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext; 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.Message;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class LoginPage implements TemplateComposer { public class LoginPage implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(LoginPage.class); private static final Logger log = LoggerFactory.getLogger(LoginPage.class);
private final PageService pageService; private final PageService pageService;
private final AuthorizationContextHolder authorizationContextHolder; private final AuthorizationContextHolder authorizationContextHolder;
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
private final DefaultRegisterPage defaultRegisterPage; private final DefaultRegisterPage defaultRegisterPage;
private final boolean registreringEnabled; private final boolean registeringEnabled;
public LoginPage( public LoginPage(
final PageService pageService, final PageService pageService,
final DefaultRegisterPage defaultRegisterPage, final DefaultRegisterPage defaultRegisterPage,
@Value("${sebserver.gui.self-registering:false}") final Boolean registreringEnabled) { @Value("${sebserver.gui.self-registering:false}") final Boolean registeringEnabled) {
this.pageService = pageService; this.pageService = pageService;
this.authorizationContextHolder = pageService.getAuthorizationContextHolder(); this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
this.i18nSupport = pageService.getI18nSupport(); this.i18nSupport = pageService.getI18nSupport();
this.defaultRegisterPage = defaultRegisterPage; this.defaultRegisterPage = defaultRegisterPage;
this.registreringEnabled = BooleanUtils.toBoolean(registreringEnabled); this.registeringEnabled = BooleanUtils.toBoolean(registeringEnabled);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final Composite parent = pageContext.getParent(); final Composite parent = pageContext.getParent();
WidgetFactory.setTestId(parent, "login-page"); WidgetFactory.setTestId(parent, "login-page");
WidgetFactory.setARIARole(parent, "composite"); WidgetFactory.setARIARole(parent, "composite");
final Composite loginGroup = new Composite(parent, SWT.NONE); final Composite loginGroup = new Composite(parent, SWT.NONE);
final GridLayout rowLayout = new GridLayout(); final GridLayout rowLayout = new GridLayout();
rowLayout.marginWidth = 20; rowLayout.marginWidth = 20;
rowLayout.marginRight = 100; rowLayout.marginRight = 100;
loginGroup.setLayout(rowLayout); loginGroup.setLayout(rowLayout);
loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key); loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key);
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username"); final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
name.setLayoutData(new GridData(300, -1)); name.setLayoutData(new GridData(300, -1));
name.setAlignment(SWT.BOTTOM); name.setAlignment(SWT.BOTTOM);
final Text loginName = this.widgetFactory.textInput(loginGroup); final Text loginName = this.widgetFactory.textInput(loginGroup);
loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
gridData.verticalIndent = 10; gridData.verticalIndent = 10;
final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd"); final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd");
pwd.setLayoutData(gridData); pwd.setLayoutData(gridData);
final Text loginPassword = this.widgetFactory.passwordInput(loginGroup); final Text loginPassword = this.widgetFactory.passwordInput(loginGroup);
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder
.getAuthorizationContext(RWT.getUISession().getHttpSession()); .getAuthorizationContext(RWT.getUISession().getHttpSession());
final Composite buttons = new Composite(loginGroup, SWT.NONE); final Composite buttons = new Composite(loginGroup, SWT.NONE);
buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
buttons.setLayout(new GridLayout(2, false)); buttons.setLayout(new GridLayout(2, false));
buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key); buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key);
final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login"); final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login");
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
gridData.verticalIndent = 10; gridData.verticalIndent = 10;
loginButton.setLayoutData(gridData); loginButton.setLayoutData(gridData);
loginButton.addListener(SWT.Selection, event -> { loginButton.addListener(SWT.Selection, event -> login(
login( pageContext,
pageContext, loginName.getText(),
loginName.getText(), loginPassword.getText(),
loginPassword.getText(), authorizationContext));
authorizationContext); loginName.addListener(SWT.KeyDown, event -> {
}); if (event.character == '\n' || event.character == '\r') {
loginName.addListener(SWT.KeyDown, event -> { if (StringUtils.isNotBlank(loginPassword.getText())) {
if (event.character == '\n' || event.character == '\r') { login(
if (StringUtils.isNotBlank(loginPassword.getText())) { pageContext,
login( loginName.getText(),
pageContext, loginPassword.getText(),
loginName.getText(), authorizationContext);
loginPassword.getText(), } else {
authorizationContext); loginPassword.setFocus();
} else { }
loginPassword.setFocus(); }
} });
} loginPassword.addListener(SWT.KeyDown, event -> {
}); if (event.character == '\n' || event.character == '\r') {
loginPassword.addListener(SWT.KeyDown, event -> { if (StringUtils.isNotBlank(loginName.getText())) {
if (event.character == '\n' || event.character == '\r') { login(
if (StringUtils.isNotBlank(loginName.getText())) { pageContext,
login( loginName.getText(),
pageContext, loginPassword.getText(),
loginName.getText(), authorizationContext);
loginPassword.getText(), } else {
authorizationContext); loginName.setFocus();
} else { }
loginName.setFocus(); }
} });
}
}); if (this.registeringEnabled) {
final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register");
if (this.registreringEnabled) { gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register"); gridData.verticalIndent = 10;
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); registerButton.setLayoutData(gridData);
gridData.verticalIndent = 10; registerButton.addListener(SWT.Selection, event -> pageContext.forwardToPage(this.defaultRegisterPage));
registerButton.setLayoutData(gridData); }
registerButton.addListener(SWT.Selection, event -> { }
pageContext.forwardToPage(this.defaultRegisterPage);
}); private void login(
} final PageContext pageContext,
} final String loginName,
final CharSequence loginPassword,
private void login( final SEBServerAuthorizationContext authorizationContext) {
final PageContext pageContext,
final String loginName, try {
final CharSequence loginPassword,
final SEBServerAuthorizationContext authorizationContext) { final boolean loggedIn = authorizationContext.login(
loginName,
final String username = loginName; loginPassword);
try {
if (loggedIn) {
final boolean loggedIn = authorizationContext.login( // Set users locale on page after successful login
username, try {
loginPassword); RWT.getUISession()
.getHttpSession()
if (loggedIn) { .setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, authorizationContext
// Set users locale on page after successful login .getLoggedInUser()
try { .getOrThrow().language);
RWT.getUISession()
.getHttpSession() } catch (final IllegalStateException e) {
.setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, authorizationContext log.error("Set current locale for session failed: ", e);
.getLoggedInUser() }
.getOrThrow().language);
RWT.setLocale(this.i18nSupport.getUsersFormatLocale());
} catch (final IllegalStateException e) {
log.error("Set current locale for session failed: ", e); pageContext.forwardToMainPage();
}
} else {
RWT.setLocale(this.i18nSupport.getUsersFormatLocale()); loginError(pageContext, "sebserver.login.failed.message");
}
pageContext.forwardToMainPage(); } catch (final Exception e) {
log.error("Unexpected error while trying to login with user: {}", loginName, e);
} else { loginError(pageContext, "Unexpected Error. Please call an Administrator");
loginError(pageContext, "sebserver.login.failed.message"); }
} }
} catch (final Exception e) {
log.error("Unexpected error while trying to login with user: {}", username, e); private void loginError(
loginError(pageContext, "Unexpected Error. Please call an Administrator"); final PageContext pageContext,
} final String message) {
}
this.pageService.logout(pageContext);
private void loginError( final MessageBox error = new Message(
final PageContext pageContext, pageContext.getShell(),
final String message) { this.i18nSupport.getText("sebserver.login.failed.title"),
this.i18nSupport.getText(message, message),
this.pageService.logout(pageContext); SWT.ERROR,
final MessageBox error = new Message( this.i18nSupport);
pageContext.getShell(), error.open(null);
this.i18nSupport.getText("sebserver.login.failed.title"), }
this.i18nSupport.getText(message, message),
SWT.ERROR, }
this.i18nSupport);
error.open(null);
}
}

View file

@ -1,184 +1,184 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.activity.ActivitiesPane; 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.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; 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.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; 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.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent; 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.ActionEventListener;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener; 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;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class MainPage implements TemplateComposer { public class MainPage implements TemplateComposer {
static final Logger log = LoggerFactory.getLogger(MainPage.class); static final Logger log = LoggerFactory.getLogger(MainPage.class);
private static final int ACTIVITY_PANE_WEIGHT = 18; private static final int ACTIVITY_PANE_WEIGHT = 18;
private static final int CONTENT_PANE_WEIGHT = 65; private static final int CONTENT_PANE_WEIGHT = 65;
private static final int ACTION_PANE_WEIGHT = 20; private static final int ACTION_PANE_WEIGHT = 20;
private static final int[] DEFAULT_SASH_WEIGHTS = new int[] { private static final int[] DEFAULT_SASH_WEIGHTS = new int[] {
ACTIVITY_PANE_WEIGHT, ACTIVITY_PANE_WEIGHT,
CONTENT_PANE_WEIGHT, CONTENT_PANE_WEIGHT,
ACTION_PANE_WEIGHT ACTION_PANE_WEIGHT
}; };
private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 }; private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 };
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
private final PolyglotPageService polyglotPageService; private final PolyglotPageService polyglotPageService;
public MainPage( public MainPage(
final WidgetFactory widgetFactory, final WidgetFactory widgetFactory,
final PolyglotPageService polyglotPageService) { final PolyglotPageService polyglotPageService) {
this.widgetFactory = widgetFactory; this.widgetFactory = widgetFactory;
this.polyglotPageService = polyglotPageService; this.polyglotPageService = polyglotPageService;
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final Composite parent = pageContext.getParent(); final Composite parent = pageContext.getParent();
parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
WidgetFactory.setTestId(parent, "main-page"); WidgetFactory.setTestId(parent, "main-page");
final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL); final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL);
final GridLayout gridLayout = new GridLayout(); final GridLayout gridLayout = new GridLayout();
mainSash.setLayout(gridLayout); mainSash.setLayout(gridLayout);
mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Composite nav = new Composite(mainSash, SWT.NONE); final Composite nav = new Composite(mainSash, SWT.NONE);
nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final GridLayout navLayout = new GridLayout(); final GridLayout navLayout = new GridLayout();
navLayout.marginHeight = 20; navLayout.marginHeight = 20;
navLayout.marginWidth = 0; navLayout.marginWidth = 0;
nav.setLayout(navLayout); nav.setLayout(navLayout);
final Composite content = PageService.createManagedVScrolledComposite( final Composite content = PageService.createManagedVScrolledComposite(
mainSash, mainSash,
scrolledComposite -> { scrolledComposite -> {
final Composite result = new Composite(scrolledComposite, SWT.NONE); final Composite result = new Composite(scrolledComposite, SWT.NONE);
result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
final GridLayout contentOuterlayout = new GridLayout(); final GridLayout contentOuterLayout = new GridLayout();
contentOuterlayout.marginHeight = 0; contentOuterLayout.marginHeight = 0;
contentOuterlayout.marginWidth = 0; contentOuterLayout.marginWidth = 0;
result.setLayout(contentOuterlayout); result.setLayout(contentOuterLayout);
return result; return result;
}, },
false); false);
final Label toggleView = this.widgetFactory.imageButton( final Label toggleView = this.widgetFactory.imageButton(
ImageIcon.MAXIMIZE, ImageIcon.MAXIMIZE,
content, content,
new LocTextKey("sebserver.mainpage.maximize.tooltip"), new LocTextKey("sebserver.mainpage.maximize.tooltip"),
event -> { event -> {
final Label ib = (Label) event.widget; final Label ib = (Label) event.widget;
if ((Boolean) ib.getData("fullScreen")) { if ((Boolean) ib.getData("fullScreen")) {
mainSash.setWeights(DEFAULT_SASH_WEIGHTS); mainSash.setWeights(DEFAULT_SASH_WEIGHTS);
ib.setData("fullScreen", false); ib.setData("fullScreen", false);
ib.setImage(WidgetFactory.ImageIcon.MAXIMIZE.getImage(ib.getDisplay())); ib.setImage(WidgetFactory.ImageIcon.MAXIMIZE.getImage(ib.getDisplay()));
this.polyglotPageService.injectI18n( this.polyglotPageService.injectI18n(
ib, ib,
null, null,
new LocTextKey("sebserver.mainpage.maximize.tooltip")); new LocTextKey("sebserver.mainpage.maximize.tooltip"));
} else { } else {
mainSash.setWeights(OPENED_SASH_WEIGHTS); mainSash.setWeights(OPENED_SASH_WEIGHTS);
ib.setData("fullScreen", true); ib.setData("fullScreen", true);
ib.setImage(WidgetFactory.ImageIcon.MINIMIZE.getImage(ib.getDisplay())); ib.setImage(WidgetFactory.ImageIcon.MINIMIZE.getImage(ib.getDisplay()));
this.polyglotPageService.injectI18n( this.polyglotPageService.injectI18n(
ib, ib,
null, null,
new LocTextKey("sebserver.mainpage.minimize.tooltip")); new LocTextKey("sebserver.mainpage.minimize.tooltip"));
} }
}); });
final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false); final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false);
toggleView.setLayoutData(gridData); toggleView.setLayoutData(gridData);
toggleView.setData("fullScreen", false); toggleView.setData("fullScreen", false);
final Composite contentObjects = new Composite(content, SWT.NONE); final Composite contentObjects = new Composite(content, SWT.NONE);
contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final GridLayout contentObjectslayout = new GridLayout(); final GridLayout contentObjectsLayout = new GridLayout();
contentObjectslayout.marginHeight = 0; contentObjectsLayout.marginHeight = 0;
contentObjectslayout.marginWidth = 0; contentObjectsLayout.marginWidth = 0;
contentObjects.setLayout(contentObjectslayout); contentObjects.setLayout(contentObjectsLayout);
contentObjects.setData( contentObjects.setData(
PageEventListener.LISTENER_ATTRIBUTE_KEY, PageEventListener.LISTENER_ATTRIBUTE_KEY,
new ContentActionEventListener(event -> pageContext new ContentActionEventListener(event -> pageContext
.composerService() .composerService()
.compose( .compose(
event.action.definition.targetState.contentPaneComposer(), event.action.definition.targetState.contentPaneComposer(),
event.action.pageContext().copyOf(contentObjects)), event.action.pageContext().copyOf(contentObjects)),
2)); 2));
final Composite actionPane = new Composite(mainSash, SWT.NONE); final Composite actionPane = new Composite(mainSash, SWT.NONE);
actionPane.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); actionPane.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
final GridLayout actionPaneGrid = new GridLayout(); final GridLayout actionPaneGrid = new GridLayout();
actionPane.setLayout(actionPaneGrid); actionPane.setLayout(actionPaneGrid);
actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane"); actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane");
actionPane.setData( actionPane.setData(
PageEventListener.LISTENER_ATTRIBUTE_KEY, PageEventListener.LISTENER_ATTRIBUTE_KEY,
new ContentActionEventListener(event -> pageContext new ContentActionEventListener(event -> pageContext
.composerService() .composerService()
.compose( .compose(
event.action.definition.targetState.actionPaneComposer(), event.action.definition.targetState.actionPaneComposer(),
event.action.pageContext().copyOf(actionPane)), event.action.pageContext().copyOf(actionPane)),
1)); 1));
pageContext.composerService().compose( pageContext.composerService().compose(
ActivitiesPane.class, ActivitiesPane.class,
pageContext.copyOf(nav)); pageContext.copyOf(nav));
mainSash.setWeights(DEFAULT_SASH_WEIGHTS); mainSash.setWeights(DEFAULT_SASH_WEIGHTS);
} }
private static final class ContentActionEventListener implements ActionEventListener { private static final class ContentActionEventListener implements ActionEventListener {
private final int priority; private final int priority;
private final Consumer<ActionEvent> apply; private final Consumer<ActionEvent> apply;
protected ContentActionEventListener(final Consumer<ActionEvent> apply, final int priority) { protected ContentActionEventListener(final Consumer<ActionEvent> apply, final int priority) {
this.apply = apply; this.apply = apply;
this.priority = priority; this.priority = priority;
} }
@Override @Override
public int priority() { public int priority() {
return this.priority; return this.priority;
} }
@Override @Override
public void notify(final ActionEvent event) { public void notify(final ActionEvent event) {
this.apply.accept(event); this.apply.accept(event);
} }
} }
} }

View file

@ -240,8 +240,8 @@ public class QuizDiscoveryList implements TemplateComposer {
} }
private static Function<QuizData, String> quizDataLmsSetupNameFunction(final ResourceService resourceService) { private static Function<QuizData, String> quizDataLmsSetupNameFunction(final ResourceService resourceService) {
return quizzData -> resourceService.getLmsSetupNameFunction() return quizData -> resourceService.getLmsSetupNameFunction()
.apply(String.valueOf(quizzData.lmsSetupId)); .apply(String.valueOf(quizData.lmsSetupId));
} }
private PageAction importQuizData(final PageAction action, final EntityTable<QuizData> table) { private PageAction importQuizData(final PageAction action, final EntityTable<QuizData> table) {

View file

@ -247,9 +247,7 @@ public class RegisterPage implements TemplateComposer {
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
gridData.verticalIndent = 10; gridData.verticalIndent = 10;
cancelButton.setLayoutData(gridData); cancelButton.setLayoutData(gridData);
cancelButton.addListener(SWT.Selection, event -> { cancelButton.addListener(SWT.Selection, event -> pageContext.forwardToLoginPage());
pageContext.forwardToLoginPage();
});
} }

View file

@ -48,7 +48,7 @@ import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
@GuiProfile @GuiProfile
public class SebClientConfigList implements TemplateComposer { 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"); new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege");
private static final LocTextKey EMPTY_LIST_TEXT_KEY = private static final LocTextKey EMPTY_LIST_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.list.empty"); new LocTextKey("sebserver.clientconfig.list.empty");
@ -176,7 +176,7 @@ public class SebClientConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
.withSelect( .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) PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false) .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false)

View file

@ -81,7 +81,7 @@ final class SebExamConfigImportPopup {
}; };
} }
private static final boolean doImport( private static boolean doImport(
final PageService pageService, final PageService pageService,
final FormHandle<ConfigurationNode> formHandle, final FormHandle<ConfigurationNode> formHandle,
final boolean newConfig) { final boolean newConfig) {
@ -93,7 +93,7 @@ final class SebExamConfigImportPopup {
final PageContext context = formHandle.getContext(); final PageContext context = formHandle.getContext();
// Ad-hoc field validation // 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); final String fieldValue = form.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_NAME);
if (StringUtils.isBlank(fieldValue)) { if (StringUtils.isBlank(fieldValue)) {
form.setFieldError( form.setFieldError(
@ -116,7 +116,7 @@ final class SebExamConfigImportPopup {
return false; return false;
} }
if (fieldControl != null && fieldControl instanceof FileUploadSelection) { if (fieldControl instanceof FileUploadSelection) {
final FileUploadSelection fileUpload = (FileUploadSelection) fieldControl; final FileUploadSelection fileUpload = (FileUploadSelection) fieldControl;
final InputStream inputStream = fileUpload.getInputStream(); final InputStream inputStream = fileUpload.getInputStream();
if (inputStream != null) { if (inputStream != null) {
@ -162,7 +162,6 @@ final class SebExamConfigImportPopup {
new ActionEvent(action), new ActionEvent(action),
action.pageContext()); action.pageContext());
} }
return true;
} else { } else {
final Exception error = configuration.getError(); final Exception error = configuration.getError();
if (error instanceof RestCallError) { if (error instanceof RestCallError) {
@ -188,12 +187,12 @@ final class SebExamConfigImportPopup {
SebExamConfigPropForm.FORM_TITLE, SebExamConfigPropForm.FORM_TITLE,
configuration.getError()); configuration.getError());
return true;
} }
return true;
} else { } else {
formHandle.getContext().publishPageMessage( formHandle.getContext().publishPageMessage(
new LocTextKey("sebserver.error.unexpected"), 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() { void cancelUpload() {
if (this.form != null) { if (this.form != null) {
final Control fieldControl = this.form.getFieldInput(API.IMPORT_FILE_ATTR_NAME); final Control fieldControl = this.form.getFieldInput(API.IMPORT_FILE_ATTR_NAME);
if (fieldControl != null && fieldControl instanceof FileUploadSelection) { if (fieldControl instanceof FileUploadSelection) {
((FileUploadSelection) fieldControl).close(); ((FileUploadSelection) fieldControl).close();
} }
} }

View file

@ -43,7 +43,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class SebExamConfigList implements TemplateComposer { 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"); new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY = private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.empty"); new LocTextKey("sebserver.examconfig.list.empty");
@ -165,7 +165,7 @@ public class SebExamConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
.withSelect( .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) PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false) .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false)

View file

@ -265,7 +265,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
.noEventPropagation() .noEventPropagation()
.publishIf(() -> modifyGrant && isReadonly) .publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE) .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SebExamConfigCreationPopup.configCreationFunction( .withExec(SebExamConfigCreationPopup.configCreationFunction(
this.pageService, this.pageService,
@ -313,7 +313,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_START_TIME, QuizData.QUIZ_ATTR_START_TIME,
new LocTextKey( new LocTextKey(
ExamList.EXAM_LIST_COLUMN_STARTTIME, ExamList.EXAM_LIST_COLUMN_START_TIME,
this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()), this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()),
ExamConfigurationMap::getExamStartTime)) ExamConfigurationMap::getExamStartTime))

View file

@ -190,7 +190,7 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> examConfigGrant.iw() && !readonly) .publishIf(() -> examConfigGrant.iw() && !readonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE) .newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SebExamConfigCreationPopup.configCreationFunction( .withExec(SebExamConfigCreationPopup.configCreationFunction(
this.pageService, this.pageService,

View file

@ -1,41 +1,41 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content.action; package ch.ethz.seb.sebserver.gui.content.action;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
public enum ActionCategory { public enum ActionCategory {
FORM(null, 0), FORM(null, 0),
INSTITUTION_LIST(new LocTextKey("sebserver.institution.list.actions"), 1), INSTITUTION_LIST(new LocTextKey("sebserver.institution.list.actions"), 1),
USER_ACCOUNT_LIST(new LocTextKey("sebserver.useraccount.list.actions"), 1), USER_ACCOUNT_LIST(new LocTextKey("sebserver.useraccount.list.actions"), 1),
LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1), LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1),
QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1), QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1),
EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1), EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1),
EXAM_CONFIG_MAPPING_LIST(new LocTextKey("sebserver.exam.configuration.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), INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1), SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.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_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1),
SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.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), RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.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_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
LOGS_SEB_CLIENT_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), VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0),
FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50); FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50);
public final LocTextKey title; public final LocTextKey title;
public final int slotPosition; public final int slotPosition;
private ActionCategory(final LocTextKey title, final int slotPosition) { ActionCategory(final LocTextKey title, final int slotPosition) {
this.title = title; this.title = title;
this.slotPosition = slotPosition; this.slotPosition = slotPosition;
} }
} }

View file

@ -467,7 +467,7 @@ public enum ActionDefinition {
new LocTextKey("sebserver.examconfig.action.copy"), new LocTextKey("sebserver.examconfig.action.copy"),
ImageIcon.COPY, ImageIcon.COPY,
ActionCategory.FORM), ActionCategory.FORM),
SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE( SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE(
new LocTextKey("sebserver.examconfig.action.copy-as-template"), new LocTextKey("sebserver.examconfig.action.copy-as-template"),
ImageIcon.TEMPLATE, ImageIcon.TEMPLATE,
ActionCategory.FORM), ActionCategory.FORM),

View file

@ -8,10 +8,17 @@
package ch.ethz.seb.sebserver.gui.content.action; package ch.ethz.seb.sebserver.gui.content.action;
import java.util.ArrayList; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import java.util.HashMap; import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import java.util.Map; 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.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.template.ImageCell; 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.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import java.util.ArrayList;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; import java.util.HashMap;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import java.util.Map;
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;
@Lazy @Lazy
@Component @Component

View file

@ -1,42 +1,42 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content.activity; package ch.ethz.seb.sebserver.gui.content.activity;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; 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.Activity;
public enum ActivityDefinition implements Activity { public enum ActivityDefinition implements Activity {
SEB_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.serveradmin")), SEB_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.serveradmin")),
INSTITUTION(new LocTextKey("sebserver.institution.action.list")), INSTITUTION(new LocTextKey("sebserver.institution.action.list")),
USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")), USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")),
USER_ACTIVITY_LOGS(new LocTextKey("sebserver.logs.activity.userlogs")), USER_ACTIVITY_LOGS(new LocTextKey("sebserver.logs.activity.userlogs")),
LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")), LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")),
QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")), QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")),
EXAM_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.examadmin")), EXAM_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.examadmin")),
EXAM(new LocTextKey("sebserver.exam.action.list")), EXAM(new LocTextKey("sebserver.exam.action.list")),
SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")), SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")),
SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")), SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")),
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")), SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")),
SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")), SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")),
MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")), MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")), MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs")); SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
public final LocTextKey displayName; public final LocTextKey displayName;
private ActivityDefinition(final LocTextKey displayName) { ActivityDefinition(final LocTextKey displayName) {
this.displayName = displayName; this.displayName = displayName;
} }
@Override @Override
public LocTextKey displayName() { public LocTextKey displayName() {
return this.displayName; return this.displayName;
} }
} }

View file

@ -94,7 +94,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
public final Class<? extends TemplateComposer> actionPaneComposer; public final Class<? extends TemplateComposer> actionPaneComposer;
public final Activity activityAnchor; public final Activity activityAnchor;
private PageStateDefinitionImpl( PageStateDefinitionImpl(
final Type type, final Type type,
final Class<? extends TemplateComposer> contentPaneComposer, final Class<? extends TemplateComposer> contentPaneComposer,
final Activity activityAnchor) { final Activity activityAnchor) {
@ -102,7 +102,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
this(type, contentPaneComposer, ActionPane.class, activityAnchor); this(type, contentPaneComposer, ActionPane.class, activityAnchor);
} }
private PageStateDefinitionImpl( PageStateDefinitionImpl(
final Type type, final Type type,
final Class<? extends TemplateComposer> contentPaneComposer, final Class<? extends TemplateComposer> contentPaneComposer,
final Class<? extends TemplateComposer> actionPaneComposer, final Class<? extends TemplateComposer> actionPaneComposer,

View file

@ -44,7 +44,6 @@ public class ThresholdListBuilder extends FieldBuilder<Collection<Threshold>> {
final Control titleLabel = createTitleLabel(builder.formParent, builder, this); final Control titleLabel = createTitleLabel(builder.formParent, builder, this);
if (builder.readonly || this.readonly) { if (builder.readonly || this.readonly) {
// No read-only view needed for this so far? // No read-only view needed for this so far?
return;
} else { } else {
final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput); final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput);

View file

@ -1,109 +1,109 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig; package ch.ethz.seb.sebserver.gui.service.examconfig;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; 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.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.util.Result; 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.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; 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.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; 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;
public interface ExamConfigurationService { public interface ExamConfigurationService {
public static final String ATTRIBUTE_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.label."; String ATTRIBUTE_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.label.";
public static final String GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group."; String GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group.";
public static final String TOOL_TIP_SUFFIX = ".tooltip"; String TOOL_TIP_SUFFIX = ".tooltip";
public static final String TABLE_ROW_TITLE_SUFFIX = ".row.title"; String TABLE_ROW_TITLE_SUFFIX = ".row.title";
WidgetFactory getWidgetFactory(); WidgetFactory getWidgetFactory();
InputFieldBuilder getInputFieldBuilder( InputFieldBuilder getInputFieldBuilder(
ConfigurationAttribute attribute, ConfigurationAttribute attribute,
Orientation orientation); Orientation orientation);
Result<AttributeMapping> getAttributes(Long templateId); Result<AttributeMapping> getAttributes(Long templateId);
Result<AttributeMapping> getAttributes( Result<AttributeMapping> getAttributes(
final TemplateAttribute attribute, final TemplateAttribute attribute,
final Orientation defaultOrientation); final Orientation defaultOrientation);
List<View> getViews(AttributeMapping allAttributes); List<View> getViews(AttributeMapping allAttributes);
ViewContext createViewContext( ViewContext createViewContext(
PageContext pageContext, PageContext pageContext,
Configuration configuration, Configuration configuration,
View view, View view,
AttributeMapping attributeMapping, AttributeMapping attributeMapping,
int rows, int rows,
boolean readonly); boolean readonly);
Composite createViewGrid( Composite createViewGrid(
Composite parent, Composite parent,
ViewContext viewContext); ViewContext viewContext);
void initInputFieldValues( void initInputFieldValues(
Long configurationId, Long configurationId,
Collection<ViewContext> viewContexts); Collection<ViewContext> viewContexts);
PageAction resetToDefaults(PageAction action); PageAction resetToDefaults(PageAction action);
PageAction removeFromView(PageAction action); PageAction removeFromView(PageAction action);
PageAction attachToDefaultView(final PageAction action); PageAction attachToDefaultView(final PageAction action);
static String attributeNameKey(final ConfigurationAttribute attribute) { static String attributeNameKey(final ConfigurationAttribute attribute) {
if (attribute == null) { if (attribute == null) {
return null; return null;
} }
return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name; return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name;
} }
static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) { static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) {
if (attribute == null) { if (attribute == null) {
return null; return null;
} }
return new LocTextKey(attributeNameKey(attribute)); return new LocTextKey(attributeNameKey(attribute));
} }
static LocTextKey getToolTipKey( static LocTextKey getToolTipKey(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) { final I18nSupport i18nSupport) {
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX; final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX;
if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) { if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) {
return null; return null;
} else { } else {
return new LocTextKey(attributeNameKey); return new LocTextKey(attributeNameKey);
} }
} }
static LocTextKey getTablePopupTitleKey( static LocTextKey getTablePopupTitleKey(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) { final I18nSupport i18nSupport) {
return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX); return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX);
} }
} }

View file

@ -1,338 +1,336 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TableItem;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; 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;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; 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.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; 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.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
public abstract class AbstractTableFieldBuilder implements InputFieldBuilder { public abstract class AbstractTableFieldBuilder implements InputFieldBuilder {
private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class); private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class);
private static final int ROW_HEIGHT = 20; private static final int ROW_HEIGHT = 20;
private static final int NAV_HEIGHT = 40; private static final int NAV_HEIGHT = 40;
private static final int TABLE_WIDTH_SPACE = 50; private static final int TABLE_WIDTH_SPACE = 50;
protected final RestService restService; protected final RestService restService;
protected final WidgetFactory widgetFactory; protected final WidgetFactory widgetFactory;
protected InputFieldBuilderSupplier inputFieldBuilderSupplier; protected InputFieldBuilderSupplier inputFieldBuilderSupplier;
protected AbstractTableFieldBuilder( protected AbstractTableFieldBuilder(
final RestService restService, final RestService restService,
final WidgetFactory widgetFactory) { final WidgetFactory widgetFactory) {
this.restService = restService; this.restService = restService;
this.widgetFactory = widgetFactory; this.widgetFactory = widgetFactory;
} }
@Override @Override
public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) { public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier; this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
} }
protected Table createTable(final Composite parent, final TableContext tableContext) { protected Table createTable(final Composite parent, final TableContext tableContext) {
final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL); final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL);
table.setLayout(new GridLayout()); table.setLayout(new GridLayout());
final GridData gridData = new GridData( final GridData gridData = new GridData(
SWT.FILL, SWT.FILL, SWT.FILL, SWT.FILL,
true, false, true, false,
tableContext.orientation.width(), tableContext.orientation.width(),
tableContext.orientation.height()); tableContext.orientation.height());
gridData.heightHint = tableContext.orientation.height() * ROW_HEIGHT + NAV_HEIGHT; gridData.heightHint = tableContext.orientation.height() * ROW_HEIGHT + NAV_HEIGHT;
table.setLayoutData(gridData); table.setLayoutData(gridData);
table.setHeaderVisible(true); table.setHeaderVisible(true);
table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext)); table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
return table; return table;
} }
protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) { protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) {
final TableContext tableContext = new TableContext( return new TableContext(
this.inputFieldBuilderSupplier, this.inputFieldBuilderSupplier,
this.widgetFactory, this.widgetFactory,
attribute, attribute,
viewContext); viewContext);
return tableContext; }
}
protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) {
protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) { table.addListener(SWT.MouseDoubleClick, event -> {
table.addListener(SWT.MouseDoubleClick, event -> { final int selectionIndex = table.getSelectionIndex();
final int selectionIndex = table.getSelectionIndex(); if (selectionIndex >= 0) {
if (selectionIndex >= 0) { tableField.openForm(selectionIndex);
tableField.openForm(selectionIndex); }
} });
}); }
}
protected void adaptColumnWidth(
protected void adaptColumnWidth( final Table table,
final Table table, final TableContext tableContext) {
final TableContext tableContext) {
try {
try { final boolean readonly = tableContext.getViewContext().readonly;
final boolean readonly = tableContext.getViewContext().readonly; final int currentTableWidth = table.getClientArea().width - TABLE_WIDTH_SPACE;
final int currentTableWidth = table.getClientArea().width - TABLE_WIDTH_SPACE; final TableColumn[] columns = table.getColumns();
final TableColumn[] columns = table.getColumns(); final List<Orientation> orientations = tableContext
final List<Orientation> orientations = tableContext .getColumnAttributes()
.getColumnAttributes() .stream()
.stream() .map(attr -> tableContext.getOrientation(attr.id))
.map(attr -> tableContext.getOrientation(attr.id)) .collect(Collectors.toList());
.collect(Collectors.toList()); final Integer div = orientations
final Integer div = orientations .stream()
.stream() .map(o -> o.width)
.map(o -> o.width) .reduce(0, Integer::sum);
.reduce(0, (acc, val) -> acc + val); final int widthUnit = currentTableWidth / div;
final int widthUnit = currentTableWidth / div; for (int i = 0; i < columns.length - ((readonly) ? 0 : 2); i++) {
for (int i = 0; i < columns.length - ((readonly) ? 0 : 2); i++) { columns[i].setWidth(widthUnit * orientations.get(i).width);
columns[i].setWidth(widthUnit * orientations.get(i).width); }
} } catch (final Exception e) {
} catch (final Exception e) { log.warn("Failed to adaptColumnWidth: ", e);
log.warn("Failed to adaptColumnWidth: ", e); }
} }
}
protected static void setValueToCell(
protected static void setValueToCell( final TableContext tableContext,
final TableContext tableContext, final TableItem item,
final TableItem item, final int cellIndex,
final int cellIndex, final ConfigurationAttribute attribute,
final ConfigurationAttribute attribute, final TableValue tableValue) {
final TableValue tableValue) {
switch (attribute.type) {
switch (attribute.type) { case CHECKBOX: {
case CHECKBOX: { item.setImage(
item.setImage( cellIndex,
cellIndex, (BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null))
(BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null)) ? ImageIcon.YES.getImage(item.getDisplay())
? ImageIcon.YES.getImage(item.getDisplay()) : ImageIcon.NO.getImage(item.getDisplay()));
: ImageIcon.NO.getImage(item.getDisplay())); break;
break; }
} case SINGLE_SELECTION: {
case SINGLE_SELECTION: { final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.getName() + "." +
attribute.getName() + "." + tableValue.value;
tableValue.value; item.setText(
item.setText( cellIndex,
cellIndex, tableContext.i18nSupport().getText(key, getValue(attribute, tableValue)));
tableContext.i18nSupport().getText(key, getValue(attribute, tableValue))); break;
break; }
} default: {
default: { item.setText(cellIndex, getValue(attribute, tableValue));
item.setText(cellIndex, getValue(attribute, tableValue)); break;
break; }
} }
} }
}
private static String getValue(
private static String getValue( final ConfigurationAttribute attribute,
final ConfigurationAttribute attribute, final TableValue tableValue) {
final TableValue tableValue) {
if (tableValue == null) {
if (tableValue == null) { if (StringUtils.isBlank(attribute.defaultValue)) {
if (StringUtils.isBlank(attribute.defaultValue)) { return Constants.EMPTY_NOTE;
return Constants.EMPTY_NOTE; } else {
} else { return attribute.defaultValue;
return attribute.defaultValue; }
} } else {
} else { if (StringUtils.isBlank(tableValue.value)) {
if (StringUtils.isBlank(tableValue.value)) { return Constants.EMPTY_NOTE;
return Constants.EMPTY_NOTE; } else {
} else { return tableValue.value;
return tableValue.value; }
} }
} }
}
static abstract class AbstractTableInputField extends AbstractInputField<Table> {
static abstract class AbstractTableInputField extends AbstractInputField<Table> {
protected final TableContext tableContext;
protected final TableContext tableContext;
protected AbstractTableInputField(
protected AbstractTableInputField( final ConfigurationAttribute attribute,
final ConfigurationAttribute attribute, final Orientation orientation,
final Orientation orientation, final Table control,
final Table control, final Label errorLabel,
final Label errorLabel, final TableContext tableContext) {
final TableContext tableContext) {
super(attribute, orientation, control, errorLabel);
super(attribute, orientation, control, errorLabel); this.tableContext = tableContext;
this.tableContext = tableContext; }
}
@Override
@Override public ConfigurationValue initValue(final Collection<ConfigurationValue> values) {
public ConfigurationValue initValue(final Collection<ConfigurationValue> values) { clearTable();
clearTable(); // get all child values as TableValues
// get all child values as TableValues final List<TableValue> tableValues = getChildValues(
final List<TableValue> tableValues = getChildValues( this.tableContext,
this.tableContext, this.attribute,
this.attribute, values);
values);
initValue(tableValues);
initValue(tableValues); return null;
return null; }
}
abstract void initValue(final List<TableValue> tableValues);
abstract void initValue(final List<TableValue> tableValues);
abstract void openForm(final int selectionIndex);
abstract void openForm(final int selectionIndex);
abstract void applyTableRowValues(final int index);
abstract void applyTableRowValues(final int index);
protected List<TableValue> getChildValues(
protected List<TableValue> getChildValues( final TableContext tableContext,
final TableContext tableContext, final ConfigurationAttribute attribute,
final ConfigurationAttribute attribute, final Collection<ConfigurationValue> values) {
final Collection<ConfigurationValue> values) {
return values.stream()
return values.stream() .filter(v -> isChildValue(tableContext, attribute, v))
.filter(v -> isChildValue(tableContext, attribute, v)) .map(TableValue::of)
.map(TableValue::of) .collect(Collectors.toList());
.collect(Collectors.toList()); }
}
protected boolean isChildValue(
protected boolean isChildValue( final TableContext tableContext,
final TableContext tableContext, final ConfigurationAttribute attribute,
final ConfigurationAttribute attribute, final ConfigurationValue value) {
final ConfigurationValue value) {
if (!tableContext.getViewContext().attributeMapping.attributeIdMapping
if (!tableContext.getViewContext().attributeMapping.attributeIdMapping .containsKey(value.attributeId)) {
.containsKey(value.attributeId)) {
return false;
return false; }
}
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId); if (attr == null) {
if (attr == null) { return false;
return false; }
} while (attr.parentId != null) {
while (attr.parentId != null) { if (attribute.id.equals(attr.parentId)) {
if (attribute.id.equals(attr.parentId)) { return true;
return true; }
} attr = tableContext.getAttribute(attr.parentId);
attr = tableContext.getAttribute(attr.parentId); }
}
return false;
return false; }
}
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) { final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>(); for (final TableValue tableValue : tableValues) {
for (final TableValue tableValue : tableValues) { final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent( tableValue.listIndex,
tableValue.listIndex, key -> new HashMap<>());
key -> new HashMap<>()); rowValues.put(tableValue.attributeId, tableValue);
rowValues.put(tableValue.attributeId, tableValue); }
} return indexMapping;
return indexMapping; }
}
protected void valuesFromIndexMap(
protected void valuesFromIndexMap( final List<Map<Long, TableValue>> values,
final List<Map<Long, TableValue>> values, final Map<Integer, Map<Long, TableValue>> indexMapping) {
final Map<Integer, Map<Long, TableValue>> indexMapping) {
values.clear();
values.clear(); final List<Integer> rows = new ArrayList<>(indexMapping.keySet());
final List<Integer> rows = new ArrayList<>(indexMapping.keySet()); rows.sort(Integer::compareTo);
rows.sort((i1, i2) -> i1.compareTo(i2)); rows
rows .forEach(i -> {
.stream() final Map<Long, TableValue> rowValues = indexMapping.get(i);
.forEach(i -> { values.add(rowValues);
final Map<Long, TableValue> rowValues = indexMapping.get(i); });
values.add(rowValues); }
});
} protected void applyFormValues(
final List<Map<Long, TableValue>> values,
protected void applyFormValues( final Map<Long, TableValue> rowValues,
final List<Map<Long, TableValue>> values, final int index) {
final Map<Long, TableValue> rowValues,
final int index) { if (!values.isEmpty()) {
values.remove(index);
if (!values.isEmpty()) { values.add(index, rowValues);
values.remove(index); applyTableRowValues(index);
values.add(index, rowValues); }
applyTableRowValues(index);
} // send values to web-service
this.tableContext.getValueChangeListener()
// send values to web-service .tableChanged(extractTableValue(values));
this.tableContext.getValueChangeListener() }
.tableChanged(extractTableValue(values));
} protected ConfigurationTableValues extractTableValue(final List<Map<Long, TableValue>> values) {
final List<TableValue> collect = values
protected ConfigurationTableValues extractTableValue(final List<Map<Long, TableValue>> values) { .stream()
final List<TableValue> collect = values .flatMap(map -> map.values().stream())
.stream() .collect(Collectors.toList());
.flatMap(map -> map.values().stream())
.collect(Collectors.toList()); return new ConfigurationTableValues(
this.tableContext.getInstitutionId(),
return new ConfigurationTableValues( this.tableContext.getConfigurationId(),
this.tableContext.getInstitutionId(), this.attribute.id,
this.tableContext.getConfigurationId(), collect);
this.attribute.id, }
collect);
} @Override
public void setDefaultValue() {
@Override // NOTE this just empty the list for now
public void setDefaultValue() { // TODO do we need default values for lists?
// NOTE this just empty the list for now clearTable();
// TODO do we need default values for lists? final List<TableValue> values = new ArrayList<>();
clearTable(); this.tableContext.getValueChangeListener().tableChanged(
final List<TableValue> values = new ArrayList<>(); new ConfigurationTableValues(
this.tableContext.getValueChangeListener().tableChanged( this.tableContext.getInstitutionId(),
new ConfigurationTableValues( this.tableContext.getConfigurationId(),
this.tableContext.getInstitutionId(), this.attribute.id,
this.tableContext.getConfigurationId(), values));
this.attribute.id, }
values));
} void clearTable() {
this.control.setSelection(-1);
void clearTable() { if (this.control.getItemCount() > 0) {
this.control.setSelection(-1); for (final TableItem item : this.control.getItems()) {
if (this.control.getItemCount() > 0) { item.dispose();
for (final TableItem item : this.control.getItems()) { }
item.dispose(); }
} }
}
} @Override
protected void setValueToControl(final String value) {
@Override throw new UnsupportedOperationException();
protected void setValueToControl(final String value) { }
throw new UnsupportedOperationException();
} @Override
public String getValue() {
@Override throw new UnsupportedOperationException();
public String getValue() { }
throw new UnsupportedOperationException(); }
}
} }
}

View file

@ -1,225 +1,225 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Collection; import java.util.Collection;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; 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.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; 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.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
interface CellFieldBuilderAdapter { interface CellFieldBuilderAdapter {
static CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() { CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() {
@Override @Override
public void createCell(final ViewGridBuilder builder) { public void createCell(final ViewGridBuilder builder) {
} }
@Override @Override
public String toString() { public String toString() {
return "[DUMMY]"; return "[DUMMY]";
} }
}; };
void createCell(ViewGridBuilder builder); void createCell(ViewGridBuilder builder);
default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
} }
static CellFieldBuilderAdapter fieldBuilderAdapter( static CellFieldBuilderAdapter fieldBuilderAdapter(
final InputFieldBuilder inputFieldBuilder, final InputFieldBuilder inputFieldBuilder,
final ConfigurationAttribute attribute) { final ConfigurationAttribute attribute) {
return new CellFieldBuilderAdapter() { return new CellFieldBuilderAdapter() {
@Override @Override
public void createCell(final ViewGridBuilder builder) { public void createCell(final ViewGridBuilder builder) {
final InputField inputField = inputFieldBuilder.createInputField( final InputField inputField = inputFieldBuilder.createInputField(
builder.parent, builder.parent,
attribute, attribute,
builder.viewContext); builder.viewContext);
if (inputField != null) { if (inputField != null) {
builder.viewContext.registerInputField(inputField); builder.viewContext.registerInputField(inputField);
} }
} }
@Override @Override
public String toString() { public String toString() {
return "[FIELD]"; return "[FIELD]";
} }
}; };
} }
static CellFieldBuilderAdapter labelBuilder( static CellFieldBuilderAdapter labelBuilder(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
return new CellFieldBuilderAdapter() { return new CellFieldBuilderAdapter() {
private int span = 1; private int span = 1;
@Override @Override
public void createCell(final ViewGridBuilder builder) { public void createCell(final ViewGridBuilder builder) {
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
final Label label = widgetFactory.labelLocalized( final Label label = widgetFactory.labelLocalized(
builder.parent, builder.parent,
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name, new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name,
attribute.name)); attribute.name));
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
switch (orientation.title) { switch (orientation.title) {
case LEFT: case LEFT:
case RIGHT: { case RIGHT: {
label.setAlignment(SWT.LEFT); label.setAlignment(SWT.LEFT);
gridData.verticalIndent = 5; gridData.verticalIndent = 5;
break; break;
} }
case RIGHT_SPAN: case RIGHT_SPAN:
case LEFT_SPAN: { case LEFT_SPAN: {
label.setAlignment(SWT.LEFT); label.setAlignment(SWT.LEFT);
gridData.horizontalSpan = (span > 1) ? span : orientation.width; gridData.horizontalSpan = (span > 1) ? span : orientation.width;
gridData.verticalIndent = 5; gridData.verticalIndent = 5;
break; break;
} }
case TOP: { case TOP: {
gridData.horizontalSpan = orientation.width; gridData.horizontalSpan = orientation.width;
gridData.verticalAlignment = SWT.BOTTOM; gridData.verticalAlignment = SWT.BOTTOM;
break; break;
} }
default: { default: {
label.setAlignment(SWT.LEFT); label.setAlignment(SWT.LEFT);
break; break;
} }
} }
label.setLayoutData(gridData); label.setLayoutData(gridData);
label.pack(); label.pack();
} }
@Override @Override
public void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { public void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
if (grid[y][x] != this) { if (grid[y][x] != this) {
return; return;
} }
if (orientation.title == TitleOrientation.LEFT_SPAN) { if (orientation.title == TitleOrientation.LEFT_SPAN) {
int xpos = x - 1; int xpos = x - 1;
while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) { while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) {
grid[y][xpos] = this; grid[y][xpos] = this;
grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER; grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER;
this.span++; this.span++;
xpos--; xpos--;
} }
} }
} }
@Override @Override
public String toString() { public String toString() {
return "[LABEL]"; return "[LABEL]";
} }
}; };
} }
static CellFieldBuilderAdapter passwordConfirmLabel( static CellFieldBuilderAdapter passwordConfirmLabel(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
return new CellFieldBuilderAdapter() { return new CellFieldBuilderAdapter() {
@Override @Override
public void createCell(final ViewGridBuilder builder) { public void createCell(final ViewGridBuilder builder) {
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
final Label label = widgetFactory.labelLocalized( final Label label = widgetFactory.labelLocalized(
builder.parent, builder.parent,
new LocTextKey( new LocTextKey(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name
+ ".confirm")); + ".confirm"));
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
label.setAlignment(SWT.LEFT); label.setAlignment(SWT.LEFT);
gridData.verticalIndent = 20; gridData.verticalIndent = 20;
label.setLayoutData(gridData); label.setLayoutData(gridData);
} }
@Override @Override
public String toString() { public String toString() {
return "[PASSWORD CONFIRM LABEL]"; return "[PASSWORD CONFIRM LABEL]";
} }
}; };
} }
static class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter { class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter {
final Collection<Orientation> orientationsOfGroup; final Collection<Orientation> orientationsOfGroup;
int x = 100; int x = 100;
int y = 100; int y = 100;
int width = 1; int width = 1;
int height = 1; int height = 1;
GroupCellFieldBuilderAdapter(final Collection<Orientation> orientationsOfGroup) { GroupCellFieldBuilderAdapter(final Collection<Orientation> orientationsOfGroup) {
this.orientationsOfGroup = orientationsOfGroup; this.orientationsOfGroup = orientationsOfGroup;
for (final Orientation o : this.orientationsOfGroup) { for (final Orientation o : this.orientationsOfGroup) {
final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0); final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0);
this.x = (xpos < this.x) ? xpos : this.x; this.x = Math.min(xpos, this.x);
final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0); final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0);
this.y = (ypos < this.y) ? ypos : this.y; this.y = Math.min(ypos, this.y);
this.width = (this.width < o.xpos() + o.width()) ? o.xpos() + o.width() : this.width; this.width = Math.max(this.width, o.xpos() + o.width());
this.height = (this.height < o.ypos() + o.height()) ? o.ypos() + o.height() : this.height; this.height = Math.max(this.height, o.ypos() + o.height());
} }
this.width = this.width - this.x; this.width = this.width - this.x;
this.height = this.height - this.y + 1; this.height = this.height - this.y + 1;
} }
@Override @Override
public void createCell(final ViewGridBuilder builder) { public void createCell(final ViewGridBuilder builder) {
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
final Orientation o = this.orientationsOfGroup.stream().findFirst().get(); final Orientation o = this.orientationsOfGroup.stream().findFirst().orElse(null);
final LocTextKey groupLabelKey = new LocTextKey( final LocTextKey groupLabelKey = new LocTextKey(
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
o.groupId, o.groupId,
o.groupId); o.groupId);
final LocTextKey groupTooltipKey = new LocTextKey( final LocTextKey groupTooltipKey = new LocTextKey(
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
o.groupId + o.groupId +
ExamConfigurationService.TOOL_TIP_SUFFIX, ExamConfigurationService.TOOL_TIP_SUFFIX,
o.groupId); o.groupId);
final Group group = widgetFactory.groupLocalized( final Group group = widgetFactory.groupLocalized(
builder.parent, builder.parent,
this.width, this.width,
groupLabelKey, groupLabelKey,
groupTooltipKey); groupTooltipKey);
group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height)); group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height));
final ViewGridBuilder groupBuilder = new ViewGridBuilder( final ViewGridBuilder groupBuilder = new ViewGridBuilder(
group, group,
builder.viewContext, builder.viewContext,
this, this,
builder.examConfigurationService); builder.examConfigurationService);
for (final Orientation orientation : this.orientationsOfGroup) { for (final Orientation orientation : this.orientationsOfGroup) {
final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId); final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId);
groupBuilder.add(attribute); groupBuilder.add(attribute);
} }
groupBuilder.compose(); groupBuilder.compose();
} }
} }
} }

View file

@ -1,134 +1,134 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Objects; import java.util.Objects;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; 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.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class CheckBoxBuilder implements InputFieldBuilder { public class CheckBoxBuilder implements InputFieldBuilder {
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
protected CheckBoxBuilder(final WidgetFactory widgetFactory) { protected CheckBoxBuilder(final WidgetFactory widgetFactory) {
this.widgetFactory = widgetFactory; this.widgetFactory = widgetFactory;
} }
@Override @Override
public boolean builderFor( public boolean builderFor(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
return attribute.type == AttributeType.CHECKBOX; return attribute.type == AttributeType.CHECKBOX;
} }
@Override @Override
public InputField createInputField( public InputField createInputField(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
Objects.requireNonNull(parent); Objects.requireNonNull(parent);
Objects.requireNonNull(attribute); Objects.requireNonNull(attribute);
Objects.requireNonNull(viewContext); Objects.requireNonNull(viewContext);
final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport();
final Orientation orientation = viewContext final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, attribute, orientation); .createInnerGrid(parent, attribute, orientation);
final Button checkbox = this.widgetFactory.buttonLocalized( final Button checkbox = this.widgetFactory.buttonLocalized(
innerGrid, innerGrid,
SWT.CHECK, SWT.CHECK,
(orientation.title == TitleOrientation.NONE) (orientation.title == TitleOrientation.NONE)
? ExamConfigurationService.attributeNameLocKey(attribute) ? ExamConfigurationService.attributeNameLocKey(attribute)
: null, : null,
ExamConfigurationService.getToolTipKey(attribute, i18nSupport)); ExamConfigurationService.getToolTipKey(attribute, i18nSupport));
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
gridData.verticalIndent = 0; gridData.verticalIndent = 0;
checkbox.setLayoutData(gridData); checkbox.setLayoutData(gridData);
final CheckboxField checkboxField = new CheckboxField( final CheckboxField checkboxField = new CheckboxField(
attribute, attribute,
viewContext.getOrientation(attribute.id), viewContext.getOrientation(attribute.id),
checkbox); checkbox);
if (viewContext.readonly) { if (viewContext.readonly) {
checkbox.setEnabled(false); checkbox.setEnabled(false);
} else { } else {
checkbox.addListener( checkbox.addListener(
SWT.Selection, SWT.Selection,
event -> viewContext.getValueChangeListener().valueChanged( event -> viewContext.getValueChangeListener().valueChanged(
viewContext, viewContext,
attribute, attribute,
checkboxField.getValue(), checkboxField.getValue(),
checkboxField.listIndex)); checkboxField.listIndex));
} }
return checkboxField; return checkboxField;
} }
static final class CheckboxField extends AbstractInputField<Button> { static final class CheckboxField extends AbstractInputField<Button> {
CheckboxField( CheckboxField(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation, final Orientation orientation,
final Button control) { final Button control) {
super(attribute, orientation, control, null); super(attribute, orientation, control, null);
} }
@Override @Override
protected void setValueToControl(final String value) { protected void setValueToControl(final String value) {
this.control.setSelection(Boolean.valueOf(this.initValue)); this.control.setSelection(Boolean.parseBoolean(this.initValue));
} }
@Override @Override
public String getValue() { public String getValue() {
return this.control.getSelection() return this.control.getSelection()
? Constants.TRUE_STRING ? Constants.TRUE_STRING
: Constants.FALSE_STRING; : Constants.FALSE_STRING;
} }
@Override @Override
public String getReadableValue() { public String getReadableValue() {
return this.control.getSelection() return this.control.getSelection()
? "Active" ? "Active"
: "Inactive"; : "Inactive";
} }
} }
} }

View file

@ -1,270 +1,270 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TableItem;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; 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.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; 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;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class CompositeTableFieldBuilder extends AbstractTableFieldBuilder { public class CompositeTableFieldBuilder extends AbstractTableFieldBuilder {
private static final Logger log = LoggerFactory.getLogger(CompositeTableFieldBuilder.class); private static final Logger log = LoggerFactory.getLogger(CompositeTableFieldBuilder.class);
private static final String TABLE_ENTRY_NAME = "TABLE_ENTRY"; private static final String TABLE_ENTRY_NAME = "TABLE_ENTRY";
private static final String TABLE_COLUMN_NAME_KEY = "TABLE_COLUMN_NAME"; private static final String TABLE_COLUMN_NAME_KEY = "TABLE_COLUMN_NAME";
protected CompositeTableFieldBuilder( protected CompositeTableFieldBuilder(
final RestService restService, final RestService restService,
final WidgetFactory widgetFactory) { final WidgetFactory widgetFactory) {
super(restService, widgetFactory); super(restService, widgetFactory);
} }
@Override @Override
public boolean builderFor( public boolean builderFor(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
return AttributeType.COMPOSITE_TABLE == attribute.type; return AttributeType.COMPOSITE_TABLE == attribute.type;
} }
@Override @Override
public InputField createInputField( public InputField createInputField(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
final I18nSupport i18nSupport = viewContext.getI18nSupport(); final I18nSupport i18nSupport = viewContext.getI18nSupport();
final TableContext tableContext = createTableContext(attribute, viewContext); final TableContext tableContext = createTableContext(attribute, viewContext);
final Table table = createTable(parent, tableContext); final Table table = createTable(parent, tableContext);
final String resources = attribute.getResources(); final String resources = attribute.getResources();
final String[] columnsAndRows = StringUtils.split( final String[] columnsAndRows = StringUtils.split(
resources, resources,
Constants.EMBEDDED_LIST_SEPARATOR); Constants.EMBEDDED_LIST_SEPARATOR);
final String[] columns = (columnsAndRows.length == 2) final String[] columns = (columnsAndRows.length == 2)
? StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR) ? StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR)
: new String[] { TABLE_ENTRY_NAME }; : new String[] { TABLE_ENTRY_NAME };
final String[] rows = (columnsAndRows.length == 2) final String[] rows = (columnsAndRows.length == 2)
? StringUtils.split(columnsAndRows[1], Constants.LIST_SEPARATOR) ? StringUtils.split(columnsAndRows[1], Constants.LIST_SEPARATOR)
: StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR); : StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR);
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute); final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute);
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
final TableColumn column = this.widgetFactory.tableColumnLocalized( final TableColumn column = this.widgetFactory.tableColumnLocalized(
table, table,
new LocTextKey(attributeNameKey + "." + columns[i]), new LocTextKey(attributeNameKey + "." + columns[i]),
new LocTextKey(attributeNameKey + "." + columns[i] + ".tootlip")); new LocTextKey(attributeNameKey + "." + columns[i] + ".tootlip"));
column.setData(TABLE_COLUMN_NAME_KEY, columns[i]); column.setData(TABLE_COLUMN_NAME_KEY, columns[i]);
column.setWidth(100); column.setWidth(100);
column.setResizable(false); column.setResizable(false);
column.setMoveable(false); column.setMoveable(false);
} }
for (int i = 0; i < rows.length; i++) { for (int i = 0; i < rows.length; i++) {
final TableItem item = new TableItem(table, SWT.NONE); final TableItem item = new TableItem(table, SWT.NONE);
for (int j = 0; j < columns.length; j++) { for (int j = 0; j < columns.length; j++) {
if (TABLE_ENTRY_NAME.equals(columns[j])) { if (TABLE_ENTRY_NAME.equals(columns[j])) {
item.setText(j, i18nSupport.getText( item.setText(j, i18nSupport.getText(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + rows[i], ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + rows[i],
rows[i])); rows[i]));
} }
} }
} }
final CompositeTableInputField tableField = new CompositeTableInputField( final CompositeTableInputField tableField = new CompositeTableInputField(
tableContext, tableContext,
table, table,
Arrays.asList(columns), Arrays.asList(columns),
Arrays.asList(rows)); Arrays.asList(rows));
setSelectionListener(table, tableField); setSelectionListener(table, tableField);
return tableField; return tableField;
} }
@Override @Override
protected void adaptColumnWidth( protected void adaptColumnWidth(
final Table table, final Table table,
final TableContext tableContext) { final TableContext tableContext) {
try { try {
final int currentTableWidth = table.getClientArea().width - 50; final int currentTableWidth = table.getClientArea().width - 50;
final TableColumn[] columns = table.getColumns(); final TableColumn[] columns = table.getColumns();
final int widthUnit = currentTableWidth / (columns.length + 2); final int widthUnit = currentTableWidth / (columns.length + 2);
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
final int factor = (TABLE_ENTRY_NAME.equals(columns[i].getData(TABLE_COLUMN_NAME_KEY))) ? 4 : 1; final int factor = (TABLE_ENTRY_NAME.equals(columns[i].getData(TABLE_COLUMN_NAME_KEY))) ? 4 : 1;
columns[i].setWidth(widthUnit * factor); columns[i].setWidth(widthUnit * factor);
} }
} catch (final Exception e) { } catch (final Exception e) {
log.warn("Failed to adaptColumnWidth: ", e); log.warn("Failed to adaptColumnWidth: ", e);
} }
} }
static final class CompositeTableInputField extends AbstractTableInputField { static final class CompositeTableInputField extends AbstractTableInputField {
final List<String> columns; final List<String> columns;
final List<String> rows; final List<String> rows;
final List<Map<Long, TableValue>> values; final List<Map<Long, TableValue>> values;
CompositeTableInputField( CompositeTableInputField(
final TableContext tableContext, final TableContext tableContext,
final Table control, final Table control,
final List<String> columns, final List<String> columns,
final List<String> rows) { final List<String> rows) {
super(tableContext.attribute, tableContext.orientation, control, null, tableContext); super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
this.values = new ArrayList<>(); this.values = new ArrayList<>();
this.columns = columns; this.columns = columns;
this.rows = rows; this.rows = rows;
} }
@Override @Override
void initValue(final List<TableValue> tableValues) { void initValue(final List<TableValue> tableValues) {
valuesFromIndexMap(this.values, createRowIndexMap(tableValues)); valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
for (int i = 0; i < this.values.size(); i++) { for (int i = 0; i < this.values.size(); i++) {
setRowValues(i, this.values.get(i)); setRowValues(i, this.values.get(i));
} }
} }
@Override @Override
protected void applyTableRowValues(final int index) { protected void applyTableRowValues(final int index) {
setRowValues(index, this.values.get(index)); setRowValues(index, this.values.get(index));
} }
private void setRowValues(final int index, final Map<Long, TableValue> map) { private void setRowValues(final int index, final Map<Long, TableValue> map) {
final TableItem rowItem = this.control.getItem(index); final TableItem rowItem = this.control.getItem(index);
for (final TableValue val : map.values()) { for (final TableValue val : map.values()) {
final Orientation orientation = this.tableContext.getOrientation(val.attributeId); final Orientation orientation = this.tableContext.getOrientation(val.attributeId);
final String groupId = orientation.getGroupId(); final String groupId = orientation.getGroupId();
if (StringUtils.isNotBlank(groupId)) { if (StringUtils.isNotBlank(groupId)) {
final int cellIndex = this.columns.indexOf(groupId); final int cellIndex = this.columns.indexOf(groupId);
if (cellIndex >= 0) { if (cellIndex >= 0) {
setValueToCell( setValueToCell(
this.tableContext, this.tableContext,
rowItem, rowItem,
cellIndex, cellIndex,
this.tableContext.getAttribute(val.attributeId), this.tableContext.getAttribute(val.attributeId),
val); val);
} }
} }
} }
} }
@Override @Override
protected void openForm(final int selectionIndex) { protected void openForm(final int selectionIndex) {
final String row = this.rows.get(selectionIndex); final String row = this.rows.get(selectionIndex);
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex); final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
final TableRowFormBuilder builder = new TableRowFormBuilder( final TableRowFormBuilder builder = new TableRowFormBuilder(
this.tableContext, this.tableContext,
rowValues, rowValues,
row); row);
final ModalInputDialog<Map<Long, TableValue>> dialog = new ModalInputDialog<Map<Long, TableValue>>( final ModalInputDialog<Map<Long, TableValue>> dialog = new ModalInputDialog<Map<Long, TableValue>>(
this.control.getShell(), this.control.getShell(),
this.tableContext.getWidgetFactory()) this.tableContext.getWidgetFactory())
.setDialogWidth(500); .setDialogWidth(500);
if (this.tableContext.getViewContext().readonly) { if (this.tableContext.getViewContext().readonly) {
dialog.open( dialog.open(
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row), new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
builder); builder);
} else { } else {
dialog.open( dialog.open(
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row), new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
(Consumer<Map<Long, TableValue>>) rowVals -> applyFormValues( (Consumer<Map<Long, TableValue>>) _rowValues -> applyFormValues(
this.values, this.values,
rowVals, _rowValues,
selectionIndex), selectionIndex),
() -> this.tableContext.getValueChangeListener() () -> this.tableContext.getValueChangeListener()
.tableChanged(extractTableValue(this.values)), .tableChanged(extractTableValue(this.values)),
builder); builder);
} }
} }
@Override @Override
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) { protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>(); final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
for (final TableValue tableValue : tableValues) { for (final TableValue tableValue : tableValues) {
final ConfigurationAttribute attribute = this.tableContext final ConfigurationAttribute attribute = this.tableContext
.getViewContext() .getViewContext()
.getAttribute(tableValue.attributeId); .getAttribute(tableValue.attributeId);
final String groupId = ConfigurationAttribute.getDependencyValue( final String groupId = ConfigurationAttribute.getDependencyValue(
ConfigurationAttribute.DEPENDENCY_GROUP_ID, ConfigurationAttribute.DEPENDENCY_GROUP_ID,
attribute); attribute);
final int index = this.rows.indexOf(groupId); final int index = this.rows.indexOf(groupId);
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent( final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
index, index,
key -> new HashMap<>()); key -> new HashMap<>());
rowValues.put(tableValue.attributeId, tableValue); rowValues.put(tableValue.attributeId, tableValue);
} }
return indexMapping; return indexMapping;
} }
@Override @Override
void clearTable() { void clearTable() {
// nothing to clear for this table type // nothing to clear for this table type
} }
@Override @Override
protected boolean isChildValue( protected boolean isChildValue(
final TableContext tableContext, final TableContext tableContext,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ConfigurationValue value) { final ConfigurationValue value) {
final boolean childValue = super.isChildValue(tableContext, attribute, value); final boolean childValue = super.isChildValue(tableContext, attribute, value);
if (childValue) { if (childValue) {
final ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId); final ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
return ConfigurationAttribute.hasDependency( return ConfigurationAttribute.hasDependency(
ConfigurationAttribute.DEPENDENCY_GROUP_ID, ConfigurationAttribute.DEPENDENCY_GROUP_ID,
attr); attr);
} }
return childValue; return childValue;
} }
} }
} }

View file

@ -1,423 +1,414 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.Comparator;
import java.util.Set; import java.util.List;
import java.util.stream.Collectors; import java.util.Set;
import java.util.stream.Collectors;
import org.apache.tomcat.util.buf.StringUtils;
import org.eclipse.swt.SWT; import org.apache.tomcat.util.buf.StringUtils;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.layout.GridLayout;
import org.slf4j.Logger; import org.eclipse.swt.widgets.Composite;
import org.slf4j.LoggerFactory; import org.slf4j.Logger;
import org.springframework.context.annotation.Lazy; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule; import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule;
import ch.ethz.seb.sebserver.gui.service.page.FieldValidationError; 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.FieldValidationError;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.AttachDefaultOrientation; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigAttributes; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.AttachDefaultOrientation;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigAttributes;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientations; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewList; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientations;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.RemoveOrientation; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewList;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ResetTemplateValues; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.RemoveOrientation;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ResetTemplateValues;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Service @Lazy
@GuiProfile @Service
public class ExamConfigurationServiceImpl implements ExamConfigurationService { @GuiProfile
public class ExamConfigurationServiceImpl implements ExamConfigurationService {
private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class);
private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class);
private final RestService restService;
private final JSONMapper jsonMapper; private final RestService restService;
private final WidgetFactory widgetFactory; private final JSONMapper jsonMapper;
private final WidgetFactory widgetFactory;
private final InputFieldBuilderSupplier inputFieldBuilderSupplier;
private final Collection<ValueChangeRule> valueChangeRules; private final InputFieldBuilderSupplier inputFieldBuilderSupplier;
private final Collection<ValueChangeRule> valueChangeRules;
public ExamConfigurationServiceImpl(
final RestService restService, public ExamConfigurationServiceImpl(
final JSONMapper jsonMapper, final RestService restService,
final WidgetFactory widgetFactory, final JSONMapper jsonMapper,
final InputFieldBuilderSupplier inputFieldBuilderSupplier, final WidgetFactory widgetFactory,
final Collection<ValueChangeRule> valueChangeRules) { final InputFieldBuilderSupplier inputFieldBuilderSupplier,
final Collection<ValueChangeRule> valueChangeRules) {
this.restService = restService;
this.jsonMapper = jsonMapper; this.restService = restService;
this.widgetFactory = widgetFactory; this.jsonMapper = jsonMapper;
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier; this.widgetFactory = widgetFactory;
this.valueChangeRules = Utils.immutableCollectionOf(valueChangeRules); this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
} this.valueChangeRules = Utils.immutableCollectionOf(valueChangeRules);
}
@Override
public WidgetFactory getWidgetFactory() { @Override
return this.widgetFactory; public WidgetFactory getWidgetFactory() {
} return this.widgetFactory;
}
@Override
public InputFieldBuilder getInputFieldBuilder( @Override
final ConfigurationAttribute attribute, public InputFieldBuilder getInputFieldBuilder(
final Orientation orientation) { final ConfigurationAttribute attribute,
final Orientation orientation) {
return this.inputFieldBuilderSupplier.getInputFieldBuilder(attribute, orientation);
} return this.inputFieldBuilderSupplier.getInputFieldBuilder(attribute, orientation);
}
@Override
public Result<AttributeMapping> getAttributes(final Long templateId) { @Override
return Result.tryCatch(() -> { public Result<AttributeMapping> getAttributes(final Long templateId) {
return new AttributeMapping( return Result.tryCatch(() -> new AttributeMapping(
templateId, templateId,
getAttributes(), getAttributes(),
getOrientations(templateId)); getOrientations(templateId)));
}); }
}
@Override
@Override public Result<AttributeMapping> getAttributes(
public Result<AttributeMapping> getAttributes( final TemplateAttribute attribute,
final TemplateAttribute attribute, final Orientation defaultOrientation) {
final Orientation defaultOrientation) {
final List<Orientation> orientations = getOrientations(attribute.templateId);
final List<Orientation> orientations = getOrientations(attribute.templateId); if (attribute.getOrientation() == null) {
if (attribute.getOrientation() == null) { orientations.add(defaultOrientation);
orientations.add(defaultOrientation); }
}
return Result.tryCatch(() -> new AttributeMapping(
return Result.tryCatch(() -> { attribute.templateId,
return new AttributeMapping( getAttributes(),
attribute.templateId, orientations));
getAttributes(), }
orientations);
}); private List<Orientation> getOrientations(final Long templateId) {
} return this.restService
.getBuilder(GetOrientations.class)
private List<Orientation> getOrientations(final Long templateId) { .withQueryParam(Orientation.FILTER_ATTR_TEMPLATE_ID, String.valueOf(templateId))
return this.restService .call()
.getBuilder(GetOrientations.class) .onError(t -> log.error("Failed to get all Orientation of template {}", templateId, t))
.withQueryParam(Orientation.FILTER_ATTR_TEMPLATE_ID, String.valueOf(templateId)) .getOrThrow();
.call() }
.onError(t -> log.error("Failed to get all Orientation of template {}", templateId, t))
.getOrThrow(); private List<ConfigurationAttribute> getAttributes() {
} return this.restService
.getBuilder(GetConfigAttributes.class)
private List<ConfigurationAttribute> getAttributes() { .call()
return this.restService .onError(t -> log.error("Failed to get all ConfigurationAttribute"))
.getBuilder(GetConfigAttributes.class) .getOrThrow();
.call() }
.onError(t -> log.error("Failed to get all ConfigurationAttribute"))
.getOrThrow(); @Override
} public List<View> getViews(final AttributeMapping allAttributes) {
final Collection<Long> viewIds = allAttributes.getViewIds();
@Override if (viewIds == null || viewIds.isEmpty()) {
public List<View> getViews(final AttributeMapping allAttributes) { return Collections.emptyList();
final Collection<Long> viewIds = allAttributes.getViewIds(); }
if (viewIds == null || viewIds.isEmpty()) {
return Collections.emptyList(); final String ids = StringUtils.join(
} viewIds
.stream()
final String ids = StringUtils.join( .map(String::valueOf)
viewIds .collect(Collectors.toList()),
.stream() Constants.LIST_SEPARATOR_CHAR);
.map(String::valueOf)
.collect(Collectors.toList()), return this.restService.getBuilder(GetViewList.class)
Constants.LIST_SEPARATOR_CHAR); .withQueryParam(API.PARAM_MODEL_ID_LIST, ids)
.call()
return this.restService.getBuilder(GetViewList.class) .getOrThrow()
.withQueryParam(API.PARAM_MODEL_ID_LIST, ids) .stream()
.call() .sorted(Comparator.comparing(v -> v.position))
.getOrThrow() .collect(Collectors.toList());
.stream() }
.sorted((v1, v2) -> v1.position.compareTo(v2.position))
.collect(Collectors.toList()); @Override
} public ViewContext createViewContext(
final PageContext pageContext,
@Override final Configuration configuration,
public ViewContext createViewContext( final View view,
final PageContext pageContext, final AttributeMapping attributeMapping,
final Configuration configuration, final int rows,
final View view, final boolean readonly) {
final AttributeMapping attributeMapping,
final int rows, return new ViewContext(
final boolean readonly) { configuration,
view,
return new ViewContext( rows,
configuration, attributeMapping,
view, new ValueChangeListenerImpl(
rows, pageContext,
attributeMapping, this.restService,
new ValueChangeListenerImpl( this.jsonMapper,
pageContext, this.valueChangeRules),
this.restService, this.widgetFactory.getI18nSupport(),
this.jsonMapper, readonly);
this.valueChangeRules),
this.widgetFactory.getI18nSupport(), }
readonly);
@Override
} public Composite createViewGrid(final Composite parent, final ViewContext viewContext) {
final Composite composite = new Composite(parent, SWT.NONE);
@Override final GridLayout gridLayout = new GridLayout(viewContext.getColumns(), true);
public Composite createViewGrid(final Composite parent, final ViewContext viewContext) { gridLayout.verticalSpacing = 0;
final Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(gridLayout);
final GridLayout gridLayout = new GridLayout(viewContext.getColumns(), true); final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
gridLayout.verticalSpacing = 0; composite.setLayoutData(gridData);
composite.setLayout(gridLayout);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); final ViewGridBuilder viewGridBuilder = new ViewGridBuilder(
composite.setLayoutData(gridData); composite,
viewContext,
final ViewGridBuilder viewGridBuilder = new ViewGridBuilder( this);
composite,
viewContext, for (final ConfigurationAttribute attribute : viewContext.getAttributes()) {
this); final Orientation orientation = viewContext.getOrientation(attribute.id);
if (orientation != null && viewContext.getId().equals(orientation.viewId)) {
for (final ConfigurationAttribute attribute : viewContext.getAttributes()) { viewGridBuilder.add(attribute);
final Orientation orientation = viewContext.getOrientation(attribute.id); }
if (orientation != null && viewContext.getId().equals(orientation.viewId)) { }
viewGridBuilder.add(attribute);
} viewGridBuilder.compose();
} return composite;
}
viewGridBuilder.compose();
return composite; @Override
} public void initInputFieldValues(
final Long configurationId,
@Override final Collection<ViewContext> viewContexts) {
public void initInputFieldValues(
final Long configurationId, if (viewContexts == null || viewContexts.size() < 1) {
final Collection<ViewContext> viewContexts) { log.warn("No viewContexts available");
return;
if (viewContexts == null || viewContexts.size() < 1) { }
log.warn("No viewContexts available");
return; final Collection<ConfigurationValue> attributeValues = this.restService
} .getBuilder(GetConfigurationValues.class)
.withQueryParam(
final Collection<ConfigurationValue> attributeValues = this.restService ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID,
.getBuilder(GetConfigurationValues.class) String.valueOf(configurationId))
.withQueryParam( .call()
ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, .onError(t -> log.error(
String.valueOf(configurationId)) "Failed to get all ConfigurationValue for configuration with id: {}",
.call() configurationId))
.onError(t -> log.error( .getOrElse(Collections::emptyList);
"Failed to get all ConfigurationValue for configuration with id: {}",
configurationId)) viewContexts
.getOrElse(Collections::emptyList); .forEach(vc -> vc.setValuesToInputFields(attributeValues));
}
viewContexts
.forEach(vc -> vc.setValuesToInputFields(attributeValues)); @Override
} public final PageAction resetToDefaults(final PageAction action) {
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
@Override final Set<EntityKey> selection = action.getMultiSelection();
public final PageAction resetToDefaults(final PageAction action) { if (selection != null && !selection.isEmpty()) {
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey(); selection.forEach(entityKey -> callTemplateAction(
final Set<EntityKey> selection = action.getMultiSelection(); ResetTemplateValues.class,
if (selection != null && !selection.isEmpty()) { parentEntityKey.modelId,
selection.stream().forEach(entityKey -> { entityKey.modelId));
callTemplateAction( } else {
ResetTemplateValues.class, final EntityKey entityKey = action.getEntityKey();
parentEntityKey.modelId, callTemplateAction(
entityKey.modelId); ResetTemplateValues.class,
}); parentEntityKey.modelId,
} else { entityKey.modelId);
final EntityKey entityKey = action.getEntityKey(); }
callTemplateAction(
ResetTemplateValues.class, return action;
parentEntityKey.modelId, }
entityKey.modelId);
} @Override
public final PageAction removeFromView(final PageAction action) {
return action; final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
} final Set<EntityKey> selection = action.getMultiSelection();
if (selection != null && !selection.isEmpty()) {
@Override selection.forEach(entityKey -> callTemplateAction(
public final PageAction removeFromView(final PageAction action) { RemoveOrientation.class,
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey(); parentEntityKey.modelId,
final Set<EntityKey> selection = action.getMultiSelection(); entityKey.modelId));
if (selection != null && !selection.isEmpty()) { } else {
selection.stream().forEach(entityKey -> { final EntityKey entityKey = action.getEntityKey();
callTemplateAction( callTemplateAction(
RemoveOrientation.class, RemoveOrientation.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId); entityKey.modelId);
}); }
} else {
final EntityKey entityKey = action.getEntityKey(); return action;
callTemplateAction( }
RemoveOrientation.class,
parentEntityKey.modelId, @Override
entityKey.modelId); public final PageAction attachToDefaultView(final PageAction action) {
} final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
final Set<EntityKey> selection = action.getMultiSelection();
return action; if (selection != null && !selection.isEmpty()) {
} selection.forEach(entityKey -> callTemplateAction(
AttachDefaultOrientation.class,
@Override parentEntityKey.modelId,
public final PageAction attachToDefaultView(final PageAction action) { entityKey.modelId));
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey(); } else {
final Set<EntityKey> selection = action.getMultiSelection(); final EntityKey entityKey = action.getEntityKey();
if (selection != null && !selection.isEmpty()) { callTemplateAction(
selection.stream().forEach(entityKey -> { AttachDefaultOrientation.class,
callTemplateAction( parentEntityKey.modelId,
AttachDefaultOrientation.class, entityKey.modelId);
parentEntityKey.modelId, }
entityKey.modelId);
}); return action;
} else { }
final EntityKey entityKey = action.getEntityKey();
callTemplateAction( private void callTemplateAction(
AttachDefaultOrientation.class, final Class<? extends RestCall<TemplateAttribute>> actionType,
parentEntityKey.modelId, final String templateId,
entityKey.modelId); final String attributeId) {
}
this.restService.getBuilder(actionType)
return action; .withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId)
} .withURIVariable(API.PARAM_MODEL_ID, attributeId)
.call()
private void callTemplateAction( .getOrThrow();
final Class<? extends RestCall<TemplateAttribute>> actionType, }
final String templateId,
final String attributeId) { private static final class ValueChangeListenerImpl implements ValueChangeListener {
this.restService.getBuilder(actionType) public static final String VALIDATION_ERROR_KEY_PREFIX = "sebserver.examconfig.props.validation.";
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId)
.withURIVariable(API.PARAM_MODEL_ID, attributeId) private final PageContext pageContext;
.call() private final RestService restService;
.getOrThrow(); private final JSONMapper jsonMapper;
} private final Collection<ValueChangeRule> valueChangeRules;
private static final class ValueChangeListenerImpl implements ValueChangeListener { protected ValueChangeListenerImpl(
final PageContext pageContext,
public static final String VALIDATION_ERROR_KEY_PREFIX = "sebserver.examconfig.props.validation."; final RestService restService,
final JSONMapper jsonMapper,
private final PageContext pageContext; final Collection<ValueChangeRule> valueChangeRules) {
private final RestService restService;
private final JSONMapper jsonMapper; this.pageContext = pageContext;
private final Collection<ValueChangeRule> valueChangeRules; this.restService = restService;
this.jsonMapper = jsonMapper;
protected ValueChangeListenerImpl( this.valueChangeRules = valueChangeRules;
final PageContext pageContext, }
final RestService restService,
final JSONMapper jsonMapper, @Override
final Collection<ValueChangeRule> valueChangeRules) { public void valueChanged(
final ViewContext context,
this.pageContext = pageContext; final ConfigurationAttribute attribute,
this.restService = restService; final String value,
this.jsonMapper = jsonMapper; final int listIndex) {
this.valueChangeRules = valueChangeRules;
} final ConfigurationValue configurationValue = new ConfigurationValue(
null,
@Override context.getInstitutionId(),
public void valueChanged( context.getConfigurationId(),
final ViewContext context, attribute.id,
final ConfigurationAttribute attribute, listIndex,
final String value, value);
final int listIndex) {
try {
final ConfigurationValue configurationValue = new ConfigurationValue( final String jsonValue = this.jsonMapper.writeValueAsString(configurationValue);
null,
context.getInstitutionId(), final Result<ConfigurationValue> savedValue = this.restService.getBuilder(SaveExamConfigValue.class)
context.getConfigurationId(), .withBody(jsonValue)
attribute.id, .call();
listIndex,
value); if (savedValue.hasError()) {
context.showError(attribute.id, verifyErrorMessage(savedValue.getError()));
try { } else {
final String jsonValue = this.jsonMapper.writeValueAsString(configurationValue); this.notifyGUI(context, attribute, savedValue.get());
}
final Result<ConfigurationValue> savedValue = this.restService.getBuilder(SaveExamConfigValue.class)
.withBody(jsonValue) } catch (final Exception e) {
.call(); this.pageContext.notifySaveError(EntityType.CONFIGURATION_VALUE, e);
}
if (savedValue.hasError()) { }
context.showError(attribute.id, verifyErrorMessage(savedValue.getError()));
} else { @Override
this.notifyGUI(context, attribute, savedValue.get()); public void tableChanged(final ConfigurationTableValues tableValue) {
} this.restService.getBuilder(SaveExamConfigTableValues.class)
.withBody(tableValue)
} catch (final Exception e) { .call();
this.pageContext.notifySaveError(EntityType.CONFIGURATION_VALUE, e); }
}
} private String verifyErrorMessage(final Exception error) {
if (error instanceof RestCallError) {
@Override final List<APIMessage> errorMessages = ((RestCallError) error).getErrorMessages();
public void tableChanged(final ConfigurationTableValues tableValue) { if (errorMessages.isEmpty()) {
this.restService.getBuilder(SaveExamConfigTableValues.class) return "";
.withBody(tableValue) }
.call();
} final APIMessage apiMessage = errorMessages.get(0);
if (!ErrorMessage.FIELD_VALIDATION.isOf(apiMessage)) {
private String verifyErrorMessage(final Exception error) { return "";
if (error instanceof RestCallError) { }
final List<APIMessage> errorMessages = ((RestCallError) error).getErrorMessages();
if (errorMessages.isEmpty()) { final FieldValidationError fieldValidationError = new FieldValidationError(apiMessage);
return ""; return this.pageContext.getI18nSupport().getText(new LocTextKey(
} VALIDATION_ERROR_KEY_PREFIX + fieldValidationError.errorType,
(Object[]) fieldValidationError.getAttributes()));
final APIMessage apiMessage = errorMessages.get(0); }
if (!ErrorMessage.FIELD_VALIDATION.isOf(apiMessage)) {
return ""; log.warn("Unexpected error happened while trying to set SEB configuration value: ", error);
} return VALIDATION_ERROR_KEY_PREFIX + "unexpected";
}
final FieldValidationError fieldValidationError = new FieldValidationError(apiMessage);
return this.pageContext.getI18nSupport().getText(new LocTextKey( @Override
VALIDATION_ERROR_KEY_PREFIX + fieldValidationError.errorType, public void notifyGUI(
(Object[]) fieldValidationError.getAttributes())); final ViewContext viewContext,
} final ConfigurationAttribute attribute,
final ConfigurationValue value) {
log.warn("Unexpected error happened while trying to set SEB configuration value: ", error);
return VALIDATION_ERROR_KEY_PREFIX + "unexpected"; this.valueChangeRules.stream()
} .filter(rule -> rule.observesAttribute(attribute))
.forEach(rule -> rule.applyRule(viewContext, attribute, value));
@Override
public void notifyGUI( }
final ViewContext viewContext, }
final ConfigurationAttribute attribute,
final ConfigurationValue value) { }
this.valueChangeRules.stream()
.filter(rule -> rule.observesAttribute(attribute))
.forEach(rule -> rule.applyRule(viewContext, attribute, value));
}
}
}

View file

@ -1,132 +1,130 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; 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.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.widget.GridTable; import ch.ethz.seb.sebserver.gui.widget.GridTable;
import ch.ethz.seb.sebserver.gui.widget.GridTable.ColumnDef; import ch.ethz.seb.sebserver.gui.widget.GridTable.ColumnDef;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class InlineTableFieldBuilder implements InputFieldBuilder { public class InlineTableFieldBuilder implements InputFieldBuilder {
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
protected InlineTableFieldBuilder(final WidgetFactory widgetFactory) { protected InlineTableFieldBuilder(final WidgetFactory widgetFactory) {
this.widgetFactory = widgetFactory; this.widgetFactory = widgetFactory;
} }
@Override @Override
public boolean builderFor( public boolean builderFor(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
return attribute != null && attribute.type == AttributeType.INLINE_TABLE; return attribute != null && attribute.type == AttributeType.INLINE_TABLE;
} }
@Override @Override
public InputField createInputField( public InputField createInputField(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
final Orientation orientation = viewContext final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, attribute, orientation); .createInnerGrid(parent, attribute, orientation);
final Map<String, String> defaultValues = StringUtils.isBlank(attribute.defaultValue) final Map<String, String> defaultValues = StringUtils.isBlank(attribute.defaultValue)
? Collections.emptyMap() ? Collections.emptyMap()
: Arrays.asList(StringUtils.split( : Arrays.stream(StringUtils.split(
attribute.defaultValue, attribute.defaultValue,
Constants.EMBEDDED_LIST_SEPARATOR)) Constants.EMBEDDED_LIST_SEPARATOR))
.stream() .map(valueString -> StringUtils.split(
.map(valueString -> StringUtils.split( valueString,
valueString, Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)) .collect(Collectors.toMap(
.collect(Collectors.toMap( valueMap -> valueMap[0],
valueMap -> valueMap[0], valueMap -> (valueMap.length > 1) ? valueMap[1] : StringUtils.EMPTY));
valueMap -> (valueMap.length > 1) ? valueMap[1] : StringUtils.EMPTY));
final List<ColumnDef> columns = Arrays.stream(StringUtils.split(
final List<ColumnDef> columns = Arrays.asList(StringUtils.split( attribute.getResources(),
attribute.getResources(), Constants.EMBEDDED_LIST_SEPARATOR))
Constants.EMBEDDED_LIST_SEPARATOR)) .map(columnString -> ColumnDef.fromString(columnString, defaultValues))
.stream() .collect(Collectors.toList());
.map(columnString -> ColumnDef.fromString(columnString, defaultValues))
.collect(Collectors.toList()); final GridTable gridTable = new GridTable(
innerGrid,
final GridTable gridTable = new GridTable( columns,
innerGrid, ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".",
columns, this.widgetFactory);
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".",
this.widgetFactory); final InlineTableInputField inlineTableInputField = new InlineTableInputField(
attribute,
final InlineTableInputField inlineTableInputField = new InlineTableInputField( viewContext.getOrientation(attribute.id),
attribute, gridTable);
viewContext.getOrientation(attribute.id),
gridTable); if (viewContext.readonly) {
gridTable.setEnabled(false);
if (viewContext.readonly) { gridTable.setListener(event -> {
gridTable.setEnabled(false); });
gridTable.setListener(event -> { } else {
}); gridTable.setListener(event -> viewContext.getValueChangeListener().valueChanged(
} else { viewContext,
gridTable.setListener(event -> viewContext.getValueChangeListener().valueChanged( attribute,
viewContext, inlineTableInputField.getValue(),
attribute, inlineTableInputField.listIndex));
inlineTableInputField.getValue(), }
inlineTableInputField.listIndex));
} return inlineTableInputField;
return inlineTableInputField; }
} static final class InlineTableInputField extends AbstractInputField<GridTable> {
static final class InlineTableInputField extends AbstractInputField<GridTable> { protected InlineTableInputField(
final ConfigurationAttribute attribute,
protected InlineTableInputField( final Orientation orientation,
final ConfigurationAttribute attribute, final GridTable control) {
final Orientation orientation,
final GridTable control) { super(attribute, orientation, control, null);
}
super(attribute, orientation, control, null);
} @Override
public String getValue() {
@Override return this.control.getValue();
public String getValue() { }
return this.control.getValue();
} @Override
protected void setValueToControl(final String value) {
@Override this.control.setValue(value);
protected void setValueToControl(final String value) { }
this.control.setValue(value); }
}
} }
}

View file

@ -1,47 +1,46 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Collection; import java.util.Collection;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; 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.Orientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
@Lazy @Lazy
@Service @Service
@GuiProfile @GuiProfile
public class InputFieldBuilderSupplier { public class InputFieldBuilderSupplier {
private final Collection<InputFieldBuilder> inputFieldBuilder; private final Collection<InputFieldBuilder> inputFieldBuilder;
protected InputFieldBuilderSupplier(final Collection<InputFieldBuilder> inputFieldBuilder) { protected InputFieldBuilderSupplier(final Collection<InputFieldBuilder> inputFieldBuilder) {
this.inputFieldBuilder = inputFieldBuilder; this.inputFieldBuilder = inputFieldBuilder;
inputFieldBuilder inputFieldBuilder
.stream() .forEach(builder -> builder.init(this));
.forEach(builder -> builder.init(this)); }
}
public InputFieldBuilder getInputFieldBuilder(
public InputFieldBuilder getInputFieldBuilder( final ConfigurationAttribute attribute,
final ConfigurationAttribute attribute, final Orientation orientation) {
final Orientation orientation) {
return this.inputFieldBuilder
return this.inputFieldBuilder .stream()
.stream() .filter(b -> b.builderFor(attribute, orientation))
.filter(b -> b.builderFor(attribute, orientation)) .findFirst()
.findFirst() .orElseThrow(() -> new NoSuchElementException("No InputFieldBuilder found for : " + attribute.type));
.orElseThrow(() -> new NoSuchElementException("No InputFieldBuilder found for : " + attribute.type)); }
}
}
}

View file

@ -1,86 +1,86 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; 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.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class LabelBuilder implements InputFieldBuilder { public class LabelBuilder implements InputFieldBuilder {
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
protected LabelBuilder(final WidgetFactory widgetFactory) { protected LabelBuilder(final WidgetFactory widgetFactory) {
this.widgetFactory = widgetFactory; this.widgetFactory = widgetFactory;
} }
@Override @Override
public boolean builderFor( public boolean builderFor(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
return attribute.type == AttributeType.LABEL; return attribute.type == AttributeType.LABEL;
}; }
@Override @Override
public InputField createInputField( public InputField createInputField(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
final Label label = this.widgetFactory.labelLocalized( final Label label = this.widgetFactory.labelLocalized(
parent, parent,
ExamConfigurationService.attributeNameLocKey(attribute)); ExamConfigurationService.attributeNameLocKey(attribute));
return new LabelField( return new LabelField(
attribute, attribute,
viewContext.getOrientation(attribute.id), viewContext.getOrientation(attribute.id),
label); label);
} }
static final class LabelField extends AbstractInputField<Label> { static final class LabelField extends AbstractInputField<Label> {
LabelField( LabelField(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation, final Orientation orientation,
final Label control) { final Label control) {
super(attribute, orientation, control, null); super(attribute, orientation, control, null);
} }
@Override @Override
protected void setValueToControl(final String value) { protected void setValueToControl(final String value) {
// Does Nothing, Label has no default value // Does Nothing, Label has no default value
} }
@Override @Override
public String getValue() { public String getValue() {
return this.control.getText(); return this.control.getText();
} }
} }
} }

View file

@ -104,7 +104,7 @@ public class PasswordFieldBuilder implements InputFieldBuilder {
final CharSequence pwd = passwordInput.getValue(); final CharSequence pwd = passwordInput.getValue();
final CharSequence confirm = confirmInput.getValue(); final CharSequence confirm = confirmInput.getValue();
if (passwordInputField.initValue != null && passwordInputField.initValue.equals(pwd)) { if (passwordInputField.initValue != null && passwordInputField.initValue.contentEquals(pwd)) {
return; return;
} }

View file

@ -1,75 +1,74 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
public abstract class SelectionFieldBuilder { public abstract class SelectionFieldBuilder {
protected List<Tuple<String>> getLocalizedResources( protected List<Tuple<String>> getLocalizedResources(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
return getLocalizedRes(attribute, viewContext, false); return getLocalizedRes(attribute, viewContext, false);
} }
protected List<Tuple<String>> getLocalizedResourcesAsToolTip( protected List<Tuple<String>> getLocalizedResourcesAsToolTip(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
return getLocalizedRes(attribute, viewContext, true); return getLocalizedRes(attribute, viewContext, true);
} }
private List<Tuple<String>> getLocalizedRes( private List<Tuple<String>> getLocalizedRes(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext, final ViewContext viewContext,
final boolean toolTipResources) { final boolean toolTipResources) {
if (attribute == null) { if (attribute == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
final String prefix = final String prefix =
(ConfigurationAttribute.hasDependency( (ConfigurationAttribute.hasDependency(
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY, ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
attribute)) attribute))
? ConfigurationAttribute.getDependencyValue( ? ConfigurationAttribute.getDependencyValue(
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY, ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
attribute) + "." attribute) + "."
: ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + "."; : ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".";
return Arrays.asList(StringUtils.split( return Arrays.stream(StringUtils.split(
attribute.resources, attribute.resources,
Constants.LIST_SEPARATOR)) Constants.LIST_SEPARATOR))
.stream() .map(value -> {
.map(value -> { final String key = prefix + value + ((toolTipResources)
final String key = prefix + value + ((toolTipResources) ? ExamConfigurationService.TOOL_TIP_SUFFIX
? ExamConfigurationService.TOOL_TIP_SUFFIX : "");
: ""); final String text = viewContext.i18nSupport.getText(key, "");
final String text = viewContext.i18nSupport.getText(key, ""); return new Tuple<>(value, (StringUtils.isBlank(text))
return new Tuple<>(value, (StringUtils.isBlank(text)) ? (toolTipResources)
? (toolTipResources) ? text
? text : value
: value : text);
: text); })
}) .collect(Collectors.toList());
.collect(Collectors.toList()); }
}
}
}

View file

@ -1,226 +1,224 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TableItem;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; 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.InputField;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; 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;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class TableFieldBuilder extends AbstractTableFieldBuilder { public class TableFieldBuilder extends AbstractTableFieldBuilder {
private static final String TOOLTIP_SUFFIX = ".tooltip"; private static final String TOOLTIP_SUFFIX = ".tooltip";
private static final String ADD_TOOLTIP_SUFFIX = ".add" + TOOLTIP_SUFFIX; private static final String ADD_TOOLTIP_SUFFIX = ".add" + TOOLTIP_SUFFIX;
private static final String REMOVE_TOOLTIP_SUFFIX = ".remove" + TOOLTIP_SUFFIX; private static final String REMOVE_TOOLTIP_SUFFIX = ".remove" + TOOLTIP_SUFFIX;
protected TableFieldBuilder( protected TableFieldBuilder(
final RestService restService, final RestService restService,
final WidgetFactory widgetFactory) { final WidgetFactory widgetFactory) {
super(restService, widgetFactory); super(restService, widgetFactory);
} }
@Override @Override
public boolean builderFor( public boolean builderFor(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
return AttributeType.TABLE == attribute.type; return AttributeType.TABLE == attribute.type;
} }
@Override @Override
public InputField createInputField( public InputField createInputField(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ViewContext viewContext) { final ViewContext viewContext) {
final TableContext tableContext = createTableContext(attribute, viewContext); final TableContext tableContext = createTableContext(attribute, viewContext);
final Table table = createTable(parent, tableContext); final Table table = createTable(parent, tableContext);
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) { for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
final TableColumn column = this.widgetFactory.tableColumnLocalized( final TableColumn column = this.widgetFactory.tableColumnLocalized(
table, table,
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
columnAttribute.name), columnAttribute.name),
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
columnAttribute.name + columnAttribute.name +
TOOLTIP_SUFFIX)); TOOLTIP_SUFFIX));
column.setWidth(100); column.setWidth(100);
column.setResizable(false); column.setResizable(false);
column.setMoveable(false); column.setMoveable(false);
} }
final TableInputField tableField = new TableInputField( final TableInputField tableField = new TableInputField(
tableContext, tableContext,
table); table);
if (!viewContext.readonly) { if (!viewContext.readonly) {
TableColumn column = new TableColumn(table, SWT.NONE); TableColumn column = new TableColumn(table, SWT.NONE);
column.setImage(ImageIcon.ADD_BOX_WHITE.getImage(parent.getDisplay())); column.setImage(ImageIcon.ADD_BOX_WHITE.getImage(parent.getDisplay()));
column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText( column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
attribute.name + attribute.name +
ADD_TOOLTIP_SUFFIX, ADD_TOOLTIP_SUFFIX,
"Add new"))); "Add new")));
column.setWidth(20); column.setWidth(20);
column.setResizable(false); column.setResizable(false);
column.setMoveable(false); column.setMoveable(false);
column.addListener(SWT.Selection, event -> { column.addListener(SWT.Selection, event -> tableField.addRow());
tableField.addRow();
}); column = new TableColumn(table, SWT.NONE);
column.setImage(ImageIcon.REMOVE_BOX_WHITE.getImage(parent.getDisplay()));
column = new TableColumn(table, SWT.NONE); column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText(
column.setImage(ImageIcon.REMOVE_BOX_WHITE.getImage(parent.getDisplay())); ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText( attribute.name +
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + REMOVE_TOOLTIP_SUFFIX,
attribute.name + "Remove Selected")));
REMOVE_TOOLTIP_SUFFIX, column.setWidth(20);
"Remove Selected"))); column.setResizable(false);
column.setWidth(20); column.setMoveable(false);
column.setResizable(false);
column.setMoveable(false); column.addListener(SWT.Selection, event -> {
final int selectionIndex = table.getSelectionIndex();
column.addListener(SWT.Selection, event -> { if (selectionIndex >= 0) {
final int selectionIndex = table.getSelectionIndex(); tableField.deleteRow(selectionIndex);
if (selectionIndex >= 0) { }
tableField.deleteRow(selectionIndex); });
} }
});
} setSelectionListener(table, tableField);
return tableField;
setSelectionListener(table, tableField); }
return tableField;
} static final class TableInputField extends AbstractTableInputField {
static final class TableInputField extends AbstractTableInputField { private final List<Map<Long, TableValue>> values;
private final List<Map<Long, TableValue>> values; TableInputField(
final TableContext tableContext,
TableInputField( final Table control) {
final TableContext tableContext,
final Table control) { super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
this.values = new ArrayList<>();
super(tableContext.attribute, tableContext.orientation, control, null, tableContext); }
this.values = new ArrayList<>();
} @Override
void initValue(final List<TableValue> tableValues) {
@Override valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
void initValue(final List<TableValue> tableValues) { for (int i = 0; i < this.values.size(); i++) {
valuesFromIndexMap(this.values, createRowIndexMap(tableValues)); addTableRow(i, this.values.get(i));
for (int i = 0; i < this.values.size(); i++) { }
addTableRow(i, this.values.get(i)); }
}
} private void deleteRow(final int selectionIndex) {
this.control.remove(selectionIndex);
private void deleteRow(final int selectionIndex) { this.values.remove(selectionIndex);
this.control.remove(selectionIndex); // send new values to web-service
this.values.remove(selectionIndex); this.tableContext.getValueChangeListener()
// send new values to web-service .tableChanged(extractTableValue(this.values));
this.tableContext.getValueChangeListener() }
.tableChanged(extractTableValue(this.values));
} private void addRow() {
final int index = this.values.size();
private void addRow() { // create new values form default values
final int index = this.values.size(); final Map<Long, TableValue> rowValues = this.tableContext.getRowAttributes()
// create new values form default values .stream()
final Map<Long, TableValue> rowValues = this.tableContext.getRowAttributes() .map(attr -> new TableValue(attr.id, index, attr.defaultValue))
.stream() .collect(Collectors.toMap(
.map(attr -> new TableValue(attr.id, index, attr.defaultValue)) tv -> tv.attributeId,
.collect(Collectors.toMap( Function.identity()));
tv -> tv.attributeId,
Function.identity())); this.values.add(rowValues);
addTableRow(this.values.size() - 1, rowValues);
this.values.add(rowValues); this.control.layout();
addTableRow(this.values.size() - 1, rowValues); // send new values to web-service
this.control.layout(); this.tableContext.getValueChangeListener()
// send new values to web-service .tableChanged(extractTableValue(this.values));
this.tableContext.getValueChangeListener() }
.tableChanged(extractTableValue(this.values));
} protected void addTableRow(final int index, final Map<Long, TableValue> rowValues) {
new TableItem(this.control, SWT.NONE);
protected void addTableRow(final int index, final Map<Long, TableValue> rowValues) { applyTableRowValues(index);
new TableItem(this.control, SWT.NONE); }
applyTableRowValues(index);
} @Override
protected void applyTableRowValues(final int index) {
@Override final TableItem item = this.control.getItem(index);
protected void applyTableRowValues(final int index) { final Map<Long, TableValue> rowValues = this.values.get(index);
final TableItem item = this.control.getItem(index);
final Map<Long, TableValue> rowValues = this.values.get(index); int cellIndex = 0;
for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) {
int cellIndex = 0; if (rowValues.containsKey(attr.id)) {
for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) { final TableValue tableValue = rowValues.get(attr.id);
if (rowValues.containsKey(attr.id)) { setValueToCell(this.tableContext, item, cellIndex, attr, tableValue);
final TableValue tableValue = rowValues.get(attr.id); }
setValueToCell(this.tableContext, item, cellIndex, attr, tableValue); cellIndex++;
} }
cellIndex++; }
}
} @Override
protected void openForm(final int selectionIndex) {
@Override final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
protected void openForm(final int selectionIndex) { final TableRowFormBuilder builder = new TableRowFormBuilder(
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex); this.tableContext,
final TableRowFormBuilder builder = new TableRowFormBuilder( rowValues,
this.tableContext, selectionIndex);
rowValues,
selectionIndex); new ModalInputDialog<Map<Long, TableValue>>(
this.control.getShell(),
new ModalInputDialog<Map<Long, TableValue>>( this.tableContext.getWidgetFactory())
this.control.getShell(), .setDialogWidth(600)
this.tableContext.getWidgetFactory()) .setDialogHeight(550)
.setDialogWidth(600) .open(
.setDialogHeight(550) ExamConfigurationService.getTablePopupTitleKey(
.open( this.attribute,
ExamConfigurationService.getTablePopupTitleKey( this.tableContext.getViewContext().i18nSupport),
this.attribute, (Consumer<Map<Long, TableValue>>) _rowValues -> applyFormValues(
this.tableContext.getViewContext().i18nSupport), this.values,
(Consumer<Map<Long, TableValue>>) rowVals -> applyFormValues( _rowValues,
this.values, selectionIndex),
rowVals, () -> this.tableContext.getValueChangeListener()
selectionIndex), .tableChanged(extractTableValue(this.values)),
() -> this.tableContext.getValueChangeListener() builder);
.tableChanged(extractTableValue(this.values)), }
builder);
} }
} }
}

View file

@ -1,162 +1,160 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; 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.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; 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.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer; import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, TableValue>> { public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, TableValue>> {
private final TableContext tableContext; private final TableContext tableContext;
private final Map<Long, TableValue> rowValues; private final Map<Long, TableValue> rowValues;
private final int listIndex; private final int listIndex;
private final String rowGroupId; private final String rowGroupId;
public TableRowFormBuilder( public TableRowFormBuilder(
final TableContext tableContext, final TableContext tableContext,
final Map<Long, TableValue> rowValues, final Map<Long, TableValue> rowValues,
final int listIndex) { final int listIndex) {
this.tableContext = tableContext; this.tableContext = tableContext;
this.rowValues = rowValues; this.rowValues = rowValues;
this.listIndex = listIndex; this.listIndex = listIndex;
this.rowGroupId = null; this.rowGroupId = null;
} }
public TableRowFormBuilder( public TableRowFormBuilder(
final TableContext tableContext, final TableContext tableContext,
final Map<Long, TableValue> rowValues, final Map<Long, TableValue> rowValues,
final String rowGroupId) { final String rowGroupId) {
this.tableContext = tableContext; this.tableContext = tableContext;
this.rowValues = rowValues; this.rowValues = rowValues;
this.listIndex = 0; this.listIndex = 0;
this.rowGroupId = rowGroupId; this.rowGroupId = rowGroupId;
} }
@Override @Override
public Supplier<Map<Long, TableValue>> compose(final Composite parent) { public Supplier<Map<Long, TableValue>> compose(final Composite parent) {
final Composite grid = PageService.createManagedVScrolledComposite( final Composite grid = PageService.createManagedVScrolledComposite(
parent, parent,
scrolledComposite -> { scrolledComposite -> {
final Composite result = this.tableContext final Composite result = this.tableContext
.getWidgetFactory() .getWidgetFactory()
.formGrid(scrolledComposite, 2); .formGrid(scrolledComposite, 2);
final GridLayout layout = (GridLayout) result.getLayout(); final GridLayout layout = (GridLayout) result.getLayout();
layout.verticalSpacing = 0; layout.verticalSpacing = 0;
return result; return result;
}, },
false); false);
final List<InputField> inputFields = new ArrayList<>(); final List<InputField> inputFields = new ArrayList<>();
for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes(this.rowGroupId)) { for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes(this.rowGroupId)) {
createLabel(grid, attribute); createLabel(grid, attribute);
inputFields.add(createInputField(grid, attribute)); inputFields.add(createInputField(grid, attribute));
} }
for (final InputField inputField : inputFields) { for (final InputField inputField : inputFields) {
final ConfigurationAttribute attribute = inputField.getAttribute(); final ConfigurationAttribute attribute = inputField.getAttribute();
this.tableContext.getValueChangeListener().notifyGUI( this.tableContext.getValueChangeListener().notifyGUI(
this.tableContext.getViewContext(), this.tableContext.getViewContext(),
attribute, attribute,
new ConfigurationValue( new ConfigurationValue(
null, null,
null, null,
null, null,
attribute.id, attribute.id,
this.listIndex, this.listIndex,
inputField.getValue())); inputField.getValue()));
} }
// when the pop-up gets closed we have to remove the input fields from the view context // when the pop-up gets closed we have to remove the input fields from the view context
grid.addDisposeListener(event -> { grid.addDisposeListener(event -> this.tableContext.flushInputFields(this.rowValues.keySet()));
this.tableContext.flushInputFields(this.rowValues.keySet());
}); return () -> inputFields.stream()
.map(field -> (field.hasError())
return () -> inputFields.stream() ? this.rowValues.get(field.getAttribute().id)
.map(field -> (field.hasError()) : new TableValue(
? this.rowValues.get(field.getAttribute().id) field.getAttribute().id,
: new TableValue( this.listIndex,
field.getAttribute().id, field.getValue()))
this.listIndex, .collect(Collectors.toMap(
field.getValue())) tv -> tv.attributeId,
.collect(Collectors.toMap( Function.identity()));
tv -> tv.attributeId, }
Function.identity()));
} private InputField createInputField(
final Composite parent,
private InputField createInputField( final ConfigurationAttribute attribute) {
final Composite parent,
final ConfigurationAttribute attribute) { if (attribute.type == AttributeType.TABLE) {
throw new UnsupportedOperationException(
if (attribute.type == AttributeType.TABLE) { "Table type is currently not supported within a table row form view!");
throw new UnsupportedOperationException( }
"Table type is currently not supported within a table row form view!");
} final Orientation orientation = this.tableContext
.getOrientation(attribute.id);
final Orientation orientation = this.tableContext final InputFieldBuilder inputFieldBuilder = this.tableContext
.getOrientation(attribute.id); .getInputFieldBuilder(attribute, orientation);
final InputFieldBuilder inputFieldBuilder = this.tableContext final InputField inputField = inputFieldBuilder.createInputField(
.getInputFieldBuilder(attribute, orientation); parent,
final InputField inputField = inputFieldBuilder.createInputField( attribute,
parent, this.tableContext.getViewContext());
attribute,
this.tableContext.getViewContext()); final TableValue initValue = this.rowValues.get(attribute.id);
inputField.initValue((initValue != null) ? initValue.value : null, this.listIndex);
final TableValue initValue = this.rowValues.get(attribute.id); // we have to register the input field within the ViewContext to receive error messages
inputField.initValue((initValue != null) ? initValue.value : null, this.listIndex); this.tableContext.registerInputField(inputField);
// we have to register the input field within the ViewContext to receive error messages
this.tableContext.registerInputField(inputField); return inputField;
}
return inputField;
} private void createLabel(
final Composite parent,
private void createLabel( final ConfigurationAttribute attribute) {
final Composite parent,
final ConfigurationAttribute attribute) { final LocTextKey locTextKey = new LocTextKey(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
final LocTextKey locTextKey = new LocTextKey( attribute.name,
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name);
attribute.name, final Label label = this.tableContext
attribute.name); .getWidgetFactory()
final Label label = this.tableContext .labelLocalized(parent, locTextKey);
.getWidgetFactory() final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
.labelLocalized(parent, locTextKey); gridData.verticalIndent = 4;
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); label.setLayoutData(gridData);
gridData.verticalIndent = 4; label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
label.setLayoutData(gridData); }
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
} }
}

View file

@ -1,250 +1,248 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener; import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
public final class ViewContext { public final class ViewContext {
private static final Logger log = LoggerFactory.getLogger(ViewContext.class); private static final Logger log = LoggerFactory.getLogger(ViewContext.class);
private final Configuration configuration; private final Configuration configuration;
private final View view; private final View view;
private final int rows; private final int rows;
final AttributeMapping attributeMapping; final AttributeMapping attributeMapping;
final Map<Long, InputField> inputFieldMapping; final Map<Long, InputField> inputFieldMapping;
final ValueChangeListener valueChangeListener; final ValueChangeListener valueChangeListener;
final I18nSupport i18nSupport; final I18nSupport i18nSupport;
final boolean readonly; final boolean readonly;
ViewContext( ViewContext(
final Configuration configuration, final Configuration configuration,
final View view, final View view,
final int rows, final int rows,
final AttributeMapping attributeContext, final AttributeMapping attributeContext,
final ValueChangeListener valueChangeListener, final ValueChangeListener valueChangeListener,
final I18nSupport i18nSupport, final I18nSupport i18nSupport,
final boolean readonly) { final boolean readonly) {
Objects.requireNonNull(configuration); Objects.requireNonNull(configuration);
Objects.requireNonNull(view); Objects.requireNonNull(view);
Objects.requireNonNull(attributeContext); Objects.requireNonNull(attributeContext);
Objects.requireNonNull(valueChangeListener); Objects.requireNonNull(valueChangeListener);
this.configuration = configuration; this.configuration = configuration;
this.view = view; this.view = view;
this.rows = rows; this.rows = rows;
this.attributeMapping = attributeContext; this.attributeMapping = attributeContext;
this.inputFieldMapping = new HashMap<>(); this.inputFieldMapping = new HashMap<>();
this.valueChangeListener = valueChangeListener; this.valueChangeListener = valueChangeListener;
this.i18nSupport = i18nSupport; this.i18nSupport = i18nSupport;
this.readonly = readonly; this.readonly = readonly;
} }
public I18nSupport getI18nSupport() { public I18nSupport getI18nSupport() {
return this.i18nSupport; return this.i18nSupport;
} }
public Long getId() { public Long getId() {
return this.view.id; return this.view.id;
} }
public String getName() { public String getName() {
return this.view.name; return this.view.name;
} }
public Long getConfigurationId() { public Long getConfigurationId() {
return this.configuration.id; return this.configuration.id;
} }
public Long getInstitutionId() { public Long getInstitutionId() {
return this.configuration.institutionId; return this.configuration.institutionId;
} }
public int getColumns() { public int getColumns() {
return this.view.columns; return this.view.columns;
} }
public int getRows() { public int getRows() {
return this.rows; return this.rows;
} }
public Configuration getConfiguration() { public Configuration getConfiguration() {
return this.configuration; return this.configuration;
} }
public View getView() { public View getView() {
return this.view; return this.view;
} }
public Collection<ConfigurationAttribute> getChildAttributes(final Long id) { public Collection<ConfigurationAttribute> getChildAttributes(final Long id) {
return this.attributeMapping.childAttributeMapping.get(id); return this.attributeMapping.childAttributeMapping.get(id);
} }
public Collection<ConfigurationAttribute> getAttributes() { public Collection<ConfigurationAttribute> getAttributes() {
return this.attributeMapping.getAttributes(); return this.attributeMapping.getAttributes();
} }
public ConfigurationAttribute getAttribute(final Long attributeId) { public ConfigurationAttribute getAttribute(final Long attributeId) {
return this.attributeMapping.getAttribute(attributeId); return this.attributeMapping.getAttribute(attributeId);
} }
public Long getAttributeIdByName(final String name) { public Long getAttributeIdByName(final String name) {
return this.attributeMapping.attributeNameIdMapping.get(name); return this.attributeMapping.attributeNameIdMapping.get(name);
} }
public ConfigurationAttribute getAttributeByName(final String name) { public ConfigurationAttribute getAttributeByName(final String name) {
final Long attributeId = this.attributeMapping.attributeNameIdMapping.get(name); final Long attributeId = this.attributeMapping.attributeNameIdMapping.get(name);
if (attributeId != null) { if (attributeId != null) {
return getAttribute(attributeId); return getAttribute(attributeId);
} }
return null; return null;
} }
public Collection<Orientation> getOrientationsOfGroup(final ConfigurationAttribute attribute) { public Collection<Orientation> getOrientationsOfGroup(final ConfigurationAttribute attribute) {
return this.attributeMapping.getOrientationsOfGroup(attribute); return this.attributeMapping.getOrientationsOfGroup(attribute);
} }
public Orientation getOrientation(final Long attributeId) { public Orientation getOrientation(final Long attributeId) {
return this.attributeMapping.getOrientation(attributeId); return this.attributeMapping.getOrientation(attributeId);
} }
public ValueChangeListener getValueChangeListener() { public ValueChangeListener getValueChangeListener() {
return this.valueChangeListener; return this.valueChangeListener;
} }
public void disable(final String attributeName) { public void disable(final String attributeName) {
disable(this.getAttributeIdByName(attributeName)); disable(this.getAttributeIdByName(attributeName));
} }
public void disable(final Long attributeId) { public void disable(final Long attributeId) {
final InputField inputField = this.inputFieldMapping.get(attributeId); final InputField inputField = this.inputFieldMapping.get(attributeId);
if (inputField == null) { if (inputField == null) {
return; return;
} }
inputField.disable(false); inputField.disable(false);
} }
public void enable(final String attributeName) { public void enable(final String attributeName) {
enable(this.getAttributeIdByName(attributeName)); enable(this.getAttributeIdByName(attributeName));
} }
public void enable(final Long attributeId) { public void enable(final Long attributeId) {
final InputField inputField = this.inputFieldMapping.get(attributeId); final InputField inputField = this.inputFieldMapping.get(attributeId);
if (inputField == null) { if (inputField == null) {
return; return;
} }
inputField.enable(false); inputField.enable(false);
} }
public void disableGroup(final String attributeName) { public void disableGroup(final String attributeName) {
disableGroup(this.getAttributeIdByName(attributeName)); disableGroup(this.getAttributeIdByName(attributeName));
} }
public void disableGroup(final Long attributeId) { public void disableGroup(final Long attributeId) {
final InputField inputField = this.inputFieldMapping.get(attributeId); final InputField inputField = this.inputFieldMapping.get(attributeId);
if (inputField == null) { if (inputField == null) {
return; return;
} }
inputField.disable(true); inputField.disable(true);
try { try {
this.attributeMapping.attributeGroupMapping this.attributeMapping.attributeGroupMapping
.get(inputField.getOrientation().groupId) .get(inputField.getOrientation().groupId)
.stream() .stream()
.map(ConfigurationAttribute::getId) .map(ConfigurationAttribute::getId)
.map(this.inputFieldMapping::get) .map(this.inputFieldMapping::get)
.forEach(InputField::setDefaultValue); .forEach(InputField::setDefaultValue);
} catch (final Exception e) { } catch (final Exception e) {
log.warn("Failed to send attribute value update to server: ", e); log.warn("Failed to send attribute value update to server: ", e);
} }
} }
public void enableGroup(final String attributeName) { public void enableGroup(final String attributeName) {
enableGroup(this.getAttributeIdByName(attributeName)); enableGroup(this.getAttributeIdByName(attributeName));
} }
public void enableGroup(final Long attributeId) { public void enableGroup(final Long attributeId) {
final InputField inputField = this.inputFieldMapping.get(attributeId); final InputField inputField = this.inputFieldMapping.get(attributeId);
if (inputField == null) { if (inputField == null) {
return; return;
} }
inputField.enable(true); inputField.enable(true);
} }
public void showError(final Long attributeId, final String errorMessage) { public void showError(final Long attributeId, final String errorMessage) {
final InputField inputField = this.inputFieldMapping.get(attributeId); final InputField inputField = this.inputFieldMapping.get(attributeId);
if (inputField == null) { if (inputField == null) {
return; return;
} }
inputField.showError(errorMessage); inputField.showError(errorMessage);
} }
public void clearError(final Long attributeId) { public void clearError(final Long attributeId) {
final InputField inputField = this.inputFieldMapping.get(attributeId); final InputField inputField = this.inputFieldMapping.get(attributeId);
if (inputField == null) { if (inputField == null) {
return; return;
} }
inputField.clearError(); inputField.clearError();
} }
public void registerInputField(final InputField inputField) { public void registerInputField(final InputField inputField) {
this.inputFieldMapping.put( this.inputFieldMapping.put(
inputField.getAttribute().id, inputField.getAttribute().id,
inputField); inputField);
} }
void setValuesToInputFields(final Collection<ConfigurationValue> values) { void setValuesToInputFields(final Collection<ConfigurationValue> values) {
this.inputFieldMapping this.inputFieldMapping
.values() .values()
.stream() .forEach(field -> {
.forEach(field -> { final ConfigurationValue initValue = field.initValue(values);
final ConfigurationValue initValue = field.initValue(values); if (initValue != null) {
if (initValue != null) { this.valueChangeListener.notifyGUI(this, field.getAttribute(), initValue);
this.valueChangeListener.notifyGUI(this, field.getAttribute(), initValue); }
} });
}); }
}
/** Removes all registered InputFields with the given attribute ids
/** Removes all registered InputFields with the given attribute ids *
* * @param values Collection of attribute ids */
* @param values Collection of attribute ids */ void flushInputFields(final Collection<Long> values) {
void flushInputFields(final Collection<Long> values) { if (values == null) {
if (values == null) { return;
return; }
}
values.forEach(this.inputFieldMapping::remove);
values.stream() }
.forEach(attrId -> this.inputFieldMapping.remove(attrId));
} }
}

View file

@ -1,213 +1,213 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl; package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.GroupCellFieldBuilderAdapter; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.GroupCellFieldBuilderAdapter;
public class ViewGridBuilder { public class ViewGridBuilder {
private static final Logger log = LoggerFactory.getLogger(ViewGridBuilder.class); private static final Logger log = LoggerFactory.getLogger(ViewGridBuilder.class);
final ExamConfigurationService examConfigurationService; final ExamConfigurationService examConfigurationService;
final Composite parent; final Composite parent;
final ViewContext viewContext; final ViewContext viewContext;
private final CellFieldBuilderAdapter[][] grid; private final CellFieldBuilderAdapter[][] grid;
private final GroupCellFieldBuilderAdapter groupBuilderAdapter; private final GroupCellFieldBuilderAdapter groupBuilderAdapter;
private final Set<String> registeredGroups; private final Set<String> registeredGroups;
ViewGridBuilder( ViewGridBuilder(
final Composite parent, final Composite parent,
final ViewContext viewContext, final ViewContext viewContext,
final ExamConfigurationService examConfigurationService) { final ExamConfigurationService examConfigurationService) {
this.examConfigurationService = examConfigurationService; this.examConfigurationService = examConfigurationService;
this.parent = parent; this.parent = parent;
this.viewContext = viewContext; this.viewContext = viewContext;
this.grid = new CellFieldBuilderAdapter[viewContext.getRows()][viewContext.getColumns()]; this.grid = new CellFieldBuilderAdapter[viewContext.getRows()][viewContext.getColumns()];
this.groupBuilderAdapter = null; this.groupBuilderAdapter = null;
this.registeredGroups = new HashSet<>(); this.registeredGroups = new HashSet<>();
} }
ViewGridBuilder( ViewGridBuilder(
final Composite parent, final Composite parent,
final ViewContext viewContext, final ViewContext viewContext,
final GroupCellFieldBuilderAdapter groupBuilderAdapter, final GroupCellFieldBuilderAdapter groupBuilderAdapter,
final ExamConfigurationService examConfigurationService) { final ExamConfigurationService examConfigurationService) {
this.examConfigurationService = examConfigurationService; this.examConfigurationService = examConfigurationService;
this.parent = parent; this.parent = parent;
this.viewContext = viewContext; this.viewContext = viewContext;
this.groupBuilderAdapter = groupBuilderAdapter; this.groupBuilderAdapter = groupBuilderAdapter;
this.grid = new CellFieldBuilderAdapter[groupBuilderAdapter.height - 1][groupBuilderAdapter.width]; this.grid = new CellFieldBuilderAdapter[groupBuilderAdapter.height - 1][groupBuilderAdapter.width];
this.registeredGroups = null; this.registeredGroups = null;
} }
ViewGridBuilder add(final ConfigurationAttribute attribute) { ViewGridBuilder add(final ConfigurationAttribute attribute) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Add SEB Configuration Attribute: " + attribute); log.debug("Add SEB Configuration Attribute: " + attribute);
} }
// ignore nested attributes here (if not propagated to show up in view) // ignore nested attributes here (if not propagated to show up in view)
if (attribute.parentId != null && if (attribute.parentId != null &&
!BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue( !BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue(
ConfigurationAttribute.DEPENDENCY_SHOW_IN_VIEW, ConfigurationAttribute.DEPENDENCY_SHOW_IN_VIEW,
attribute))) { attribute))) {
return this; return this;
} }
final Orientation orientation = this.viewContext final Orientation orientation = this.viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
// create group if this is not a group builder // create group if this is not a group builder
if (this.groupBuilderAdapter == null && StringUtils.isNotBlank(orientation.groupId)) { if (this.groupBuilderAdapter == null && StringUtils.isNotBlank(orientation.groupId)) {
if (this.registeredGroups.contains(orientation.groupId)) { if (this.registeredGroups.contains(orientation.groupId)) {
return this; return this;
} }
final GroupCellFieldBuilderAdapter groupBuilder = final GroupCellFieldBuilderAdapter groupBuilder =
new GroupCellFieldBuilderAdapter(this.viewContext.getOrientationsOfGroup(attribute)); new GroupCellFieldBuilderAdapter(this.viewContext.getOrientationsOfGroup(attribute));
fillDummy(groupBuilder.x, groupBuilder.y, groupBuilder.width, groupBuilder.height); fillDummy(groupBuilder.x, groupBuilder.y, groupBuilder.width, groupBuilder.height);
this.grid[groupBuilder.y][groupBuilder.x] = groupBuilder; this.grid[groupBuilder.y][groupBuilder.x] = groupBuilder;
this.registeredGroups.add(orientation.groupId); this.registeredGroups.add(orientation.groupId);
return this; return this;
} }
// create single input field with label // create single input field with label
final int xpos = orientation.xpos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.x : 0); final int xpos = orientation.xpos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.x : 0);
final int ypos = orientation.ypos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.y : 0); final int ypos = orientation.ypos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.y : 0);
if (orientation.width > 1 || orientation.height > 1) { if (orientation.width > 1 || orientation.height > 1) {
fillDummy(xpos, ypos, orientation.width, orientation.height); fillDummy(xpos, ypos, orientation.width, orientation.height);
} }
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder( final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
attribute, attribute,
orientation); orientation);
this.grid[ypos][xpos] = CellFieldBuilderAdapter.fieldBuilderAdapter( this.grid[ypos][xpos] = CellFieldBuilderAdapter.fieldBuilderAdapter(
inputFieldBuilder, inputFieldBuilder,
attribute); attribute);
try { try {
switch (orientation.title) { switch (orientation.title) {
case RIGHT: case RIGHT:
case RIGHT_SPAN: { case RIGHT_SPAN: {
this.grid[ypos][xpos + 1] = CellFieldBuilderAdapter.labelBuilder( this.grid[ypos][xpos + 1] = CellFieldBuilderAdapter.labelBuilder(
attribute, attribute,
orientation); orientation);
break; break;
} }
case LEFT: case LEFT:
case LEFT_SPAN: { case LEFT_SPAN: {
this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder( this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder(
attribute, attribute,
orientation); orientation);
// special case for password, also add confirm label // special case for password, also add confirm label
if (attribute.type == AttributeType.PASSWORD_FIELD) { if (attribute.type == AttributeType.PASSWORD_FIELD) {
this.grid[ypos + 1][xpos - 1] = CellFieldBuilderAdapter.passwordConfirmLabel( this.grid[ypos + 1][xpos - 1] = CellFieldBuilderAdapter.passwordConfirmLabel(
attribute, attribute,
orientation); orientation);
} }
break; break;
} }
case TOP: { case TOP: {
fillDummy(xpos, ypos - 1, orientation.width, 1); fillDummy(xpos, ypos - 1, orientation.width, 1);
this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder( this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder(
attribute, attribute,
orientation); orientation);
break; break;
} }
default: { default: {
// do nothing // do nothing
break; break;
} }
} }
} catch (final ArrayIndexOutOfBoundsException e) { } catch (final ArrayIndexOutOfBoundsException e) {
log.error("Failed to set title as configured in: {} for attribute: {}", orientation, attribute, e); log.error("Failed to set title as configured in: {} for attribute: {}", orientation, attribute, e);
} }
return this; return this;
} }
void compose() { void compose() {
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
log.trace("Compose grid view: \n" + gridToString()); log.trace("Compose grid view: \n" + gridToString());
} }
// balance grid (optimize span and grab empty spaces for labels where applicable) // balance grid (optimize span and grab empty spaces for labels where applicable)
for (int y = 0; y < this.grid.length; y++) { for (int y = 0; y < this.grid.length; y++) {
for (int x = 0; x < this.grid[y].length; x++) { for (int x = 0; x < this.grid[y].length; x++) {
if (this.grid[y][x] != null) { if (this.grid[y][x] != null) {
this.grid[y][x].balanceGrid(this.grid, x, y); this.grid[y][x].balanceGrid(this.grid, x, y);
} }
} }
} }
for (int y = 0; y < this.grid.length; y++) { for (int y = 0; y < this.grid.length; y++) {
for (int x = 0; x < this.grid[y].length; x++) { for (int x = 0; x < this.grid[y].length; x++) {
if (this.grid[y][x] == null) { if (this.grid[y][x] == null) {
final Label empty = new Label(this.parent, SWT.LEFT); final Label empty = new Label(this.parent, SWT.LEFT);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
gridData.verticalIndent = 8; gridData.verticalIndent = 8;
empty.setLayoutData(gridData); empty.setLayoutData(gridData);
empty.setText(StringUtils.EMPTY /* "empty " + x + " " + y */); empty.setText(StringUtils.EMPTY /* "empty " + x + " " + y */);
} else { } else {
this.grid[y][x].createCell(this); this.grid[y][x].createCell(this);
} }
} }
} }
} }
private void fillDummy(final int x, final int y, final int width, final int height) { private void fillDummy(final int x, final int y, final int width, final int height) {
final int upperBoundX = x + width; final int upperBoundX = x + width;
final int upperBoundY = y + height; final int upperBoundY = y + height;
for (int _y = y; _y < upperBoundY; _y++) { for (int _y = y; _y < upperBoundY; _y++) {
for (int _x = x; _x < upperBoundX; _x++) { for (int _x = x; _x < upperBoundX; _x++) {
if (_y < 0 || _x < 0 || _y >= this.grid.length || _x >= this.grid[_y].length) { if (_y < 0 || _x < 0 || _y >= this.grid.length || _x >= this.grid[_y].length) {
log.warn("Out of bounds: {} {}", _x, _y); log.warn("Out of bounds: {} {}", _x, _y);
continue; continue;
} }
this.grid[_y][_x] = CellFieldBuilderAdapter.DUMMY_BUILDER_ADAPTER; this.grid[_y][_x] = CellFieldBuilderAdapter.DUMMY_BUILDER_ADAPTER;
} }
} }
} }
private String gridToString() { private String gridToString() {
final StringBuffer sb = new StringBuffer(); final StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.grid.length; i++) { for (int i = 0; i < this.grid.length; i++) {
if (sb.length() > 0) { if (sb.length() > 0) {
sb.append(",\n"); sb.append(",\n");
} }
sb.append(Arrays.toString(this.grid[i])); sb.append(Arrays.toString(this.grid[i]));
} }
return sb.toString(); return sb.toString();
} }
} }

View file

@ -1,78 +1,74 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.examconfig.impl.rules; package ch.ethz.seb.sebserver.gui.service.examconfig.impl.rules;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule; import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
@Lazy @Lazy
@Service @Service
@GuiProfile @GuiProfile
public class BrowserViewModeRule implements ValueChangeRule { public class BrowserViewModeRule implements ValueChangeRule {
private static final Logger log = LoggerFactory.getLogger(BrowserViewModeRule.class); private static final Logger log = LoggerFactory.getLogger(BrowserViewModeRule.class);
public static final String KEY_BROWSER_VIEW_MODE = "browserViewMode"; public static final String KEY_BROWSER_VIEW_MODE = "browserViewMode";
public static final String KEY_TOUCH_EXIT = "enableTouchExit"; public static final String KEY_TOUCH_EXIT = "enableTouchExit";
public static final String KEY_MAIN_WINDOW_GROUP = "mainBrowserWindowWidth"; public static final String KEY_MAIN_WINDOW_GROUP = "mainBrowserWindowWidth";
@Override @Override
public boolean observesAttribute(final ConfigurationAttribute attribute) { public boolean observesAttribute(final ConfigurationAttribute attribute) {
return KEY_BROWSER_VIEW_MODE.equals(attribute.name); return KEY_BROWSER_VIEW_MODE.equals(attribute.name);
} }
@Override @Override
public void applyRule( public void applyRule(
final ViewContext context, final ViewContext context,
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final ConfigurationValue value) { final ConfigurationValue value) {
if (StringUtils.isBlank(value.value)) { if (StringUtils.isBlank(value.value)) {
return; return;
} }
try { try {
context.enable(KEY_TOUCH_EXIT); context.enable(KEY_TOUCH_EXIT);
context.enableGroup(KEY_MAIN_WINDOW_GROUP); context.enableGroup(KEY_MAIN_WINDOW_GROUP);
switch (Integer.parseInt(value.value)) { switch (Integer.parseInt(value.value)) {
case 0: { case 1: {
context.disable(KEY_TOUCH_EXIT); context.disable(KEY_TOUCH_EXIT);
break; context.disableGroup(KEY_MAIN_WINDOW_GROUP);
} break;
case 1: { }
context.disable(KEY_TOUCH_EXIT); case 2: {
context.disableGroup(KEY_MAIN_WINDOW_GROUP); context.disableGroup(KEY_MAIN_WINDOW_GROUP);
break; break;
} }
case 2: { default: {
context.disableGroup(KEY_MAIN_WINDOW_GROUP); context.disable(KEY_TOUCH_EXIT);
break; break;
} }
default: { }
context.disable(KEY_TOUCH_EXIT); } catch (final Exception e) {
break; log.warn("Failed to apply rule: ", e);
} }
}
} catch (final Exception e) { }
log.warn("Failed to apply rule: ", e);
} }
}
}

View file

@ -17,10 +17,10 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
public interface I18nSupport { public interface I18nSupport {
public static final String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages"; String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages";
public static final String MULTILINGUAL_KEY = "sebserver.gui.multilingual"; String MULTILINGUAL_KEY = "sebserver.gui.multilingual";
public static final String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat"; String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat";
public static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE"; String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE";
/** Get all supported languages as a collection of Locale /** Get all supported languages as a collection of Locale
* *
@ -40,7 +40,7 @@ public interface I18nSupport {
Locale getUsersFormatLocale(); Locale getUsersFormatLocale();
/** Format a DateTime to a text format to display. /** Format a DateTime to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.date.display format'
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
* *
* Adds time-zone offset information if the currents user time-zone is different form UTC * Adds time-zone offset information if the currents user time-zone is different form UTC
@ -50,7 +50,7 @@ public interface I18nSupport {
String formatDisplayDate(DateTime date); String formatDisplayDate(DateTime date);
/** Format a DateTime to a text format to display with additional time zone name at the end. /** Format a DateTime to a text format to display with additional time zone name at the end.
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.date.display format'
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
* *
* Adds time-zone offset information if the currents user time-zone is different form UTC * Adds time-zone offset information if the currents user time-zone is different form UTC
@ -62,19 +62,19 @@ public interface I18nSupport {
} }
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.date.display format'
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param timestamp the unix-timestamp in milliseconds
* @return date formatted date String to display */ * @return date formatted date String to display */
default String formatDisplayDate(final Long timestamp) { default String formatDisplayDate(final Long timestamp) {
return formatDisplayDate(Utils.toDateTimeUTC(timestamp)); return formatDisplayDate(Utils.toDateTimeUTC(timestamp));
} }
/** Format a DateTime to a text format to display. /** Format a DateTime to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.datetime.display format'
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
@ -84,19 +84,19 @@ public interface I18nSupport {
String formatDisplayDateTime(DateTime date); String formatDisplayDateTime(DateTime date);
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.datetime.display format'
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param timestamp the unix-timestamp in milliseconds
* @return date formatted date time String to display */ * @return date formatted date time String to display */
default String formatDisplayDateTime(final Long timestamp) { default String formatDisplayDateTime(final Long timestamp) {
return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp)); return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp));
} }
/** Format a DateTime to a text format to display. /** Format a DateTime to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.time.display format'
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
@ -106,12 +106,12 @@ public interface I18nSupport {
String formatDisplayTime(DateTime date); String formatDisplayTime(DateTime date);
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.time.display format'
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param timestamp the unix-timestamp in milliseconds
* @return date formatted time String to display */ * @return date formatted time String to display */
default String formatDisplayTime(final Long timestamp) { default String formatDisplayTime(final Long timestamp) {
return formatDisplayTime(Utils.toDateTimeUTC(timestamp)); return formatDisplayTime(Utils.toDateTimeUTC(timestamp));

View file

@ -39,34 +39,116 @@ public interface PolyglotPageService {
* @param locale the Locale to set */ * @param locale the Locale to set */
void setPageLocale(Composite root, Locale locale); void setPageLocale(Composite root, Locale locale);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param imageUpload the Control instance
* @param locTextKey the localized text key to inject
*/
void injectI18n(ImageUploadSelection imageUpload, LocTextKey locTextKey); void injectI18n(ImageUploadSelection imageUpload, LocTextKey locTextKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param label the Control instance
* @param locTextKey the localized text key to inject
*/
void injectI18n(Label label, LocTextKey locTextKey); void injectI18n(Label label, LocTextKey locTextKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param label the Control instance
* @param locTextKey the localized text key to inject
* @param locToolTipKey the localized text key for the tooltip to inject
*/
void injectI18n(Label label, LocTextKey locTextKey, LocTextKey locToolTipKey); void injectI18n(Label label, LocTextKey locTextKey, LocTextKey locToolTipKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param group the Control instance
* @param locTextKey the localized text key to inject
* @param locTooltipKey the localized text key for the tooltip to inject
*/
void injectI18n(Group group, LocTextKey locTextKey, LocTextKey locTooltipKey); void injectI18n(Group group, LocTextKey locTextKey, LocTextKey locTooltipKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param button the Control instance
* @param locTextKey the localized text key to inject
*/
void injectI18n(Button button, LocTextKey locTextKey); void injectI18n(Button button, LocTextKey locTextKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param button the Control instance
* @param locTextKey the localized text key to inject
* @param locToolTipKey the localized text key for the tooltip to inject
*/
void injectI18n(Button button, LocTextKey locTextKey, LocTextKey locToolTipKey); void injectI18n(Button button, LocTextKey locTextKey, LocTextKey locToolTipKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param tree the Control instance
*/
void injectI18n(Tree tree); void injectI18n(Tree tree);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param treeItem the Control instance
* @param locTextKey the localized text key to inject
*/
void injectI18n(TreeItem treeItem, LocTextKey locTextKey); void injectI18n(TreeItem treeItem, LocTextKey locTextKey);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param table the Control instance
*/
void injectI18n(Table table); void injectI18n(Table table);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param tabFolder the Control instance
*/
void injectI18n(TabFolder tabFolder); void injectI18n(TabFolder tabFolder);
/** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param tableColumn the Control instance
* @param locTextKey the localized text key to inject
* @param locTooltipKey the localized text key for the tooltip to inject
*/
void injectI18n(TableColumn tableColumn, LocTextKey locTextKey, LocTextKey locTooltipKey); void injectI18n(TableColumn tableColumn, LocTextKey locTextKey, LocTextKey locTooltipKey);
void injectI18n(TableItem tableItem, LocTextKey... locTextKey); /** Used to inject a localised text within the given Control (Widget) that automatically gets changed on language
* change.
*
* @param tabItem the Control instance
* @param locTextKey the localized text key to inject
* @param locTooltipKey the localized text key for the tooltip to inject
*/
void injectI18n(TabItem tabItem, LocTextKey locTextKey, LocTextKey locTooltipKey); void injectI18n(TabItem tabItem, LocTextKey locTextKey, LocTextKey locTooltipKey);
/** Used to inject a localised tooltip text within the given Control (Widget) that automatically gets changed on
* language change.
*
* @param control the Control instance
* @param locTooltipKey the localized text key for the tooltip to inject
*/
void injectI18nTooltip(Control control, LocTextKey locTooltipKey); void injectI18nTooltip(Control control, LocTextKey locTooltipKey);
/** Used to create the page language selector if needed
*
* @param composerCtx the PageContext
*/
void createLanguageSelector(PageContext composerCtx); void createLanguageSelector(PageContext composerCtx);
} }

View file

@ -1,186 +1,185 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.i18n.impl; package ch.ethz.seb.sebserver.gui.service.i18n.impl;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@Lazy @Lazy
@Service @Service
@GuiProfile @GuiProfile
public class I18nSupportImpl implements I18nSupport { public class I18nSupportImpl implements I18nSupport {
private static final Logger log = LoggerFactory.getLogger(I18nSupportImpl.class); private static final Logger log = LoggerFactory.getLogger(I18nSupportImpl.class);
private final Locale defaultFormatLocale; private final Locale defaultFormatLocale;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final MessageSource messageSource; private final MessageSource messageSource;
private final Locale defaultLocale = Locale.ENGLISH; private final Locale defaultLocale = Locale.ENGLISH;
private final Collection<Locale> supportedLanguages; private final Collection<Locale> supportedLanguages;
public I18nSupportImpl( public I18nSupportImpl(
final CurrentUser currentUser, final CurrentUser currentUser,
final MessageSource messageSource, final MessageSource messageSource,
final Environment environment) { final Environment environment) {
this.currentUser = currentUser; this.currentUser = currentUser;
this.messageSource = messageSource; this.messageSource = messageSource;
final String defaultForamtLocaleString = environment.getProperty( final String defaultFormatLocaleString = environment.getProperty(
FORMAL_LOCALE_KEY, FORMAL_LOCALE_KEY,
Constants.DEFAULT_LANG_CODE); Constants.DEFAULT_LANG_CODE);
this.defaultFormatLocale = Locale.forLanguageTag(defaultForamtLocaleString); this.defaultFormatLocale = Locale.forLanguageTag(defaultFormatLocaleString);
final boolean multilingual = BooleanUtils.toBoolean(environment.getProperty( final boolean multilingual = BooleanUtils.toBoolean(environment.getProperty(
MULTILINGUAL_KEY, MULTILINGUAL_KEY,
Constants.FALSE_STRING)); Constants.FALSE_STRING));
if (multilingual) { if (multilingual) {
final String languagesString = environment.getProperty( final String languagesString = environment.getProperty(
SUPPORTED_LANGUAGES_KEY, SUPPORTED_LANGUAGES_KEY,
Locale.ENGLISH.getLanguage()); Locale.ENGLISH.getLanguage());
this.supportedLanguages = Utils.immutableCollectionOf( this.supportedLanguages = Utils.immutableCollectionOf(
Arrays.asList(StringUtils.split(languagesString, Constants.LIST_SEPARATOR)) Arrays.stream(StringUtils.split(languagesString, Constants.LIST_SEPARATOR))
.stream() .map(Locale::forLanguageTag)
.map(s -> Locale.forLanguageTag(s)) .collect(Collectors.toList()));
.collect(Collectors.toList()));
} else {
} else { this.supportedLanguages = Utils.immutableCollectionOf(Locale.ENGLISH);
this.supportedLanguages = Utils.immutableCollectionOf(Locale.ENGLISH); }
}
}
}
@Override
@Override public Collection<Locale> supportedLanguages() {
public Collection<Locale> supportedLanguages() { return this.supportedLanguages;
return this.supportedLanguages; }
}
@Override
@Override public Locale getUsersFormatLocale() {
public Locale getUsersFormatLocale() { // TODO here also a user based format locale can be verified on the future
// TODO here also a user based format locale can be verified on the future return this.defaultFormatLocale;
return this.defaultFormatLocale; }
}
@Override
@Override public Locale getUsersLanguageLocale() {
public Locale getUsersLanguageLocale() { // first session-locale if available
// first session-locale if available try {
try { final Locale sessionLocale = (Locale) RWT.getUISession()
final Locale sessionLocale = (Locale) RWT.getUISession() .getHttpSession()
.getHttpSession() .getAttribute(ATTR_CURRENT_SESSION_LOCALE);
.getAttribute(ATTR_CURRENT_SESSION_LOCALE); if (sessionLocale != null) {
if (sessionLocale != null) { return sessionLocale;
return sessionLocale; }
} } catch (final IllegalStateException e) {
} catch (final IllegalStateException e) { log.warn("Get current locale for session failed: {}", e.getMessage());
log.warn("Get current locale for session failed: {}", e.getMessage()); }
}
// second user-locale if available
// second user-locale if available if (this.currentUser.isAvailable()) {
if (this.currentUser.isAvailable()) { return this.currentUser.get().language;
return this.currentUser.get().language; }
}
// last the default locale
// last the default locale return this.defaultLocale;
return this.defaultLocale; }
}
@Override
@Override public String formatDisplayDate(final DateTime date) {
public String formatDisplayDate(final DateTime date) { final String pattern = DateTimeFormat.patternForStyle("M-", getUsersFormatLocale());
final String pattern = DateTimeFormat.patternForStyle("M-", getUsersFormatLocale()); return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern)); }
}
@Override
@Override public String formatDisplayDateTime(final DateTime date) {
public String formatDisplayDateTime(final DateTime date) { final String pattern = DateTimeFormat.patternForStyle("MS", getUsersFormatLocale());
final String pattern = DateTimeFormat.patternForStyle("MS", getUsersFormatLocale()); return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern)); }
}
@Override
@Override public String formatDisplayTime(final DateTime date) {
public String formatDisplayTime(final DateTime date) { final String pattern = DateTimeFormat.patternForStyle("-S", getUsersFormatLocale());
final String pattern = DateTimeFormat.patternForStyle("-S", getUsersFormatLocale()); return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern)); }
}
@Override
@Override public String getUsersTimeZoneTitleSuffix() {
public String getUsersTimeZoneTitleSuffix() { final UserInfo userInfo = this.currentUser.get();
final UserInfo userInfo = this.currentUser.get(); if (userInfo.timeZone == null || userInfo.timeZone.equals(DateTimeZone.UTC)) {
if (userInfo.timeZone == null || userInfo.timeZone.equals(DateTimeZone.UTC)) { return "";
return ""; } else {
} else { return "(" + this.currentUser.get().timeZone.getID() + ")";
return "(" + this.currentUser.get().timeZone.getID() + ")"; }
} }
}
@Override
@Override public String getText(final String key, final String def, final Object... args) {
public String getText(final String key, final String def, final Object... args) { return this.messageSource.getMessage(key, args, def, this.getUsersLanguageLocale());
return this.messageSource.getMessage(key, args, def, this.getUsersLanguageLocale()); }
}
@Override
@Override public String getText(final String key, final Locale locale, final String def, final Object... args) {
public String getText(final String key, final Locale locale, final String def, final Object... args) { return this.messageSource.getMessage(key, args, def, locale);
return this.messageSource.getMessage(key, args, def, locale); }
}
@Override
@Override public boolean hasText(final LocTextKey key) {
public boolean hasText(final LocTextKey key) { if (key == null) {
if (key == null) { return false;
return false; }
}
return StringUtils.isNotBlank(getText(key.name, (String) null));
return StringUtils.isNotBlank(getText(key.name, (String) null)); }
}
private String formatDisplayDate(final DateTime date, final DateTimeFormatter formatter) {
private String formatDisplayDate(final DateTime date, final DateTimeFormatter formatter) { if (date == null) {
if (date == null) { return Constants.EMPTY_NOTE;
return Constants.EMPTY_NOTE; }
}
DateTime dateUTC = date;
DateTime dateUTC = date; if (date.getZone() != DateTimeZone.UTC) {
if (date.getZone() != DateTimeZone.UTC) { log.warn("Date that has not UTC timezone used. "
log.warn("Date that has not UTC timezone used. " + "Reset to UTC timezone with any change on time instance for further processing");
+ "Reset to UTC timezone with any change on time instance for further processing"); dateUTC = date.withZone(DateTimeZone.UTC);
dateUTC = date.withZone(DateTimeZone.UTC); }
}
final UserInfo userInfo = this.currentUser.get();
final UserInfo userInfo = this.currentUser.get(); if (userInfo != null && userInfo.timeZone != null && !userInfo.timeZone.equals(DateTimeZone.UTC)) {
if (userInfo != null && userInfo.timeZone != null && !userInfo.timeZone.equals(DateTimeZone.UTC)) { return dateUTC.toString(formatter.withZone(userInfo.timeZone));
return dateUTC.toString(formatter.withZone(userInfo.timeZone)); } else {
} else { return dateUTC.toString(formatter);
return dateUTC.toString(formatter); }
} }
}
}
}

View file

@ -165,18 +165,6 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
} }
} }
@Override
public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) {
if (locTextKey == null) {
return;
}
tableItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
for (int i = 0; i < locTextKey.length; i++) {
tableItem.setText(i, this.i18nSupport.getText(locTextKey[i]));
}
}
@Override @Override
public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey); tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);

View file

@ -1,202 +1,202 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.page.impl; package ch.ethz.seb.sebserver.gui.service.page.impl;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.MessageBox;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.ComposerService; import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition; import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
import ch.ethz.seb.sebserver.gui.service.page.PageService; 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.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.IllegalUserSessionStateException; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.IllegalUserSessionStateException;
import ch.ethz.seb.sebserver.gui.widget.Message; import ch.ethz.seb.sebserver.gui.widget.Message;
@Lazy @Lazy
@Service @Service
@GuiProfile @GuiProfile
public class ComposerServiceImpl implements ComposerService { public class ComposerServiceImpl implements ComposerService {
private static final Logger log = LoggerFactory.getLogger(ComposerServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(ComposerServiceImpl.class);
private final Class<? extends PageDefinition> loginPageType = DefaultLoginPage.class; private final Class<? extends PageDefinition> loginPageType = DefaultLoginPage.class;
private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class; private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class;
final AuthorizationContextHolder authorizationContextHolder; final AuthorizationContextHolder authorizationContextHolder;
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
private final Map<String, TemplateComposer> composer; private final Map<String, TemplateComposer> composer;
private final Map<String, PageDefinition> pages; private final Map<String, PageDefinition> pages;
public ComposerServiceImpl( public ComposerServiceImpl(
final AuthorizationContextHolder authorizationContextHolder, final AuthorizationContextHolder authorizationContextHolder,
final I18nSupport i18nSupport, final I18nSupport i18nSupport,
final Collection<TemplateComposer> composer, final Collection<TemplateComposer> composer,
final Collection<PageDefinition> pageDefinitions) { final Collection<PageDefinition> pageDefinitions) {
this.authorizationContextHolder = authorizationContextHolder; this.authorizationContextHolder = authorizationContextHolder;
this.i18nSupport = i18nSupport; this.i18nSupport = i18nSupport;
this.composer = composer this.composer = composer
.stream() .stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
comp -> comp.getClass().getName(), comp -> comp.getClass().getName(),
Function.identity())); Function.identity()));
this.pages = pageDefinitions this.pages = pageDefinitions
.stream() .stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
page -> page.getClass().getName(), page -> page.getClass().getName(),
Function.identity())); Function.identity()));
} }
@Override @Override
public PageDefinition mainPage() { public PageDefinition mainPage() {
return this.pages.get(this.mainPageType.getName()); return this.pages.get(this.mainPageType.getName());
} }
@Override @Override
public PageDefinition loginPage() { public PageDefinition loginPage() {
return this.pages.get(this.loginPageType.getName()); return this.pages.get(this.loginPageType.getName());
} }
@Override @Override
public boolean validate(final String composerName, final PageContext pageContext) { public boolean validate(final String composerName, final PageContext pageContext) {
if (!this.composer.containsKey(composerName)) { if (!this.composer.containsKey(composerName)) {
return false; return false;
} }
return this.composer return this.composer
.get(composerName) .get(composerName)
.validate(pageContext); .validate(pageContext);
} }
@Override @Override
public void compose( public void compose(
final Class<? extends TemplateComposer> composerType, final Class<? extends TemplateComposer> composerType,
final PageContext pageContext) { final PageContext pageContext) {
if (composerType != null && pageContext != null) { if (composerType != null && pageContext != null) {
compose(composerType.getName(), pageContext); compose(composerType.getName(), pageContext);
} }
} }
@Override @Override
public void compose( public void compose(
final String name, final String name,
final PageContext pageContext) { final PageContext pageContext) {
// Check first if there is still a valid authorization context // Check first if there is still a valid authorization context
if (!this.authorizationContextHolder.getAuthorizationContext().isValid()) { if (!this.authorizationContextHolder.getAuthorizationContext().isValid()) {
return; return;
} }
if (!this.composer.containsKey(name)) { if (!this.composer.containsKey(name)) {
log.error("No TemplateComposer with name: " + name + " found. Check Spring confiuration and beans"); log.error("No TemplateComposer with name: " + name + " found. Check Spring configuration and beans");
return; return;
} }
final TemplateComposer composer = this.composer.get(name); final TemplateComposer composer = this.composer.get(name);
if (composer.validate(pageContext)) { if (composer.validate(pageContext)) {
PageService.clearComposite(pageContext.getParent()); PageService.clearComposite(pageContext.getParent());
try { try {
composer.compose(pageContext); composer.compose(pageContext);
PageService.updateScrolledComposite(pageContext.getParent()); PageService.updateScrolledComposite(pageContext.getParent());
} catch (final IllegalUserSessionStateException e) { } catch (final IllegalUserSessionStateException e) {
log.warn("Illegal user session state detected... ceanup user session and forward to login page."); log.warn("Illegal user session state detected... cleanup user session and forward to login page.");
pageContext.forwardToLoginPage(); pageContext.forwardToLoginPage();
final MessageBox logoutSuccess = new Message( final MessageBox logoutSuccess = new Message(
pageContext.getShell(), pageContext.getShell(),
this.i18nSupport.getText("sebserver.logout"), this.i18nSupport.getText("sebserver.logout"),
this.i18nSupport.getText("sebserver.logout.invalid-session.message"), this.i18nSupport.getText("sebserver.logout.invalid-session.message"),
SWT.ICON_INFORMATION, SWT.ICON_INFORMATION,
this.i18nSupport); this.i18nSupport);
logoutSuccess.open(null); logoutSuccess.open(null);
return; return;
} catch (final RuntimeException e) { } catch (final RuntimeException e) {
log.warn("Failed to compose: {}, pageContext: {}", name, pageContext, e); log.warn("Failed to compose: {}, pageContext: {}", name, pageContext, e);
pageContext.notifyError(new LocTextKey("sebserver.error.unexpected"), e); pageContext.notifyError(new LocTextKey("sebserver.error.unexpected"), e);
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to compose: {}, pageContext: {}", name, pageContext, e); log.error("Failed to compose: {}, pageContext: {}", name, pageContext, e);
} }
try { try {
pageContext.getParent().layout(); pageContext.getParent().layout();
} catch (final Exception e) { } catch (final Exception e) {
log.warn("Failed to layout new composition: {}, pageContext: {}", name, pageContext, e); log.warn("Failed to layout new composition: {}, pageContext: {}", name, pageContext, e);
} }
} else { } else {
log.error( log.error(
"Invalid or missing mandatory attributes to handle compose request of ViewComposer: {} pageContext: {}", "Invalid or missing mandatory attributes to handle compose request of ViewComposer: {} pageContext: {}",
name, name,
pageContext); pageContext);
} }
} }
@Override @Override
public void composePage( public void composePage(
final PageDefinition pageDefinition, final PageDefinition pageDefinition,
final Composite root) { final Composite root) {
compose( compose(
pageDefinition.composer(), pageDefinition.composer(),
pageDefinition.applyPageContext(createPageContext(root))); pageDefinition.applyPageContext(createPageContext(root)));
} }
@Override @Override
public void composePage( public void composePage(
final Class<? extends PageDefinition> pageType, final Class<? extends PageDefinition> pageType,
final Composite root) { final Composite root) {
final String pageName = pageType.getName(); final String pageName = pageType.getName();
if (!this.pages.containsKey(pageName)) { if (!this.pages.containsKey(pageName)) {
log.error("Unknown page with name: {}", pageName); log.error("Unknown page with name: {}", pageName);
return; return;
} }
final PageDefinition pageDefinition = this.pages.get(pageName); final PageDefinition pageDefinition = this.pages.get(pageName);
compose( compose(
pageDefinition.composer(), pageDefinition.composer(),
pageDefinition.applyPageContext(createPageContext(root))); pageDefinition.applyPageContext(createPageContext(root)));
} }
@Override @Override
public void loadLoginPage(final Composite parent) { public void loadLoginPage(final Composite parent) {
composePage(this.loginPageType, parent); composePage(this.loginPageType, parent);
} }
@Override @Override
public void loadMainPage(final Composite parent) { public void loadMainPage(final Composite parent) {
composePage(this.mainPageType, parent); composePage(this.mainPageType, parent);
} }
private PageContext createPageContext(final Composite root) { private PageContext createPageContext(final Composite root) {
return new PageContextImpl(this.i18nSupport, this, root, root, null); return new PageContextImpl(this.i18nSupport, this, root, root, null);
} }
} }