code cleanup
This commit is contained in:
parent
df884bd8d2
commit
884f9c78e0
40 changed files with 4320 additions and 4290 deletions
|
@ -101,15 +101,15 @@ public class ExamForm implements TemplateComposer {
|
|||
new LocTextKey("sebserver.exam.form.status");
|
||||
private static final LocTextKey FORM_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.type");
|
||||
private static final LocTextKey FORM_ENDTIME_TEXT_KEY =
|
||||
private static final LocTextKey FORM_END_TIME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.endtime");
|
||||
private static final LocTextKey FORM_STARTTIME_TEXT_KEY =
|
||||
private static final LocTextKey FORM_START_TIME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.starttime");
|
||||
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.description");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.name");
|
||||
private static final LocTextKey FORM_QUIZID_TEXT_KEY =
|
||||
private static final LocTextKey FORM_QUIZ_ID_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.quizid");
|
||||
private static final LocTextKey FORM_QUIZ_URL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.form.quizurl");
|
||||
|
@ -285,14 +285,14 @@ public class ExamForm implements TemplateComposer {
|
|||
|
||||
.addField(FormBuilder.text(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
FORM_STARTTIME_TEXT_KEY,
|
||||
FORM_START_TIME_TEXT_KEY,
|
||||
i18nSupport.formatDisplayDateWithTimeZone(exam.startTime))
|
||||
.readonly(true)
|
||||
.withInputSpan(3)
|
||||
.withEmptyCellSeparation(false))
|
||||
.addField(FormBuilder.text(
|
||||
QuizData.QUIZ_ATTR_END_TIME,
|
||||
FORM_ENDTIME_TEXT_KEY,
|
||||
FORM_END_TIME_TEXT_KEY,
|
||||
i18nSupport.formatDisplayDateWithTimeZone(exam.endTime))
|
||||
.readonly(true)
|
||||
.withInputSpan(3)
|
||||
|
@ -300,7 +300,7 @@ public class ExamForm implements TemplateComposer {
|
|||
|
||||
.addField(FormBuilder.text(
|
||||
Domain.EXAM.ATTR_EXTERNAL_ID,
|
||||
FORM_QUIZID_TEXT_KEY,
|
||||
FORM_QUIZ_ID_TEXT_KEY,
|
||||
exam.externalId)
|
||||
.readonly(true)
|
||||
.withEmptyCellSeparation(false))
|
||||
|
|
|
@ -62,11 +62,11 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
|||
@GuiProfile
|
||||
public class ExamList implements TemplateComposer {
|
||||
|
||||
static final String EXAM_LIST_COLUMN_STARTTIME =
|
||||
static final String EXAM_LIST_COLUMN_START_TIME =
|
||||
"sebserver.exam.list.column.starttime";
|
||||
static final LocTextKey PAGE_TITLE_KEY =
|
||||
new LocTextKey("sebserver.exam.list.title");
|
||||
static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
|
||||
new LocTextKey("sebserver.exam.list.action.no.modify.privilege");
|
||||
final static LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.exam.info.pleaseSelect");
|
||||
|
@ -175,7 +175,7 @@ public class ExamList implements TemplateComposer {
|
|||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
new LocTextKey(
|
||||
EXAM_LIST_COLUMN_STARTTIME,
|
||||
EXAM_LIST_COLUMN_START_TIME,
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
Exam::getStartTime)
|
||||
.withFilter(new TableFilterAttribute(
|
||||
|
@ -213,7 +213,7 @@ public class ExamList implements TemplateComposer {
|
|||
|
||||
.newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
|
||||
action -> modifyExam(action, table),
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> userGrant.im() && table.hasAnyContent(), false);
|
||||
|
|
|
@ -46,7 +46,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
|||
@GuiProfile
|
||||
public class LmsSetupList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
|
||||
new LocTextKey("sebserver.lmssetup.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.lmssetup.info.pleaseSelect");
|
||||
|
@ -173,7 +173,7 @@ public class LmsSetupList implements TemplateComposer {
|
|||
|
||||
.newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
|
||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> userGrant.im() && table.hasAnyContent(), false)
|
||||
|
||||
|
|
|
@ -1,201 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultRegisterPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class LoginPage implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LoginPage.class);
|
||||
|
||||
private final PageService pageService;
|
||||
private final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final DefaultRegisterPage defaultRegisterPage;
|
||||
private final boolean registreringEnabled;
|
||||
|
||||
public LoginPage(
|
||||
final PageService pageService,
|
||||
final DefaultRegisterPage defaultRegisterPage,
|
||||
@Value("${sebserver.gui.self-registering:false}") final Boolean registreringEnabled) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
|
||||
this.widgetFactory = pageService.getWidgetFactory();
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
this.defaultRegisterPage = defaultRegisterPage;
|
||||
this.registreringEnabled = BooleanUtils.toBoolean(registreringEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final Composite parent = pageContext.getParent();
|
||||
WidgetFactory.setTestId(parent, "login-page");
|
||||
WidgetFactory.setARIARole(parent, "composite");
|
||||
|
||||
final Composite loginGroup = new Composite(parent, SWT.NONE);
|
||||
final GridLayout rowLayout = new GridLayout();
|
||||
rowLayout.marginWidth = 20;
|
||||
rowLayout.marginRight = 100;
|
||||
loginGroup.setLayout(rowLayout);
|
||||
loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key);
|
||||
|
||||
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
||||
name.setLayoutData(new GridData(300, -1));
|
||||
name.setAlignment(SWT.BOTTOM);
|
||||
final Text loginName = this.widgetFactory.textInput(loginGroup);
|
||||
loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd");
|
||||
pwd.setLayoutData(gridData);
|
||||
final Text loginPassword = this.widgetFactory.passwordInput(loginGroup);
|
||||
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||
|
||||
final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder
|
||||
.getAuthorizationContext(RWT.getUISession().getHttpSession());
|
||||
|
||||
final Composite buttons = new Composite(loginGroup, SWT.NONE);
|
||||
buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
buttons.setLayout(new GridLayout(2, false));
|
||||
buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key);
|
||||
|
||||
final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login");
|
||||
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
loginButton.setLayoutData(gridData);
|
||||
loginButton.addListener(SWT.Selection, event -> {
|
||||
login(
|
||||
pageContext,
|
||||
loginName.getText(),
|
||||
loginPassword.getText(),
|
||||
authorizationContext);
|
||||
});
|
||||
loginName.addListener(SWT.KeyDown, event -> {
|
||||
if (event.character == '\n' || event.character == '\r') {
|
||||
if (StringUtils.isNotBlank(loginPassword.getText())) {
|
||||
login(
|
||||
pageContext,
|
||||
loginName.getText(),
|
||||
loginPassword.getText(),
|
||||
authorizationContext);
|
||||
} else {
|
||||
loginPassword.setFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
loginPassword.addListener(SWT.KeyDown, event -> {
|
||||
if (event.character == '\n' || event.character == '\r') {
|
||||
if (StringUtils.isNotBlank(loginName.getText())) {
|
||||
login(
|
||||
pageContext,
|
||||
loginName.getText(),
|
||||
loginPassword.getText(),
|
||||
authorizationContext);
|
||||
} else {
|
||||
loginName.setFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.registreringEnabled) {
|
||||
final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register");
|
||||
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
registerButton.setLayoutData(gridData);
|
||||
registerButton.addListener(SWT.Selection, event -> {
|
||||
pageContext.forwardToPage(this.defaultRegisterPage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void login(
|
||||
final PageContext pageContext,
|
||||
final String loginName,
|
||||
final CharSequence loginPassword,
|
||||
final SEBServerAuthorizationContext authorizationContext) {
|
||||
|
||||
final String username = loginName;
|
||||
try {
|
||||
|
||||
final boolean loggedIn = authorizationContext.login(
|
||||
username,
|
||||
loginPassword);
|
||||
|
||||
if (loggedIn) {
|
||||
// Set users locale on page after successful login
|
||||
try {
|
||||
RWT.getUISession()
|
||||
.getHttpSession()
|
||||
.setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, authorizationContext
|
||||
.getLoggedInUser()
|
||||
.getOrThrow().language);
|
||||
|
||||
} catch (final IllegalStateException e) {
|
||||
log.error("Set current locale for session failed: ", e);
|
||||
}
|
||||
|
||||
RWT.setLocale(this.i18nSupport.getUsersFormatLocale());
|
||||
|
||||
pageContext.forwardToMainPage();
|
||||
|
||||
} else {
|
||||
loginError(pageContext, "sebserver.login.failed.message");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to login with user: {}", username, e);
|
||||
loginError(pageContext, "Unexpected Error. Please call an Administrator");
|
||||
}
|
||||
}
|
||||
|
||||
private void loginError(
|
||||
final PageContext pageContext,
|
||||
final String message) {
|
||||
|
||||
this.pageService.logout(pageContext);
|
||||
final MessageBox error = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("sebserver.login.failed.title"),
|
||||
this.i18nSupport.getText(message, message),
|
||||
SWT.ERROR,
|
||||
this.i18nSupport);
|
||||
error.open(null);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultRegisterPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class LoginPage implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LoginPage.class);
|
||||
|
||||
private final PageService pageService;
|
||||
private final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final DefaultRegisterPage defaultRegisterPage;
|
||||
private final boolean registeringEnabled;
|
||||
|
||||
public LoginPage(
|
||||
final PageService pageService,
|
||||
final DefaultRegisterPage defaultRegisterPage,
|
||||
@Value("${sebserver.gui.self-registering:false}") final Boolean registeringEnabled) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
|
||||
this.widgetFactory = pageService.getWidgetFactory();
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
this.defaultRegisterPage = defaultRegisterPage;
|
||||
this.registeringEnabled = BooleanUtils.toBoolean(registeringEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final Composite parent = pageContext.getParent();
|
||||
WidgetFactory.setTestId(parent, "login-page");
|
||||
WidgetFactory.setARIARole(parent, "composite");
|
||||
|
||||
final Composite loginGroup = new Composite(parent, SWT.NONE);
|
||||
final GridLayout rowLayout = new GridLayout();
|
||||
rowLayout.marginWidth = 20;
|
||||
rowLayout.marginRight = 100;
|
||||
loginGroup.setLayout(rowLayout);
|
||||
loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key);
|
||||
|
||||
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
||||
name.setLayoutData(new GridData(300, -1));
|
||||
name.setAlignment(SWT.BOTTOM);
|
||||
final Text loginName = this.widgetFactory.textInput(loginGroup);
|
||||
loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd");
|
||||
pwd.setLayoutData(gridData);
|
||||
final Text loginPassword = this.widgetFactory.passwordInput(loginGroup);
|
||||
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||
|
||||
final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder
|
||||
.getAuthorizationContext(RWT.getUISession().getHttpSession());
|
||||
|
||||
final Composite buttons = new Composite(loginGroup, SWT.NONE);
|
||||
buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
buttons.setLayout(new GridLayout(2, false));
|
||||
buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key);
|
||||
|
||||
final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login");
|
||||
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
loginButton.setLayoutData(gridData);
|
||||
loginButton.addListener(SWT.Selection, event -> login(
|
||||
pageContext,
|
||||
loginName.getText(),
|
||||
loginPassword.getText(),
|
||||
authorizationContext));
|
||||
loginName.addListener(SWT.KeyDown, event -> {
|
||||
if (event.character == '\n' || event.character == '\r') {
|
||||
if (StringUtils.isNotBlank(loginPassword.getText())) {
|
||||
login(
|
||||
pageContext,
|
||||
loginName.getText(),
|
||||
loginPassword.getText(),
|
||||
authorizationContext);
|
||||
} else {
|
||||
loginPassword.setFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
loginPassword.addListener(SWT.KeyDown, event -> {
|
||||
if (event.character == '\n' || event.character == '\r') {
|
||||
if (StringUtils.isNotBlank(loginName.getText())) {
|
||||
login(
|
||||
pageContext,
|
||||
loginName.getText(),
|
||||
loginPassword.getText(),
|
||||
authorizationContext);
|
||||
} else {
|
||||
loginName.setFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.registeringEnabled) {
|
||||
final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register");
|
||||
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
registerButton.setLayoutData(gridData);
|
||||
registerButton.addListener(SWT.Selection, event -> pageContext.forwardToPage(this.defaultRegisterPage));
|
||||
}
|
||||
}
|
||||
|
||||
private void login(
|
||||
final PageContext pageContext,
|
||||
final String loginName,
|
||||
final CharSequence loginPassword,
|
||||
final SEBServerAuthorizationContext authorizationContext) {
|
||||
|
||||
try {
|
||||
|
||||
final boolean loggedIn = authorizationContext.login(
|
||||
loginName,
|
||||
loginPassword);
|
||||
|
||||
if (loggedIn) {
|
||||
// Set users locale on page after successful login
|
||||
try {
|
||||
RWT.getUISession()
|
||||
.getHttpSession()
|
||||
.setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, authorizationContext
|
||||
.getLoggedInUser()
|
||||
.getOrThrow().language);
|
||||
|
||||
} catch (final IllegalStateException e) {
|
||||
log.error("Set current locale for session failed: ", e);
|
||||
}
|
||||
|
||||
RWT.setLocale(this.i18nSupport.getUsersFormatLocale());
|
||||
|
||||
pageContext.forwardToMainPage();
|
||||
|
||||
} else {
|
||||
loginError(pageContext, "sebserver.login.failed.message");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to login with user: {}", loginName, e);
|
||||
loginError(pageContext, "Unexpected Error. Please call an Administrator");
|
||||
}
|
||||
}
|
||||
|
||||
private void loginError(
|
||||
final PageContext pageContext,
|
||||
final String message) {
|
||||
|
||||
this.pageService.logout(pageContext);
|
||||
final MessageBox error = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("sebserver.login.failed.title"),
|
||||
this.i18nSupport.getText(message, message),
|
||||
SWT.ERROR,
|
||||
this.i18nSupport);
|
||||
error.open(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,184 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.SashForm;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.activity.ActivitiesPane;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class MainPage implements TemplateComposer {
|
||||
|
||||
static final Logger log = LoggerFactory.getLogger(MainPage.class);
|
||||
|
||||
private static final int ACTIVITY_PANE_WEIGHT = 18;
|
||||
private static final int CONTENT_PANE_WEIGHT = 65;
|
||||
private static final int ACTION_PANE_WEIGHT = 20;
|
||||
private static final int[] DEFAULT_SASH_WEIGHTS = new int[] {
|
||||
ACTIVITY_PANE_WEIGHT,
|
||||
CONTENT_PANE_WEIGHT,
|
||||
ACTION_PANE_WEIGHT
|
||||
};
|
||||
private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 };
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final PolyglotPageService polyglotPageService;
|
||||
|
||||
public MainPage(
|
||||
final WidgetFactory widgetFactory,
|
||||
final PolyglotPageService polyglotPageService) {
|
||||
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.polyglotPageService = polyglotPageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final Composite parent = pageContext.getParent();
|
||||
parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
WidgetFactory.setTestId(parent, "main-page");
|
||||
|
||||
final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL);
|
||||
final GridLayout gridLayout = new GridLayout();
|
||||
|
||||
mainSash.setLayout(gridLayout);
|
||||
mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
|
||||
final Composite nav = new Composite(mainSash, SWT.NONE);
|
||||
nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
final GridLayout navLayout = new GridLayout();
|
||||
navLayout.marginHeight = 20;
|
||||
navLayout.marginWidth = 0;
|
||||
nav.setLayout(navLayout);
|
||||
|
||||
final Composite content = PageService.createManagedVScrolledComposite(
|
||||
mainSash,
|
||||
scrolledComposite -> {
|
||||
final Composite result = new Composite(scrolledComposite, SWT.NONE);
|
||||
result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
final GridLayout contentOuterlayout = new GridLayout();
|
||||
contentOuterlayout.marginHeight = 0;
|
||||
contentOuterlayout.marginWidth = 0;
|
||||
result.setLayout(contentOuterlayout);
|
||||
return result;
|
||||
},
|
||||
false);
|
||||
|
||||
final Label toggleView = this.widgetFactory.imageButton(
|
||||
ImageIcon.MAXIMIZE,
|
||||
content,
|
||||
new LocTextKey("sebserver.mainpage.maximize.tooltip"),
|
||||
event -> {
|
||||
final Label ib = (Label) event.widget;
|
||||
if ((Boolean) ib.getData("fullScreen")) {
|
||||
mainSash.setWeights(DEFAULT_SASH_WEIGHTS);
|
||||
ib.setData("fullScreen", false);
|
||||
ib.setImage(WidgetFactory.ImageIcon.MAXIMIZE.getImage(ib.getDisplay()));
|
||||
this.polyglotPageService.injectI18n(
|
||||
ib,
|
||||
null,
|
||||
new LocTextKey("sebserver.mainpage.maximize.tooltip"));
|
||||
} else {
|
||||
mainSash.setWeights(OPENED_SASH_WEIGHTS);
|
||||
ib.setData("fullScreen", true);
|
||||
ib.setImage(WidgetFactory.ImageIcon.MINIMIZE.getImage(ib.getDisplay()));
|
||||
this.polyglotPageService.injectI18n(
|
||||
ib,
|
||||
null,
|
||||
new LocTextKey("sebserver.mainpage.minimize.tooltip"));
|
||||
}
|
||||
});
|
||||
final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false);
|
||||
toggleView.setLayoutData(gridData);
|
||||
toggleView.setData("fullScreen", false);
|
||||
|
||||
final Composite contentObjects = new Composite(content, SWT.NONE);
|
||||
contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
final GridLayout contentObjectslayout = new GridLayout();
|
||||
contentObjectslayout.marginHeight = 0;
|
||||
contentObjectslayout.marginWidth = 0;
|
||||
contentObjects.setLayout(contentObjectslayout);
|
||||
contentObjects.setData(
|
||||
PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ContentActionEventListener(event -> pageContext
|
||||
.composerService()
|
||||
.compose(
|
||||
event.action.definition.targetState.contentPaneComposer(),
|
||||
event.action.pageContext().copyOf(contentObjects)),
|
||||
2));
|
||||
|
||||
final Composite actionPane = new Composite(mainSash, SWT.NONE);
|
||||
actionPane.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
final GridLayout actionPaneGrid = new GridLayout();
|
||||
actionPane.setLayout(actionPaneGrid);
|
||||
actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane");
|
||||
actionPane.setData(
|
||||
PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ContentActionEventListener(event -> pageContext
|
||||
.composerService()
|
||||
.compose(
|
||||
event.action.definition.targetState.actionPaneComposer(),
|
||||
event.action.pageContext().copyOf(actionPane)),
|
||||
1));
|
||||
|
||||
pageContext.composerService().compose(
|
||||
ActivitiesPane.class,
|
||||
pageContext.copyOf(nav));
|
||||
|
||||
mainSash.setWeights(DEFAULT_SASH_WEIGHTS);
|
||||
}
|
||||
|
||||
private static final class ContentActionEventListener implements ActionEventListener {
|
||||
|
||||
private final int priority;
|
||||
private final Consumer<ActionEvent> apply;
|
||||
|
||||
protected ContentActionEventListener(final Consumer<ActionEvent> apply, final int priority) {
|
||||
this.apply = apply;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(final ActionEvent event) {
|
||||
this.apply.accept(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.SashForm;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.activity.ActivitiesPane;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class MainPage implements TemplateComposer {
|
||||
|
||||
static final Logger log = LoggerFactory.getLogger(MainPage.class);
|
||||
|
||||
private static final int ACTIVITY_PANE_WEIGHT = 18;
|
||||
private static final int CONTENT_PANE_WEIGHT = 65;
|
||||
private static final int ACTION_PANE_WEIGHT = 20;
|
||||
private static final int[] DEFAULT_SASH_WEIGHTS = new int[] {
|
||||
ACTIVITY_PANE_WEIGHT,
|
||||
CONTENT_PANE_WEIGHT,
|
||||
ACTION_PANE_WEIGHT
|
||||
};
|
||||
private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 };
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final PolyglotPageService polyglotPageService;
|
||||
|
||||
public MainPage(
|
||||
final WidgetFactory widgetFactory,
|
||||
final PolyglotPageService polyglotPageService) {
|
||||
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.polyglotPageService = polyglotPageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final Composite parent = pageContext.getParent();
|
||||
parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
WidgetFactory.setTestId(parent, "main-page");
|
||||
|
||||
final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL);
|
||||
final GridLayout gridLayout = new GridLayout();
|
||||
|
||||
mainSash.setLayout(gridLayout);
|
||||
mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
|
||||
final Composite nav = new Composite(mainSash, SWT.NONE);
|
||||
nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
final GridLayout navLayout = new GridLayout();
|
||||
navLayout.marginHeight = 20;
|
||||
navLayout.marginWidth = 0;
|
||||
nav.setLayout(navLayout);
|
||||
|
||||
final Composite content = PageService.createManagedVScrolledComposite(
|
||||
mainSash,
|
||||
scrolledComposite -> {
|
||||
final Composite result = new Composite(scrolledComposite, SWT.NONE);
|
||||
result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
final GridLayout contentOuterLayout = new GridLayout();
|
||||
contentOuterLayout.marginHeight = 0;
|
||||
contentOuterLayout.marginWidth = 0;
|
||||
result.setLayout(contentOuterLayout);
|
||||
return result;
|
||||
},
|
||||
false);
|
||||
|
||||
final Label toggleView = this.widgetFactory.imageButton(
|
||||
ImageIcon.MAXIMIZE,
|
||||
content,
|
||||
new LocTextKey("sebserver.mainpage.maximize.tooltip"),
|
||||
event -> {
|
||||
final Label ib = (Label) event.widget;
|
||||
if ((Boolean) ib.getData("fullScreen")) {
|
||||
mainSash.setWeights(DEFAULT_SASH_WEIGHTS);
|
||||
ib.setData("fullScreen", false);
|
||||
ib.setImage(WidgetFactory.ImageIcon.MAXIMIZE.getImage(ib.getDisplay()));
|
||||
this.polyglotPageService.injectI18n(
|
||||
ib,
|
||||
null,
|
||||
new LocTextKey("sebserver.mainpage.maximize.tooltip"));
|
||||
} else {
|
||||
mainSash.setWeights(OPENED_SASH_WEIGHTS);
|
||||
ib.setData("fullScreen", true);
|
||||
ib.setImage(WidgetFactory.ImageIcon.MINIMIZE.getImage(ib.getDisplay()));
|
||||
this.polyglotPageService.injectI18n(
|
||||
ib,
|
||||
null,
|
||||
new LocTextKey("sebserver.mainpage.minimize.tooltip"));
|
||||
}
|
||||
});
|
||||
final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false);
|
||||
toggleView.setLayoutData(gridData);
|
||||
toggleView.setData("fullScreen", false);
|
||||
|
||||
final Composite contentObjects = new Composite(content, SWT.NONE);
|
||||
contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
final GridLayout contentObjectsLayout = new GridLayout();
|
||||
contentObjectsLayout.marginHeight = 0;
|
||||
contentObjectsLayout.marginWidth = 0;
|
||||
contentObjects.setLayout(contentObjectsLayout);
|
||||
contentObjects.setData(
|
||||
PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ContentActionEventListener(event -> pageContext
|
||||
.composerService()
|
||||
.compose(
|
||||
event.action.definition.targetState.contentPaneComposer(),
|
||||
event.action.pageContext().copyOf(contentObjects)),
|
||||
2));
|
||||
|
||||
final Composite actionPane = new Composite(mainSash, SWT.NONE);
|
||||
actionPane.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
final GridLayout actionPaneGrid = new GridLayout();
|
||||
actionPane.setLayout(actionPaneGrid);
|
||||
actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane");
|
||||
actionPane.setData(
|
||||
PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ContentActionEventListener(event -> pageContext
|
||||
.composerService()
|
||||
.compose(
|
||||
event.action.definition.targetState.actionPaneComposer(),
|
||||
event.action.pageContext().copyOf(actionPane)),
|
||||
1));
|
||||
|
||||
pageContext.composerService().compose(
|
||||
ActivitiesPane.class,
|
||||
pageContext.copyOf(nav));
|
||||
|
||||
mainSash.setWeights(DEFAULT_SASH_WEIGHTS);
|
||||
}
|
||||
|
||||
private static final class ContentActionEventListener implements ActionEventListener {
|
||||
|
||||
private final int priority;
|
||||
private final Consumer<ActionEvent> apply;
|
||||
|
||||
protected ContentActionEventListener(final Consumer<ActionEvent> apply, final int priority) {
|
||||
this.apply = apply;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(final ActionEvent event) {
|
||||
this.apply.accept(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -240,8 +240,8 @@ public class QuizDiscoveryList implements TemplateComposer {
|
|||
}
|
||||
|
||||
private static Function<QuizData, String> quizDataLmsSetupNameFunction(final ResourceService resourceService) {
|
||||
return quizzData -> resourceService.getLmsSetupNameFunction()
|
||||
.apply(String.valueOf(quizzData.lmsSetupId));
|
||||
return quizData -> resourceService.getLmsSetupNameFunction()
|
||||
.apply(String.valueOf(quizData.lmsSetupId));
|
||||
}
|
||||
|
||||
private PageAction importQuizData(final PageAction action, final EntityTable<QuizData> table) {
|
||||
|
|
|
@ -247,9 +247,7 @@ public class RegisterPage implements TemplateComposer {
|
|||
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||
gridData.verticalIndent = 10;
|
||||
cancelButton.setLayoutData(gridData);
|
||||
cancelButton.addListener(SWT.Selection, event -> {
|
||||
pageContext.forwardToLoginPage();
|
||||
});
|
||||
cancelButton.addListener(SWT.Selection, event -> pageContext.forwardToLoginPage());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
|||
@GuiProfile
|
||||
public class SebClientConfigList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
|
||||
new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.empty");
|
||||
|
@ -176,7 +176,7 @@ public class SebClientConfigList implements TemplateComposer {
|
|||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
|
||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false)
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ final class SebExamConfigImportPopup {
|
|||
};
|
||||
}
|
||||
|
||||
private static final boolean doImport(
|
||||
private static boolean doImport(
|
||||
final PageService pageService,
|
||||
final FormHandle<ConfigurationNode> formHandle,
|
||||
final boolean newConfig) {
|
||||
|
@ -93,7 +93,7 @@ final class SebExamConfigImportPopup {
|
|||
final PageContext context = formHandle.getContext();
|
||||
|
||||
// Ad-hoc field validation
|
||||
formHandle.process(name -> true, field -> field.resetError());
|
||||
formHandle.process(name -> true, Form.FormFieldAccessor::resetError);
|
||||
final String fieldValue = form.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_NAME);
|
||||
if (StringUtils.isBlank(fieldValue)) {
|
||||
form.setFieldError(
|
||||
|
@ -116,7 +116,7 @@ final class SebExamConfigImportPopup {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (fieldControl != null && fieldControl instanceof FileUploadSelection) {
|
||||
if (fieldControl instanceof FileUploadSelection) {
|
||||
final FileUploadSelection fileUpload = (FileUploadSelection) fieldControl;
|
||||
final InputStream inputStream = fileUpload.getInputStream();
|
||||
if (inputStream != null) {
|
||||
|
@ -162,7 +162,6 @@ final class SebExamConfigImportPopup {
|
|||
new ActionEvent(action),
|
||||
action.pageContext());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
final Exception error = configuration.getError();
|
||||
if (error instanceof RestCallError) {
|
||||
|
@ -188,12 +187,12 @@ final class SebExamConfigImportPopup {
|
|||
SebExamConfigPropForm.FORM_TITLE,
|
||||
configuration.getError());
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
formHandle.getContext().publishPageMessage(
|
||||
new LocTextKey("sebserver.error.unexpected"),
|
||||
new LocTextKey("Please selecte a valid SEB Exam Configuration File"));
|
||||
new LocTextKey("Please select a valid SEB Exam Configuration File"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +270,7 @@ final class SebExamConfigImportPopup {
|
|||
void cancelUpload() {
|
||||
if (this.form != null) {
|
||||
final Control fieldControl = this.form.getFieldInput(API.IMPORT_FILE_ATTR_NAME);
|
||||
if (fieldControl != null && fieldControl instanceof FileUploadSelection) {
|
||||
if (fieldControl instanceof FileUploadSelection) {
|
||||
((FileUploadSelection) fieldControl).close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
|||
@GuiProfile
|
||||
public class SebExamConfigList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
|
||||
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.empty");
|
||||
|
@ -165,7 +165,7 @@ public class SebExamConfigList implements TemplateComposer {
|
|||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
|
||||
.withSelect(
|
||||
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
|
||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false)
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
|
||||
.newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
|
@ -313,7 +313,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
new LocTextKey(
|
||||
ExamList.EXAM_LIST_COLUMN_STARTTIME,
|
||||
ExamList.EXAM_LIST_COLUMN_START_TIME,
|
||||
this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()),
|
||||
ExamConfigurationMap::getExamStartTime))
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
|
|||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> examConfigGrant.iw() && !readonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
|
||||
.newAction(ActionDefinition.SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.action;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
|
||||
public enum ActionCategory {
|
||||
FORM(null, 0),
|
||||
INSTITUTION_LIST(new LocTextKey("sebserver.institution.list.actions"), 1),
|
||||
USER_ACCOUNT_LIST(new LocTextKey("sebserver.useraccount.list.actions"), 1),
|
||||
LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1),
|
||||
QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1),
|
||||
EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1),
|
||||
EXAM_CONFIG_MAPPING_LIST(new LocTextKey("sebserver.exam.configuration.list.actions"), 1),
|
||||
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
|
||||
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
|
||||
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1),
|
||||
SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1),
|
||||
SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1),
|
||||
RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
|
||||
CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1),
|
||||
LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
|
||||
LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
|
||||
VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0),
|
||||
FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50);
|
||||
|
||||
public final LocTextKey title;
|
||||
public final int slotPosition;
|
||||
|
||||
private ActionCategory(final LocTextKey title, final int slotPosition) {
|
||||
this.title = title;
|
||||
this.slotPosition = slotPosition;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.action;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
|
||||
public enum ActionCategory {
|
||||
FORM(null, 0),
|
||||
INSTITUTION_LIST(new LocTextKey("sebserver.institution.list.actions"), 1),
|
||||
USER_ACCOUNT_LIST(new LocTextKey("sebserver.useraccount.list.actions"), 1),
|
||||
LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1),
|
||||
QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1),
|
||||
EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1),
|
||||
EXAM_CONFIG_MAPPING_LIST(new LocTextKey("sebserver.exam.configuration.list.actions"), 1),
|
||||
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
|
||||
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
|
||||
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1),
|
||||
SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1),
|
||||
SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1),
|
||||
RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
|
||||
CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1),
|
||||
LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
|
||||
LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
|
||||
VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0),
|
||||
FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50);
|
||||
|
||||
public final LocTextKey title;
|
||||
public final int slotPosition;
|
||||
|
||||
ActionCategory(final LocTextKey title, final int slotPosition) {
|
||||
this.title = title;
|
||||
this.slotPosition = slotPosition;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -467,7 +467,7 @@ public enum ActionDefinition {
|
|||
new LocTextKey("sebserver.examconfig.action.copy"),
|
||||
ImageIcon.COPY,
|
||||
ActionCategory.FORM),
|
||||
SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE(
|
||||
SEA_EXAM_CONFIG_COPY_CONFIG_AS_TEMPLATE(
|
||||
new LocTextKey("sebserver.examconfig.action.copy-as-template"),
|
||||
ImageIcon.TEMPLATE,
|
||||
ActionCategory.FORM),
|
||||
|
|
|
@ -8,10 +8,17 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.content.action;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.template.ImageCell;
|
||||
|
@ -31,19 +38,9 @@ import org.eclipse.swt.widgets.TreeItem;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionActivationEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,42 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.activity;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.Activity;
|
||||
|
||||
public enum ActivityDefinition implements Activity {
|
||||
SEB_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.serveradmin")),
|
||||
INSTITUTION(new LocTextKey("sebserver.institution.action.list")),
|
||||
USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")),
|
||||
USER_ACTIVITY_LOGS(new LocTextKey("sebserver.logs.activity.userlogs")),
|
||||
LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")),
|
||||
QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")),
|
||||
EXAM_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.examadmin")),
|
||||
EXAM(new LocTextKey("sebserver.exam.action.list")),
|
||||
SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")),
|
||||
SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")),
|
||||
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")),
|
||||
SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")),
|
||||
MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
|
||||
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
|
||||
SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
|
||||
|
||||
public final LocTextKey displayName;
|
||||
|
||||
private ActivityDefinition(final LocTextKey displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocTextKey displayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.activity;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.Activity;
|
||||
|
||||
public enum ActivityDefinition implements Activity {
|
||||
SEB_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.serveradmin")),
|
||||
INSTITUTION(new LocTextKey("sebserver.institution.action.list")),
|
||||
USER_ACCOUNT(new LocTextKey("sebserver.useraccount.action.list")),
|
||||
USER_ACTIVITY_LOGS(new LocTextKey("sebserver.logs.activity.userlogs")),
|
||||
LMS_SETUP(new LocTextKey("sebserver.lmssetup.action.list")),
|
||||
QUIZ_DISCOVERY(new LocTextKey("sebserver.quizdiscovery.action.list")),
|
||||
EXAM_ADMINISTRATION(new LocTextKey("sebserver.overall.activity.title.examadmin")),
|
||||
EXAM(new LocTextKey("sebserver.exam.action.list")),
|
||||
SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")),
|
||||
SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")),
|
||||
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")),
|
||||
SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")),
|
||||
MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
|
||||
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
|
||||
SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
|
||||
|
||||
public final LocTextKey displayName;
|
||||
|
||||
ActivityDefinition(final LocTextKey displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocTextKey displayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
|
|||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
public final Activity activityAnchor;
|
||||
|
||||
private PageStateDefinitionImpl(
|
||||
PageStateDefinitionImpl(
|
||||
final Type type,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Activity activityAnchor) {
|
||||
|
@ -102,7 +102,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
|
|||
this(type, contentPaneComposer, ActionPane.class, activityAnchor);
|
||||
}
|
||||
|
||||
private PageStateDefinitionImpl(
|
||||
PageStateDefinitionImpl(
|
||||
final Type type,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Class<? extends TemplateComposer> actionPaneComposer,
|
||||
|
|
|
@ -44,7 +44,6 @@ public class ThresholdListBuilder extends FieldBuilder<Collection<Threshold>> {
|
|||
final Control titleLabel = createTitleLabel(builder.formParent, builder, this);
|
||||
if (builder.readonly || this.readonly) {
|
||||
// No read-only view needed for this so far?
|
||||
return;
|
||||
} else {
|
||||
|
||||
final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput);
|
||||
|
|
|
@ -1,109 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
public interface ExamConfigurationService {
|
||||
|
||||
public static final String ATTRIBUTE_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.label.";
|
||||
public static final String GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group.";
|
||||
public static final String TOOL_TIP_SUFFIX = ".tooltip";
|
||||
public static final String TABLE_ROW_TITLE_SUFFIX = ".row.title";
|
||||
|
||||
WidgetFactory getWidgetFactory();
|
||||
|
||||
InputFieldBuilder getInputFieldBuilder(
|
||||
ConfigurationAttribute attribute,
|
||||
Orientation orientation);
|
||||
|
||||
Result<AttributeMapping> getAttributes(Long templateId);
|
||||
|
||||
Result<AttributeMapping> getAttributes(
|
||||
final TemplateAttribute attribute,
|
||||
final Orientation defaultOrientation);
|
||||
|
||||
List<View> getViews(AttributeMapping allAttributes);
|
||||
|
||||
ViewContext createViewContext(
|
||||
PageContext pageContext,
|
||||
Configuration configuration,
|
||||
View view,
|
||||
AttributeMapping attributeMapping,
|
||||
int rows,
|
||||
boolean readonly);
|
||||
|
||||
Composite createViewGrid(
|
||||
Composite parent,
|
||||
ViewContext viewContext);
|
||||
|
||||
void initInputFieldValues(
|
||||
Long configurationId,
|
||||
Collection<ViewContext> viewContexts);
|
||||
|
||||
PageAction resetToDefaults(PageAction action);
|
||||
|
||||
PageAction removeFromView(PageAction action);
|
||||
|
||||
PageAction attachToDefaultView(final PageAction action);
|
||||
|
||||
static String attributeNameKey(final ConfigurationAttribute attribute) {
|
||||
if (attribute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name;
|
||||
}
|
||||
|
||||
static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) {
|
||||
if (attribute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LocTextKey(attributeNameKey(attribute));
|
||||
}
|
||||
|
||||
static LocTextKey getToolTipKey(
|
||||
final ConfigurationAttribute attribute,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX;
|
||||
if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) {
|
||||
return null;
|
||||
} else {
|
||||
return new LocTextKey(attributeNameKey);
|
||||
}
|
||||
}
|
||||
|
||||
static LocTextKey getTablePopupTitleKey(
|
||||
final ConfigurationAttribute attribute,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
public interface ExamConfigurationService {
|
||||
|
||||
String ATTRIBUTE_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.label.";
|
||||
String GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group.";
|
||||
String TOOL_TIP_SUFFIX = ".tooltip";
|
||||
String TABLE_ROW_TITLE_SUFFIX = ".row.title";
|
||||
|
||||
WidgetFactory getWidgetFactory();
|
||||
|
||||
InputFieldBuilder getInputFieldBuilder(
|
||||
ConfigurationAttribute attribute,
|
||||
Orientation orientation);
|
||||
|
||||
Result<AttributeMapping> getAttributes(Long templateId);
|
||||
|
||||
Result<AttributeMapping> getAttributes(
|
||||
final TemplateAttribute attribute,
|
||||
final Orientation defaultOrientation);
|
||||
|
||||
List<View> getViews(AttributeMapping allAttributes);
|
||||
|
||||
ViewContext createViewContext(
|
||||
PageContext pageContext,
|
||||
Configuration configuration,
|
||||
View view,
|
||||
AttributeMapping attributeMapping,
|
||||
int rows,
|
||||
boolean readonly);
|
||||
|
||||
Composite createViewGrid(
|
||||
Composite parent,
|
||||
ViewContext viewContext);
|
||||
|
||||
void initInputFieldValues(
|
||||
Long configurationId,
|
||||
Collection<ViewContext> viewContexts);
|
||||
|
||||
PageAction resetToDefaults(PageAction action);
|
||||
|
||||
PageAction removeFromView(PageAction action);
|
||||
|
||||
PageAction attachToDefaultView(final PageAction action);
|
||||
|
||||
static String attributeNameKey(final ConfigurationAttribute attribute) {
|
||||
if (attribute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name;
|
||||
}
|
||||
|
||||
static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) {
|
||||
if (attribute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LocTextKey(attributeNameKey(attribute));
|
||||
}
|
||||
|
||||
static LocTextKey getToolTipKey(
|
||||
final ConfigurationAttribute attribute,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX;
|
||||
if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) {
|
||||
return null;
|
||||
} else {
|
||||
return new LocTextKey(attributeNameKey);
|
||||
}
|
||||
}
|
||||
|
||||
static LocTextKey getTablePopupTitleKey(
|
||||
final ConfigurationAttribute attribute,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,338 +1,336 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
public abstract class AbstractTableFieldBuilder implements InputFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class);
|
||||
|
||||
private static final int ROW_HEIGHT = 20;
|
||||
private static final int NAV_HEIGHT = 40;
|
||||
private static final int TABLE_WIDTH_SPACE = 50;
|
||||
|
||||
protected final RestService restService;
|
||||
protected final WidgetFactory widgetFactory;
|
||||
protected InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
|
||||
protected AbstractTableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
this.restService = restService;
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
}
|
||||
|
||||
protected Table createTable(final Composite parent, final TableContext tableContext) {
|
||||
final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL);
|
||||
table.setLayout(new GridLayout());
|
||||
final GridData gridData = new GridData(
|
||||
SWT.FILL, SWT.FILL,
|
||||
true, false,
|
||||
tableContext.orientation.width(),
|
||||
tableContext.orientation.height());
|
||||
|
||||
gridData.heightHint = tableContext.orientation.height() * ROW_HEIGHT + NAV_HEIGHT;
|
||||
table.setLayoutData(gridData);
|
||||
table.setHeaderVisible(true);
|
||||
table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
|
||||
return table;
|
||||
}
|
||||
|
||||
protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) {
|
||||
final TableContext tableContext = new TableContext(
|
||||
this.inputFieldBuilderSupplier,
|
||||
this.widgetFactory,
|
||||
attribute,
|
||||
viewContext);
|
||||
return tableContext;
|
||||
}
|
||||
|
||||
protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) {
|
||||
table.addListener(SWT.MouseDoubleClick, event -> {
|
||||
final int selectionIndex = table.getSelectionIndex();
|
||||
if (selectionIndex >= 0) {
|
||||
tableField.openForm(selectionIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
|
||||
try {
|
||||
final boolean readonly = tableContext.getViewContext().readonly;
|
||||
final int currentTableWidth = table.getClientArea().width - TABLE_WIDTH_SPACE;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final List<Orientation> orientations = tableContext
|
||||
.getColumnAttributes()
|
||||
.stream()
|
||||
.map(attr -> tableContext.getOrientation(attr.id))
|
||||
.collect(Collectors.toList());
|
||||
final Integer div = orientations
|
||||
.stream()
|
||||
.map(o -> o.width)
|
||||
.reduce(0, (acc, val) -> acc + val);
|
||||
final int widthUnit = currentTableWidth / div;
|
||||
for (int i = 0; i < columns.length - ((readonly) ? 0 : 2); i++) {
|
||||
columns[i].setWidth(widthUnit * orientations.get(i).width);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void setValueToCell(
|
||||
final TableContext tableContext,
|
||||
final TableItem item,
|
||||
final int cellIndex,
|
||||
final ConfigurationAttribute attribute,
|
||||
final TableValue tableValue) {
|
||||
|
||||
switch (attribute.type) {
|
||||
case CHECKBOX: {
|
||||
item.setImage(
|
||||
cellIndex,
|
||||
(BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null))
|
||||
? ImageIcon.YES.getImage(item.getDisplay())
|
||||
: ImageIcon.NO.getImage(item.getDisplay()));
|
||||
break;
|
||||
}
|
||||
case SINGLE_SELECTION: {
|
||||
final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.getName() + "." +
|
||||
tableValue.value;
|
||||
item.setText(
|
||||
cellIndex,
|
||||
tableContext.i18nSupport().getText(key, getValue(attribute, tableValue)));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
item.setText(cellIndex, getValue(attribute, tableValue));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getValue(
|
||||
final ConfigurationAttribute attribute,
|
||||
final TableValue tableValue) {
|
||||
|
||||
if (tableValue == null) {
|
||||
if (StringUtils.isBlank(attribute.defaultValue)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
} else {
|
||||
return attribute.defaultValue;
|
||||
}
|
||||
} else {
|
||||
if (StringUtils.isBlank(tableValue.value)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
} else {
|
||||
return tableValue.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class AbstractTableInputField extends AbstractInputField<Table> {
|
||||
|
||||
protected final TableContext tableContext;
|
||||
|
||||
protected AbstractTableInputField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Table control,
|
||||
final Label errorLabel,
|
||||
final TableContext tableContext) {
|
||||
|
||||
super(attribute, orientation, control, errorLabel);
|
||||
this.tableContext = tableContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationValue initValue(final Collection<ConfigurationValue> values) {
|
||||
clearTable();
|
||||
// get all child values as TableValues
|
||||
final List<TableValue> tableValues = getChildValues(
|
||||
this.tableContext,
|
||||
this.attribute,
|
||||
values);
|
||||
|
||||
initValue(tableValues);
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract void initValue(final List<TableValue> tableValues);
|
||||
|
||||
abstract void openForm(final int selectionIndex);
|
||||
|
||||
abstract void applyTableRowValues(final int index);
|
||||
|
||||
protected List<TableValue> getChildValues(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final Collection<ConfigurationValue> values) {
|
||||
|
||||
return values.stream()
|
||||
.filter(v -> isChildValue(tableContext, attribute, v))
|
||||
.map(TableValue::of)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected boolean isChildValue(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (!tableContext.getViewContext().attributeMapping.attributeIdMapping
|
||||
.containsKey(value.attributeId)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
|
||||
if (attr == null) {
|
||||
return false;
|
||||
}
|
||||
while (attr.parentId != null) {
|
||||
if (attribute.id.equals(attr.parentId)) {
|
||||
return true;
|
||||
}
|
||||
attr = tableContext.getAttribute(attr.parentId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
|
||||
tableValue.listIndex,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
}
|
||||
return indexMapping;
|
||||
}
|
||||
|
||||
protected void valuesFromIndexMap(
|
||||
final List<Map<Long, TableValue>> values,
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping) {
|
||||
|
||||
values.clear();
|
||||
final List<Integer> rows = new ArrayList<>(indexMapping.keySet());
|
||||
rows.sort((i1, i2) -> i1.compareTo(i2));
|
||||
rows
|
||||
.stream()
|
||||
.forEach(i -> {
|
||||
final Map<Long, TableValue> rowValues = indexMapping.get(i);
|
||||
values.add(rowValues);
|
||||
});
|
||||
}
|
||||
|
||||
protected void applyFormValues(
|
||||
final List<Map<Long, TableValue>> values,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final int index) {
|
||||
|
||||
if (!values.isEmpty()) {
|
||||
values.remove(index);
|
||||
values.add(index, rowValues);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
// send values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(values));
|
||||
}
|
||||
|
||||
protected ConfigurationTableValues extractTableValue(final List<Map<Long, TableValue>> values) {
|
||||
final List<TableValue> collect = values
|
||||
.stream()
|
||||
.flatMap(map -> map.values().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
collect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue() {
|
||||
// NOTE this just empty the list for now
|
||||
// TODO do we need default values for lists?
|
||||
clearTable();
|
||||
final List<TableValue> values = new ArrayList<>();
|
||||
this.tableContext.getValueChangeListener().tableChanged(
|
||||
new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
values));
|
||||
}
|
||||
|
||||
void clearTable() {
|
||||
this.control.setSelection(-1);
|
||||
if (this.control.getItemCount() > 0) {
|
||||
for (final TableItem item : this.control.getItems()) {
|
||||
item.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
public abstract class AbstractTableFieldBuilder implements InputFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class);
|
||||
|
||||
private static final int ROW_HEIGHT = 20;
|
||||
private static final int NAV_HEIGHT = 40;
|
||||
private static final int TABLE_WIDTH_SPACE = 50;
|
||||
|
||||
protected final RestService restService;
|
||||
protected final WidgetFactory widgetFactory;
|
||||
protected InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
|
||||
protected AbstractTableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
this.restService = restService;
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
}
|
||||
|
||||
protected Table createTable(final Composite parent, final TableContext tableContext) {
|
||||
final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL);
|
||||
table.setLayout(new GridLayout());
|
||||
final GridData gridData = new GridData(
|
||||
SWT.FILL, SWT.FILL,
|
||||
true, false,
|
||||
tableContext.orientation.width(),
|
||||
tableContext.orientation.height());
|
||||
|
||||
gridData.heightHint = tableContext.orientation.height() * ROW_HEIGHT + NAV_HEIGHT;
|
||||
table.setLayoutData(gridData);
|
||||
table.setHeaderVisible(true);
|
||||
table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
|
||||
return table;
|
||||
}
|
||||
|
||||
protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) {
|
||||
return new TableContext(
|
||||
this.inputFieldBuilderSupplier,
|
||||
this.widgetFactory,
|
||||
attribute,
|
||||
viewContext);
|
||||
}
|
||||
|
||||
protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) {
|
||||
table.addListener(SWT.MouseDoubleClick, event -> {
|
||||
final int selectionIndex = table.getSelectionIndex();
|
||||
if (selectionIndex >= 0) {
|
||||
tableField.openForm(selectionIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
|
||||
try {
|
||||
final boolean readonly = tableContext.getViewContext().readonly;
|
||||
final int currentTableWidth = table.getClientArea().width - TABLE_WIDTH_SPACE;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final List<Orientation> orientations = tableContext
|
||||
.getColumnAttributes()
|
||||
.stream()
|
||||
.map(attr -> tableContext.getOrientation(attr.id))
|
||||
.collect(Collectors.toList());
|
||||
final Integer div = orientations
|
||||
.stream()
|
||||
.map(o -> o.width)
|
||||
.reduce(0, Integer::sum);
|
||||
final int widthUnit = currentTableWidth / div;
|
||||
for (int i = 0; i < columns.length - ((readonly) ? 0 : 2); i++) {
|
||||
columns[i].setWidth(widthUnit * orientations.get(i).width);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void setValueToCell(
|
||||
final TableContext tableContext,
|
||||
final TableItem item,
|
||||
final int cellIndex,
|
||||
final ConfigurationAttribute attribute,
|
||||
final TableValue tableValue) {
|
||||
|
||||
switch (attribute.type) {
|
||||
case CHECKBOX: {
|
||||
item.setImage(
|
||||
cellIndex,
|
||||
(BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null))
|
||||
? ImageIcon.YES.getImage(item.getDisplay())
|
||||
: ImageIcon.NO.getImage(item.getDisplay()));
|
||||
break;
|
||||
}
|
||||
case SINGLE_SELECTION: {
|
||||
final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.getName() + "." +
|
||||
tableValue.value;
|
||||
item.setText(
|
||||
cellIndex,
|
||||
tableContext.i18nSupport().getText(key, getValue(attribute, tableValue)));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
item.setText(cellIndex, getValue(attribute, tableValue));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getValue(
|
||||
final ConfigurationAttribute attribute,
|
||||
final TableValue tableValue) {
|
||||
|
||||
if (tableValue == null) {
|
||||
if (StringUtils.isBlank(attribute.defaultValue)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
} else {
|
||||
return attribute.defaultValue;
|
||||
}
|
||||
} else {
|
||||
if (StringUtils.isBlank(tableValue.value)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
} else {
|
||||
return tableValue.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class AbstractTableInputField extends AbstractInputField<Table> {
|
||||
|
||||
protected final TableContext tableContext;
|
||||
|
||||
protected AbstractTableInputField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Table control,
|
||||
final Label errorLabel,
|
||||
final TableContext tableContext) {
|
||||
|
||||
super(attribute, orientation, control, errorLabel);
|
||||
this.tableContext = tableContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationValue initValue(final Collection<ConfigurationValue> values) {
|
||||
clearTable();
|
||||
// get all child values as TableValues
|
||||
final List<TableValue> tableValues = getChildValues(
|
||||
this.tableContext,
|
||||
this.attribute,
|
||||
values);
|
||||
|
||||
initValue(tableValues);
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract void initValue(final List<TableValue> tableValues);
|
||||
|
||||
abstract void openForm(final int selectionIndex);
|
||||
|
||||
abstract void applyTableRowValues(final int index);
|
||||
|
||||
protected List<TableValue> getChildValues(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final Collection<ConfigurationValue> values) {
|
||||
|
||||
return values.stream()
|
||||
.filter(v -> isChildValue(tableContext, attribute, v))
|
||||
.map(TableValue::of)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected boolean isChildValue(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (!tableContext.getViewContext().attributeMapping.attributeIdMapping
|
||||
.containsKey(value.attributeId)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
|
||||
if (attr == null) {
|
||||
return false;
|
||||
}
|
||||
while (attr.parentId != null) {
|
||||
if (attribute.id.equals(attr.parentId)) {
|
||||
return true;
|
||||
}
|
||||
attr = tableContext.getAttribute(attr.parentId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
|
||||
tableValue.listIndex,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
}
|
||||
return indexMapping;
|
||||
}
|
||||
|
||||
protected void valuesFromIndexMap(
|
||||
final List<Map<Long, TableValue>> values,
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping) {
|
||||
|
||||
values.clear();
|
||||
final List<Integer> rows = new ArrayList<>(indexMapping.keySet());
|
||||
rows.sort(Integer::compareTo);
|
||||
rows
|
||||
.forEach(i -> {
|
||||
final Map<Long, TableValue> rowValues = indexMapping.get(i);
|
||||
values.add(rowValues);
|
||||
});
|
||||
}
|
||||
|
||||
protected void applyFormValues(
|
||||
final List<Map<Long, TableValue>> values,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final int index) {
|
||||
|
||||
if (!values.isEmpty()) {
|
||||
values.remove(index);
|
||||
values.add(index, rowValues);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
// send values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(values));
|
||||
}
|
||||
|
||||
protected ConfigurationTableValues extractTableValue(final List<Map<Long, TableValue>> values) {
|
||||
final List<TableValue> collect = values
|
||||
.stream()
|
||||
.flatMap(map -> map.values().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
collect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue() {
|
||||
// NOTE this just empty the list for now
|
||||
// TODO do we need default values for lists?
|
||||
clearTable();
|
||||
final List<TableValue> values = new ArrayList<>();
|
||||
this.tableContext.getValueChangeListener().tableChanged(
|
||||
new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
values));
|
||||
}
|
||||
|
||||
void clearTable() {
|
||||
this.control.setSelection(-1);
|
||||
if (this.control.getItemCount() > 0) {
|
||||
for (final TableItem item : this.control.getItems()) {
|
||||
item.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,225 +1,225 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
interface CellFieldBuilderAdapter {
|
||||
|
||||
static CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[DUMMY]";
|
||||
}
|
||||
};
|
||||
|
||||
void createCell(ViewGridBuilder builder);
|
||||
|
||||
default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
|
||||
}
|
||||
|
||||
static CellFieldBuilderAdapter fieldBuilderAdapter(
|
||||
final InputFieldBuilder inputFieldBuilder,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
|
||||
final InputField inputField = inputFieldBuilder.createInputField(
|
||||
builder.parent,
|
||||
attribute,
|
||||
builder.viewContext);
|
||||
|
||||
if (inputField != null) {
|
||||
builder.viewContext.registerInputField(inputField);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[FIELD]";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static CellFieldBuilderAdapter labelBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
|
||||
private int span = 1;
|
||||
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
|
||||
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||
final Label label = widgetFactory.labelLocalized(
|
||||
builder.parent,
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name,
|
||||
attribute.name));
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
switch (orientation.title) {
|
||||
case LEFT:
|
||||
case RIGHT: {
|
||||
label.setAlignment(SWT.LEFT);
|
||||
gridData.verticalIndent = 5;
|
||||
break;
|
||||
}
|
||||
case RIGHT_SPAN:
|
||||
case LEFT_SPAN: {
|
||||
label.setAlignment(SWT.LEFT);
|
||||
gridData.horizontalSpan = (span > 1) ? span : orientation.width;
|
||||
gridData.verticalIndent = 5;
|
||||
break;
|
||||
}
|
||||
case TOP: {
|
||||
gridData.horizontalSpan = orientation.width;
|
||||
gridData.verticalAlignment = SWT.BOTTOM;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
label.setAlignment(SWT.LEFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
label.setLayoutData(gridData);
|
||||
label.pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
|
||||
if (grid[y][x] != this) {
|
||||
return;
|
||||
}
|
||||
if (orientation.title == TitleOrientation.LEFT_SPAN) {
|
||||
int xpos = x - 1;
|
||||
while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) {
|
||||
grid[y][xpos] = this;
|
||||
grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER;
|
||||
this.span++;
|
||||
xpos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[LABEL]";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static CellFieldBuilderAdapter passwordConfirmLabel(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||
final Label label = widgetFactory.labelLocalized(
|
||||
builder.parent,
|
||||
new LocTextKey(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name
|
||||
+ ".confirm"));
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
label.setAlignment(SWT.LEFT);
|
||||
gridData.verticalIndent = 20;
|
||||
label.setLayoutData(gridData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[PASSWORD CONFIRM LABEL]";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter {
|
||||
|
||||
final Collection<Orientation> orientationsOfGroup;
|
||||
|
||||
int x = 100;
|
||||
int y = 100;
|
||||
int width = 1;
|
||||
int height = 1;
|
||||
|
||||
GroupCellFieldBuilderAdapter(final Collection<Orientation> orientationsOfGroup) {
|
||||
this.orientationsOfGroup = orientationsOfGroup;
|
||||
|
||||
for (final Orientation o : this.orientationsOfGroup) {
|
||||
final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0);
|
||||
this.x = (xpos < this.x) ? xpos : this.x;
|
||||
final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0);
|
||||
this.y = (ypos < this.y) ? ypos : this.y;
|
||||
this.width = (this.width < o.xpos() + o.width()) ? o.xpos() + o.width() : this.width;
|
||||
this.height = (this.height < o.ypos() + o.height()) ? o.ypos() + o.height() : this.height;
|
||||
}
|
||||
|
||||
this.width = this.width - this.x;
|
||||
this.height = this.height - this.y + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||
final Orientation o = this.orientationsOfGroup.stream().findFirst().get();
|
||||
final LocTextKey groupLabelKey = new LocTextKey(
|
||||
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
|
||||
o.groupId,
|
||||
o.groupId);
|
||||
final LocTextKey groupTooltipKey = new LocTextKey(
|
||||
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
|
||||
o.groupId +
|
||||
ExamConfigurationService.TOOL_TIP_SUFFIX,
|
||||
o.groupId);
|
||||
|
||||
final Group group = widgetFactory.groupLocalized(
|
||||
builder.parent,
|
||||
this.width,
|
||||
groupLabelKey,
|
||||
groupTooltipKey);
|
||||
group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height));
|
||||
|
||||
final ViewGridBuilder groupBuilder = new ViewGridBuilder(
|
||||
group,
|
||||
builder.viewContext,
|
||||
this,
|
||||
builder.examConfigurationService);
|
||||
|
||||
for (final Orientation orientation : this.orientationsOfGroup) {
|
||||
final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId);
|
||||
groupBuilder.add(attribute);
|
||||
}
|
||||
groupBuilder.compose();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
interface CellFieldBuilderAdapter {
|
||||
|
||||
CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[DUMMY]";
|
||||
}
|
||||
};
|
||||
|
||||
void createCell(ViewGridBuilder builder);
|
||||
|
||||
default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
|
||||
}
|
||||
|
||||
static CellFieldBuilderAdapter fieldBuilderAdapter(
|
||||
final InputFieldBuilder inputFieldBuilder,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
|
||||
final InputField inputField = inputFieldBuilder.createInputField(
|
||||
builder.parent,
|
||||
attribute,
|
||||
builder.viewContext);
|
||||
|
||||
if (inputField != null) {
|
||||
builder.viewContext.registerInputField(inputField);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[FIELD]";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static CellFieldBuilderAdapter labelBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
|
||||
private int span = 1;
|
||||
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
|
||||
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||
final Label label = widgetFactory.labelLocalized(
|
||||
builder.parent,
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name,
|
||||
attribute.name));
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
switch (orientation.title) {
|
||||
case LEFT:
|
||||
case RIGHT: {
|
||||
label.setAlignment(SWT.LEFT);
|
||||
gridData.verticalIndent = 5;
|
||||
break;
|
||||
}
|
||||
case RIGHT_SPAN:
|
||||
case LEFT_SPAN: {
|
||||
label.setAlignment(SWT.LEFT);
|
||||
gridData.horizontalSpan = (span > 1) ? span : orientation.width;
|
||||
gridData.verticalIndent = 5;
|
||||
break;
|
||||
}
|
||||
case TOP: {
|
||||
gridData.horizontalSpan = orientation.width;
|
||||
gridData.verticalAlignment = SWT.BOTTOM;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
label.setAlignment(SWT.LEFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
label.setLayoutData(gridData);
|
||||
label.pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
|
||||
if (grid[y][x] != this) {
|
||||
return;
|
||||
}
|
||||
if (orientation.title == TitleOrientation.LEFT_SPAN) {
|
||||
int xpos = x - 1;
|
||||
while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) {
|
||||
grid[y][xpos] = this;
|
||||
grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER;
|
||||
this.span++;
|
||||
xpos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[LABEL]";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static CellFieldBuilderAdapter passwordConfirmLabel(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return new CellFieldBuilderAdapter() {
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||
final Label label = widgetFactory.labelLocalized(
|
||||
builder.parent,
|
||||
new LocTextKey(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name
|
||||
+ ".confirm"));
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
label.setAlignment(SWT.LEFT);
|
||||
gridData.verticalIndent = 20;
|
||||
label.setLayoutData(gridData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[PASSWORD CONFIRM LABEL]";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter {
|
||||
|
||||
final Collection<Orientation> orientationsOfGroup;
|
||||
|
||||
int x = 100;
|
||||
int y = 100;
|
||||
int width = 1;
|
||||
int height = 1;
|
||||
|
||||
GroupCellFieldBuilderAdapter(final Collection<Orientation> orientationsOfGroup) {
|
||||
this.orientationsOfGroup = orientationsOfGroup;
|
||||
|
||||
for (final Orientation o : this.orientationsOfGroup) {
|
||||
final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0);
|
||||
this.x = Math.min(xpos, this.x);
|
||||
final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0);
|
||||
this.y = Math.min(ypos, this.y);
|
||||
this.width = Math.max(this.width, o.xpos() + o.width());
|
||||
this.height = Math.max(this.height, o.ypos() + o.height());
|
||||
}
|
||||
|
||||
this.width = this.width - this.x;
|
||||
this.height = this.height - this.y + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createCell(final ViewGridBuilder builder) {
|
||||
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||
final Orientation o = this.orientationsOfGroup.stream().findFirst().orElse(null);
|
||||
final LocTextKey groupLabelKey = new LocTextKey(
|
||||
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
|
||||
o.groupId,
|
||||
o.groupId);
|
||||
final LocTextKey groupTooltipKey = new LocTextKey(
|
||||
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
|
||||
o.groupId +
|
||||
ExamConfigurationService.TOOL_TIP_SUFFIX,
|
||||
o.groupId);
|
||||
|
||||
final Group group = widgetFactory.groupLocalized(
|
||||
builder.parent,
|
||||
this.width,
|
||||
groupLabelKey,
|
||||
groupTooltipKey);
|
||||
group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height));
|
||||
|
||||
final ViewGridBuilder groupBuilder = new ViewGridBuilder(
|
||||
group,
|
||||
builder.viewContext,
|
||||
this,
|
||||
builder.examConfigurationService);
|
||||
|
||||
for (final Orientation orientation : this.orientationsOfGroup) {
|
||||
final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId);
|
||||
groupBuilder.add(attribute);
|
||||
}
|
||||
groupBuilder.compose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,134 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class CheckBoxBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected CheckBoxBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return attribute.type == AttributeType.CHECKBOX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
Objects.requireNonNull(parent);
|
||||
Objects.requireNonNull(attribute);
|
||||
Objects.requireNonNull(viewContext);
|
||||
|
||||
final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport();
|
||||
final Orientation orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
final Composite innerGrid = InputFieldBuilder
|
||||
.createInnerGrid(parent, attribute, orientation);
|
||||
|
||||
final Button checkbox = this.widgetFactory.buttonLocalized(
|
||||
innerGrid,
|
||||
SWT.CHECK,
|
||||
(orientation.title == TitleOrientation.NONE)
|
||||
? ExamConfigurationService.attributeNameLocKey(attribute)
|
||||
: null,
|
||||
ExamConfigurationService.getToolTipKey(attribute, i18nSupport));
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
|
||||
gridData.verticalIndent = 0;
|
||||
checkbox.setLayoutData(gridData);
|
||||
|
||||
final CheckboxField checkboxField = new CheckboxField(
|
||||
attribute,
|
||||
viewContext.getOrientation(attribute.id),
|
||||
checkbox);
|
||||
|
||||
if (viewContext.readonly) {
|
||||
checkbox.setEnabled(false);
|
||||
} else {
|
||||
checkbox.addListener(
|
||||
SWT.Selection,
|
||||
event -> viewContext.getValueChangeListener().valueChanged(
|
||||
viewContext,
|
||||
attribute,
|
||||
checkboxField.getValue(),
|
||||
checkboxField.listIndex));
|
||||
}
|
||||
|
||||
return checkboxField;
|
||||
}
|
||||
|
||||
static final class CheckboxField extends AbstractInputField<Button> {
|
||||
|
||||
CheckboxField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Button control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
this.control.setSelection(Boolean.valueOf(this.initValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getSelection()
|
||||
? Constants.TRUE_STRING
|
||||
: Constants.FALSE_STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadableValue() {
|
||||
return this.control.getSelection()
|
||||
? "Active"
|
||||
: "Inactive";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class CheckBoxBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected CheckBoxBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return attribute.type == AttributeType.CHECKBOX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
Objects.requireNonNull(parent);
|
||||
Objects.requireNonNull(attribute);
|
||||
Objects.requireNonNull(viewContext);
|
||||
|
||||
final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport();
|
||||
final Orientation orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
final Composite innerGrid = InputFieldBuilder
|
||||
.createInnerGrid(parent, attribute, orientation);
|
||||
|
||||
final Button checkbox = this.widgetFactory.buttonLocalized(
|
||||
innerGrid,
|
||||
SWT.CHECK,
|
||||
(orientation.title == TitleOrientation.NONE)
|
||||
? ExamConfigurationService.attributeNameLocKey(attribute)
|
||||
: null,
|
||||
ExamConfigurationService.getToolTipKey(attribute, i18nSupport));
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
|
||||
gridData.verticalIndent = 0;
|
||||
checkbox.setLayoutData(gridData);
|
||||
|
||||
final CheckboxField checkboxField = new CheckboxField(
|
||||
attribute,
|
||||
viewContext.getOrientation(attribute.id),
|
||||
checkbox);
|
||||
|
||||
if (viewContext.readonly) {
|
||||
checkbox.setEnabled(false);
|
||||
} else {
|
||||
checkbox.addListener(
|
||||
SWT.Selection,
|
||||
event -> viewContext.getValueChangeListener().valueChanged(
|
||||
viewContext,
|
||||
attribute,
|
||||
checkboxField.getValue(),
|
||||
checkboxField.listIndex));
|
||||
}
|
||||
|
||||
return checkboxField;
|
||||
}
|
||||
|
||||
static final class CheckboxField extends AbstractInputField<Button> {
|
||||
|
||||
CheckboxField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Button control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
this.control.setSelection(Boolean.parseBoolean(this.initValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getSelection()
|
||||
? Constants.TRUE_STRING
|
||||
: Constants.FALSE_STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadableValue() {
|
||||
return this.control.getSelection()
|
||||
? "Active"
|
||||
: "Inactive";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,270 +1,270 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
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.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class CompositeTableFieldBuilder extends AbstractTableFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CompositeTableFieldBuilder.class);
|
||||
|
||||
private static final String TABLE_ENTRY_NAME = "TABLE_ENTRY";
|
||||
private static final String TABLE_COLUMN_NAME_KEY = "TABLE_COLUMN_NAME";
|
||||
|
||||
protected CompositeTableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
super(restService, widgetFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return AttributeType.COMPOSITE_TABLE == attribute.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final I18nSupport i18nSupport = viewContext.getI18nSupport();
|
||||
final TableContext tableContext = createTableContext(attribute, viewContext);
|
||||
final Table table = createTable(parent, tableContext);
|
||||
|
||||
final String resources = attribute.getResources();
|
||||
final String[] columnsAndRows = StringUtils.split(
|
||||
resources,
|
||||
Constants.EMBEDDED_LIST_SEPARATOR);
|
||||
final String[] columns = (columnsAndRows.length == 2)
|
||||
? StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR)
|
||||
: new String[] { TABLE_ENTRY_NAME };
|
||||
final String[] rows = (columnsAndRows.length == 2)
|
||||
? StringUtils.split(columnsAndRows[1], Constants.LIST_SEPARATOR)
|
||||
: StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR);
|
||||
|
||||
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
final TableColumn column = this.widgetFactory.tableColumnLocalized(
|
||||
table,
|
||||
new LocTextKey(attributeNameKey + "." + columns[i]),
|
||||
new LocTextKey(attributeNameKey + "." + columns[i] + ".tootlip"));
|
||||
|
||||
column.setData(TABLE_COLUMN_NAME_KEY, columns[i]);
|
||||
column.setWidth(100);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
final TableItem item = new TableItem(table, SWT.NONE);
|
||||
for (int j = 0; j < columns.length; j++) {
|
||||
if (TABLE_ENTRY_NAME.equals(columns[j])) {
|
||||
item.setText(j, i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + rows[i],
|
||||
rows[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CompositeTableInputField tableField = new CompositeTableInputField(
|
||||
tableContext,
|
||||
table,
|
||||
Arrays.asList(columns),
|
||||
Arrays.asList(rows));
|
||||
|
||||
setSelectionListener(table, tableField);
|
||||
return tableField;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
|
||||
try {
|
||||
final int currentTableWidth = table.getClientArea().width - 50;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final int widthUnit = currentTableWidth / (columns.length + 2);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
final int factor = (TABLE_ENTRY_NAME.equals(columns[i].getData(TABLE_COLUMN_NAME_KEY))) ? 4 : 1;
|
||||
columns[i].setWidth(widthUnit * factor);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompositeTableInputField extends AbstractTableInputField {
|
||||
|
||||
final List<String> columns;
|
||||
final List<String> rows;
|
||||
final List<Map<Long, TableValue>> values;
|
||||
|
||||
CompositeTableInputField(
|
||||
final TableContext tableContext,
|
||||
final Table control,
|
||||
final List<String> columns,
|
||||
final List<String> rows) {
|
||||
|
||||
super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
|
||||
this.values = new ArrayList<>();
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
void initValue(final List<TableValue> tableValues) {
|
||||
valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
|
||||
for (int i = 0; i < this.values.size(); i++) {
|
||||
setRowValues(i, this.values.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTableRowValues(final int index) {
|
||||
setRowValues(index, this.values.get(index));
|
||||
}
|
||||
|
||||
private void setRowValues(final int index, final Map<Long, TableValue> map) {
|
||||
final TableItem rowItem = this.control.getItem(index);
|
||||
for (final TableValue val : map.values()) {
|
||||
final Orientation orientation = this.tableContext.getOrientation(val.attributeId);
|
||||
final String groupId = orientation.getGroupId();
|
||||
if (StringUtils.isNotBlank(groupId)) {
|
||||
final int cellIndex = this.columns.indexOf(groupId);
|
||||
if (cellIndex >= 0) {
|
||||
setValueToCell(
|
||||
this.tableContext,
|
||||
rowItem,
|
||||
cellIndex,
|
||||
this.tableContext.getAttribute(val.attributeId),
|
||||
val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openForm(final int selectionIndex) {
|
||||
final String row = this.rows.get(selectionIndex);
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
rowValues,
|
||||
row);
|
||||
|
||||
final ModalInputDialog<Map<Long, TableValue>> dialog = new ModalInputDialog<Map<Long, TableValue>>(
|
||||
this.control.getShell(),
|
||||
this.tableContext.getWidgetFactory())
|
||||
.setDialogWidth(500);
|
||||
|
||||
if (this.tableContext.getViewContext().readonly) {
|
||||
dialog.open(
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
|
||||
builder);
|
||||
} else {
|
||||
dialog.open(
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
|
||||
(Consumer<Map<Long, TableValue>>) rowVals -> applyFormValues(
|
||||
this.values,
|
||||
rowVals,
|
||||
selectionIndex),
|
||||
() -> this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values)),
|
||||
builder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final ConfigurationAttribute attribute = this.tableContext
|
||||
.getViewContext()
|
||||
.getAttribute(tableValue.attributeId);
|
||||
final String groupId = ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attribute);
|
||||
final int index = this.rows.indexOf(groupId);
|
||||
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
|
||||
index,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
}
|
||||
return indexMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
void clearTable() {
|
||||
// nothing to clear for this table type
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isChildValue(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
final boolean childValue = super.isChildValue(tableContext, attribute, value);
|
||||
if (childValue) {
|
||||
final ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
|
||||
return ConfigurationAttribute.hasDependency(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attr);
|
||||
}
|
||||
|
||||
return childValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
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.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class CompositeTableFieldBuilder extends AbstractTableFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CompositeTableFieldBuilder.class);
|
||||
|
||||
private static final String TABLE_ENTRY_NAME = "TABLE_ENTRY";
|
||||
private static final String TABLE_COLUMN_NAME_KEY = "TABLE_COLUMN_NAME";
|
||||
|
||||
protected CompositeTableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
super(restService, widgetFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return AttributeType.COMPOSITE_TABLE == attribute.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final I18nSupport i18nSupport = viewContext.getI18nSupport();
|
||||
final TableContext tableContext = createTableContext(attribute, viewContext);
|
||||
final Table table = createTable(parent, tableContext);
|
||||
|
||||
final String resources = attribute.getResources();
|
||||
final String[] columnsAndRows = StringUtils.split(
|
||||
resources,
|
||||
Constants.EMBEDDED_LIST_SEPARATOR);
|
||||
final String[] columns = (columnsAndRows.length == 2)
|
||||
? StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR)
|
||||
: new String[] { TABLE_ENTRY_NAME };
|
||||
final String[] rows = (columnsAndRows.length == 2)
|
||||
? StringUtils.split(columnsAndRows[1], Constants.LIST_SEPARATOR)
|
||||
: StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR);
|
||||
|
||||
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
final TableColumn column = this.widgetFactory.tableColumnLocalized(
|
||||
table,
|
||||
new LocTextKey(attributeNameKey + "." + columns[i]),
|
||||
new LocTextKey(attributeNameKey + "." + columns[i] + ".tootlip"));
|
||||
|
||||
column.setData(TABLE_COLUMN_NAME_KEY, columns[i]);
|
||||
column.setWidth(100);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
final TableItem item = new TableItem(table, SWT.NONE);
|
||||
for (int j = 0; j < columns.length; j++) {
|
||||
if (TABLE_ENTRY_NAME.equals(columns[j])) {
|
||||
item.setText(j, i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + rows[i],
|
||||
rows[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CompositeTableInputField tableField = new CompositeTableInputField(
|
||||
tableContext,
|
||||
table,
|
||||
Arrays.asList(columns),
|
||||
Arrays.asList(rows));
|
||||
|
||||
setSelectionListener(table, tableField);
|
||||
return tableField;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
|
||||
try {
|
||||
final int currentTableWidth = table.getClientArea().width - 50;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final int widthUnit = currentTableWidth / (columns.length + 2);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
final int factor = (TABLE_ENTRY_NAME.equals(columns[i].getData(TABLE_COLUMN_NAME_KEY))) ? 4 : 1;
|
||||
columns[i].setWidth(widthUnit * factor);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompositeTableInputField extends AbstractTableInputField {
|
||||
|
||||
final List<String> columns;
|
||||
final List<String> rows;
|
||||
final List<Map<Long, TableValue>> values;
|
||||
|
||||
CompositeTableInputField(
|
||||
final TableContext tableContext,
|
||||
final Table control,
|
||||
final List<String> columns,
|
||||
final List<String> rows) {
|
||||
|
||||
super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
|
||||
this.values = new ArrayList<>();
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
void initValue(final List<TableValue> tableValues) {
|
||||
valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
|
||||
for (int i = 0; i < this.values.size(); i++) {
|
||||
setRowValues(i, this.values.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTableRowValues(final int index) {
|
||||
setRowValues(index, this.values.get(index));
|
||||
}
|
||||
|
||||
private void setRowValues(final int index, final Map<Long, TableValue> map) {
|
||||
final TableItem rowItem = this.control.getItem(index);
|
||||
for (final TableValue val : map.values()) {
|
||||
final Orientation orientation = this.tableContext.getOrientation(val.attributeId);
|
||||
final String groupId = orientation.getGroupId();
|
||||
if (StringUtils.isNotBlank(groupId)) {
|
||||
final int cellIndex = this.columns.indexOf(groupId);
|
||||
if (cellIndex >= 0) {
|
||||
setValueToCell(
|
||||
this.tableContext,
|
||||
rowItem,
|
||||
cellIndex,
|
||||
this.tableContext.getAttribute(val.attributeId),
|
||||
val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openForm(final int selectionIndex) {
|
||||
final String row = this.rows.get(selectionIndex);
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
rowValues,
|
||||
row);
|
||||
|
||||
final ModalInputDialog<Map<Long, TableValue>> dialog = new ModalInputDialog<Map<Long, TableValue>>(
|
||||
this.control.getShell(),
|
||||
this.tableContext.getWidgetFactory())
|
||||
.setDialogWidth(500);
|
||||
|
||||
if (this.tableContext.getViewContext().readonly) {
|
||||
dialog.open(
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
|
||||
builder);
|
||||
} else {
|
||||
dialog.open(
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
|
||||
(Consumer<Map<Long, TableValue>>) _rowValues -> applyFormValues(
|
||||
this.values,
|
||||
_rowValues,
|
||||
selectionIndex),
|
||||
() -> this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values)),
|
||||
builder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final ConfigurationAttribute attribute = this.tableContext
|
||||
.getViewContext()
|
||||
.getAttribute(tableValue.attributeId);
|
||||
final String groupId = ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attribute);
|
||||
final int index = this.rows.indexOf(groupId);
|
||||
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
|
||||
index,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
}
|
||||
return indexMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
void clearTable() {
|
||||
// nothing to clear for this table type
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isChildValue(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
final boolean childValue = super.isChildValue(tableContext, attribute, value);
|
||||
if (childValue) {
|
||||
final ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
|
||||
return ConfigurationAttribute.hasDependency(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attr);
|
||||
}
|
||||
|
||||
return childValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,423 +1,414 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
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.ConfigurationTableValues;
|
||||
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.TemplateAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
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.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.FieldValidationError;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
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.GetConfigAttributes;
|
||||
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.GetOrientations;
|
||||
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.RemoveOrientation;
|
||||
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.SaveExamConfigTableValues;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class);
|
||||
|
||||
private final RestService restService;
|
||||
private final JSONMapper jsonMapper;
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
private final InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
private final Collection<ValueChangeRule> valueChangeRules;
|
||||
|
||||
public ExamConfigurationServiceImpl(
|
||||
final RestService restService,
|
||||
final JSONMapper jsonMapper,
|
||||
final WidgetFactory widgetFactory,
|
||||
final InputFieldBuilderSupplier inputFieldBuilderSupplier,
|
||||
final Collection<ValueChangeRule> valueChangeRules) {
|
||||
|
||||
this.restService = restService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
this.valueChangeRules = Utils.immutableCollectionOf(valueChangeRules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WidgetFactory getWidgetFactory() {
|
||||
return this.widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputFieldBuilder getInputFieldBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilderSupplier.getInputFieldBuilder(attribute, orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<AttributeMapping> getAttributes(final Long templateId) {
|
||||
return Result.tryCatch(() -> {
|
||||
return new AttributeMapping(
|
||||
templateId,
|
||||
getAttributes(),
|
||||
getOrientations(templateId));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<AttributeMapping> getAttributes(
|
||||
final TemplateAttribute attribute,
|
||||
final Orientation defaultOrientation) {
|
||||
|
||||
final List<Orientation> orientations = getOrientations(attribute.templateId);
|
||||
if (attribute.getOrientation() == null) {
|
||||
orientations.add(defaultOrientation);
|
||||
}
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
return new AttributeMapping(
|
||||
attribute.templateId,
|
||||
getAttributes(),
|
||||
orientations);
|
||||
});
|
||||
}
|
||||
|
||||
private List<Orientation> getOrientations(final Long templateId) {
|
||||
return this.restService
|
||||
.getBuilder(GetOrientations.class)
|
||||
.withQueryParam(Orientation.FILTER_ATTR_TEMPLATE_ID, String.valueOf(templateId))
|
||||
.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)
|
||||
.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();
|
||||
if (viewIds == null || viewIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final String ids = StringUtils.join(
|
||||
viewIds
|
||||
.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.toList()),
|
||||
Constants.LIST_SEPARATOR_CHAR);
|
||||
|
||||
return this.restService.getBuilder(GetViewList.class)
|
||||
.withQueryParam(API.PARAM_MODEL_ID_LIST, ids)
|
||||
.call()
|
||||
.getOrThrow()
|
||||
.stream()
|
||||
.sorted((v1, v2) -> v1.position.compareTo(v2.position))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewContext createViewContext(
|
||||
final PageContext pageContext,
|
||||
final Configuration configuration,
|
||||
final View view,
|
||||
final AttributeMapping attributeMapping,
|
||||
final int rows,
|
||||
final boolean readonly) {
|
||||
|
||||
return new ViewContext(
|
||||
configuration,
|
||||
view,
|
||||
rows,
|
||||
attributeMapping,
|
||||
new ValueChangeListenerImpl(
|
||||
pageContext,
|
||||
this.restService,
|
||||
this.jsonMapper,
|
||||
this.valueChangeRules),
|
||||
this.widgetFactory.getI18nSupport(),
|
||||
readonly);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Composite createViewGrid(final Composite parent, final ViewContext viewContext) {
|
||||
final Composite composite = new Composite(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(viewContext.getColumns(), true);
|
||||
gridLayout.verticalSpacing = 0;
|
||||
composite.setLayout(gridLayout);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
composite.setLayoutData(gridData);
|
||||
|
||||
final ViewGridBuilder viewGridBuilder = new ViewGridBuilder(
|
||||
composite,
|
||||
viewContext,
|
||||
this);
|
||||
|
||||
for (final ConfigurationAttribute attribute : viewContext.getAttributes()) {
|
||||
final Orientation orientation = viewContext.getOrientation(attribute.id);
|
||||
if (orientation != null && viewContext.getId().equals(orientation.viewId)) {
|
||||
viewGridBuilder.add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
viewGridBuilder.compose();
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initInputFieldValues(
|
||||
final Long configurationId,
|
||||
final Collection<ViewContext> viewContexts) {
|
||||
|
||||
if (viewContexts == null || viewContexts.size() < 1) {
|
||||
log.warn("No viewContexts available");
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<ConfigurationValue> attributeValues = this.restService
|
||||
.getBuilder(GetConfigurationValues.class)
|
||||
.withQueryParam(
|
||||
ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID,
|
||||
String.valueOf(configurationId))
|
||||
.call()
|
||||
.onError(t -> log.error(
|
||||
"Failed to get all ConfigurationValue for configuration with id: {}",
|
||||
configurationId))
|
||||
.getOrElse(Collections::emptyList);
|
||||
|
||||
viewContexts
|
||||
.forEach(vc -> vc.setValuesToInputFields(attributeValues));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PageAction resetToDefaults(final PageAction action) {
|
||||
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
|
||||
final Set<EntityKey> selection = action.getMultiSelection();
|
||||
if (selection != null && !selection.isEmpty()) {
|
||||
selection.stream().forEach(entityKey -> {
|
||||
callTemplateAction(
|
||||
ResetTemplateValues.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
});
|
||||
} else {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
callTemplateAction(
|
||||
ResetTemplateValues.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PageAction removeFromView(final PageAction action) {
|
||||
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
|
||||
final Set<EntityKey> selection = action.getMultiSelection();
|
||||
if (selection != null && !selection.isEmpty()) {
|
||||
selection.stream().forEach(entityKey -> {
|
||||
callTemplateAction(
|
||||
RemoveOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
});
|
||||
} else {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
callTemplateAction(
|
||||
RemoveOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PageAction attachToDefaultView(final PageAction action) {
|
||||
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
|
||||
final Set<EntityKey> selection = action.getMultiSelection();
|
||||
if (selection != null && !selection.isEmpty()) {
|
||||
selection.stream().forEach(entityKey -> {
|
||||
callTemplateAction(
|
||||
AttachDefaultOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
});
|
||||
} else {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
callTemplateAction(
|
||||
AttachDefaultOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
private void callTemplateAction(
|
||||
final Class<? extends RestCall<TemplateAttribute>> actionType,
|
||||
final String templateId,
|
||||
final String attributeId) {
|
||||
|
||||
this.restService.getBuilder(actionType)
|
||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, attributeId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
private static final class ValueChangeListenerImpl implements ValueChangeListener {
|
||||
|
||||
public static final String VALIDATION_ERROR_KEY_PREFIX = "sebserver.examconfig.props.validation.";
|
||||
|
||||
private final PageContext pageContext;
|
||||
private final RestService restService;
|
||||
private final JSONMapper jsonMapper;
|
||||
private final Collection<ValueChangeRule> valueChangeRules;
|
||||
|
||||
protected ValueChangeListenerImpl(
|
||||
final PageContext pageContext,
|
||||
final RestService restService,
|
||||
final JSONMapper jsonMapper,
|
||||
final Collection<ValueChangeRule> valueChangeRules) {
|
||||
|
||||
this.pageContext = pageContext;
|
||||
this.restService = restService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.valueChangeRules = valueChangeRules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribute,
|
||||
final String value,
|
||||
final int listIndex) {
|
||||
|
||||
final ConfigurationValue configurationValue = new ConfigurationValue(
|
||||
null,
|
||||
context.getInstitutionId(),
|
||||
context.getConfigurationId(),
|
||||
attribute.id,
|
||||
listIndex,
|
||||
value);
|
||||
|
||||
try {
|
||||
final String jsonValue = this.jsonMapper.writeValueAsString(configurationValue);
|
||||
|
||||
final Result<ConfigurationValue> savedValue = this.restService.getBuilder(SaveExamConfigValue.class)
|
||||
.withBody(jsonValue)
|
||||
.call();
|
||||
|
||||
if (savedValue.hasError()) {
|
||||
context.showError(attribute.id, verifyErrorMessage(savedValue.getError()));
|
||||
} else {
|
||||
this.notifyGUI(context, attribute, savedValue.get());
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
this.pageContext.notifySaveError(EntityType.CONFIGURATION_VALUE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tableChanged(final ConfigurationTableValues tableValue) {
|
||||
this.restService.getBuilder(SaveExamConfigTableValues.class)
|
||||
.withBody(tableValue)
|
||||
.call();
|
||||
}
|
||||
|
||||
private String verifyErrorMessage(final Exception error) {
|
||||
if (error instanceof RestCallError) {
|
||||
final List<APIMessage> errorMessages = ((RestCallError) error).getErrorMessages();
|
||||
if (errorMessages.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final APIMessage apiMessage = errorMessages.get(0);
|
||||
if (!ErrorMessage.FIELD_VALIDATION.isOf(apiMessage)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final FieldValidationError fieldValidationError = new FieldValidationError(apiMessage);
|
||||
return this.pageContext.getI18nSupport().getText(new LocTextKey(
|
||||
VALIDATION_ERROR_KEY_PREFIX + fieldValidationError.errorType,
|
||||
(Object[]) fieldValidationError.getAttributes()));
|
||||
}
|
||||
|
||||
log.warn("Unexpected error happened while trying to set SEB configuration value: ", error);
|
||||
return VALIDATION_ERROR_KEY_PREFIX + "unexpected";
|
||||
}
|
||||
|
||||
@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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
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.ConfigurationTableValues;
|
||||
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.TemplateAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
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.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.FieldValidationError;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
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.GetConfigAttributes;
|
||||
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.GetOrientations;
|
||||
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.RemoveOrientation;
|
||||
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.SaveExamConfigTableValues;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class);
|
||||
|
||||
private final RestService restService;
|
||||
private final JSONMapper jsonMapper;
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
private final InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
private final Collection<ValueChangeRule> valueChangeRules;
|
||||
|
||||
public ExamConfigurationServiceImpl(
|
||||
final RestService restService,
|
||||
final JSONMapper jsonMapper,
|
||||
final WidgetFactory widgetFactory,
|
||||
final InputFieldBuilderSupplier inputFieldBuilderSupplier,
|
||||
final Collection<ValueChangeRule> valueChangeRules) {
|
||||
|
||||
this.restService = restService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
this.valueChangeRules = Utils.immutableCollectionOf(valueChangeRules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WidgetFactory getWidgetFactory() {
|
||||
return this.widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputFieldBuilder getInputFieldBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilderSupplier.getInputFieldBuilder(attribute, orientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<AttributeMapping> getAttributes(final Long templateId) {
|
||||
return Result.tryCatch(() -> new AttributeMapping(
|
||||
templateId,
|
||||
getAttributes(),
|
||||
getOrientations(templateId)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<AttributeMapping> getAttributes(
|
||||
final TemplateAttribute attribute,
|
||||
final Orientation defaultOrientation) {
|
||||
|
||||
final List<Orientation> orientations = getOrientations(attribute.templateId);
|
||||
if (attribute.getOrientation() == null) {
|
||||
orientations.add(defaultOrientation);
|
||||
}
|
||||
|
||||
return Result.tryCatch(() -> new AttributeMapping(
|
||||
attribute.templateId,
|
||||
getAttributes(),
|
||||
orientations));
|
||||
}
|
||||
|
||||
private List<Orientation> getOrientations(final Long templateId) {
|
||||
return this.restService
|
||||
.getBuilder(GetOrientations.class)
|
||||
.withQueryParam(Orientation.FILTER_ATTR_TEMPLATE_ID, String.valueOf(templateId))
|
||||
.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)
|
||||
.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();
|
||||
if (viewIds == null || viewIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final String ids = StringUtils.join(
|
||||
viewIds
|
||||
.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.toList()),
|
||||
Constants.LIST_SEPARATOR_CHAR);
|
||||
|
||||
return this.restService.getBuilder(GetViewList.class)
|
||||
.withQueryParam(API.PARAM_MODEL_ID_LIST, ids)
|
||||
.call()
|
||||
.getOrThrow()
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(v -> v.position))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewContext createViewContext(
|
||||
final PageContext pageContext,
|
||||
final Configuration configuration,
|
||||
final View view,
|
||||
final AttributeMapping attributeMapping,
|
||||
final int rows,
|
||||
final boolean readonly) {
|
||||
|
||||
return new ViewContext(
|
||||
configuration,
|
||||
view,
|
||||
rows,
|
||||
attributeMapping,
|
||||
new ValueChangeListenerImpl(
|
||||
pageContext,
|
||||
this.restService,
|
||||
this.jsonMapper,
|
||||
this.valueChangeRules),
|
||||
this.widgetFactory.getI18nSupport(),
|
||||
readonly);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Composite createViewGrid(final Composite parent, final ViewContext viewContext) {
|
||||
final Composite composite = new Composite(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(viewContext.getColumns(), true);
|
||||
gridLayout.verticalSpacing = 0;
|
||||
composite.setLayout(gridLayout);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
composite.setLayoutData(gridData);
|
||||
|
||||
final ViewGridBuilder viewGridBuilder = new ViewGridBuilder(
|
||||
composite,
|
||||
viewContext,
|
||||
this);
|
||||
|
||||
for (final ConfigurationAttribute attribute : viewContext.getAttributes()) {
|
||||
final Orientation orientation = viewContext.getOrientation(attribute.id);
|
||||
if (orientation != null && viewContext.getId().equals(orientation.viewId)) {
|
||||
viewGridBuilder.add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
viewGridBuilder.compose();
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initInputFieldValues(
|
||||
final Long configurationId,
|
||||
final Collection<ViewContext> viewContexts) {
|
||||
|
||||
if (viewContexts == null || viewContexts.size() < 1) {
|
||||
log.warn("No viewContexts available");
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<ConfigurationValue> attributeValues = this.restService
|
||||
.getBuilder(GetConfigurationValues.class)
|
||||
.withQueryParam(
|
||||
ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID,
|
||||
String.valueOf(configurationId))
|
||||
.call()
|
||||
.onError(t -> log.error(
|
||||
"Failed to get all ConfigurationValue for configuration with id: {}",
|
||||
configurationId))
|
||||
.getOrElse(Collections::emptyList);
|
||||
|
||||
viewContexts
|
||||
.forEach(vc -> vc.setValuesToInputFields(attributeValues));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PageAction resetToDefaults(final PageAction action) {
|
||||
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
|
||||
final Set<EntityKey> selection = action.getMultiSelection();
|
||||
if (selection != null && !selection.isEmpty()) {
|
||||
selection.forEach(entityKey -> callTemplateAction(
|
||||
ResetTemplateValues.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId));
|
||||
} else {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
callTemplateAction(
|
||||
ResetTemplateValues.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PageAction removeFromView(final PageAction action) {
|
||||
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
|
||||
final Set<EntityKey> selection = action.getMultiSelection();
|
||||
if (selection != null && !selection.isEmpty()) {
|
||||
selection.forEach(entityKey -> callTemplateAction(
|
||||
RemoveOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId));
|
||||
} else {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
callTemplateAction(
|
||||
RemoveOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PageAction attachToDefaultView(final PageAction action) {
|
||||
final EntityKey parentEntityKey = action.pageContext().getParentEntityKey();
|
||||
final Set<EntityKey> selection = action.getMultiSelection();
|
||||
if (selection != null && !selection.isEmpty()) {
|
||||
selection.forEach(entityKey -> callTemplateAction(
|
||||
AttachDefaultOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId));
|
||||
} else {
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
callTemplateAction(
|
||||
AttachDefaultOrientation.class,
|
||||
parentEntityKey.modelId,
|
||||
entityKey.modelId);
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
private void callTemplateAction(
|
||||
final Class<? extends RestCall<TemplateAttribute>> actionType,
|
||||
final String templateId,
|
||||
final String attributeId) {
|
||||
|
||||
this.restService.getBuilder(actionType)
|
||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, attributeId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
private static final class ValueChangeListenerImpl implements ValueChangeListener {
|
||||
|
||||
public static final String VALIDATION_ERROR_KEY_PREFIX = "sebserver.examconfig.props.validation.";
|
||||
|
||||
private final PageContext pageContext;
|
||||
private final RestService restService;
|
||||
private final JSONMapper jsonMapper;
|
||||
private final Collection<ValueChangeRule> valueChangeRules;
|
||||
|
||||
protected ValueChangeListenerImpl(
|
||||
final PageContext pageContext,
|
||||
final RestService restService,
|
||||
final JSONMapper jsonMapper,
|
||||
final Collection<ValueChangeRule> valueChangeRules) {
|
||||
|
||||
this.pageContext = pageContext;
|
||||
this.restService = restService;
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.valueChangeRules = valueChangeRules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribute,
|
||||
final String value,
|
||||
final int listIndex) {
|
||||
|
||||
final ConfigurationValue configurationValue = new ConfigurationValue(
|
||||
null,
|
||||
context.getInstitutionId(),
|
||||
context.getConfigurationId(),
|
||||
attribute.id,
|
||||
listIndex,
|
||||
value);
|
||||
|
||||
try {
|
||||
final String jsonValue = this.jsonMapper.writeValueAsString(configurationValue);
|
||||
|
||||
final Result<ConfigurationValue> savedValue = this.restService.getBuilder(SaveExamConfigValue.class)
|
||||
.withBody(jsonValue)
|
||||
.call();
|
||||
|
||||
if (savedValue.hasError()) {
|
||||
context.showError(attribute.id, verifyErrorMessage(savedValue.getError()));
|
||||
} else {
|
||||
this.notifyGUI(context, attribute, savedValue.get());
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
this.pageContext.notifySaveError(EntityType.CONFIGURATION_VALUE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tableChanged(final ConfigurationTableValues tableValue) {
|
||||
this.restService.getBuilder(SaveExamConfigTableValues.class)
|
||||
.withBody(tableValue)
|
||||
.call();
|
||||
}
|
||||
|
||||
private String verifyErrorMessage(final Exception error) {
|
||||
if (error instanceof RestCallError) {
|
||||
final List<APIMessage> errorMessages = ((RestCallError) error).getErrorMessages();
|
||||
if (errorMessages.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final APIMessage apiMessage = errorMessages.get(0);
|
||||
if (!ErrorMessage.FIELD_VALIDATION.isOf(apiMessage)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final FieldValidationError fieldValidationError = new FieldValidationError(apiMessage);
|
||||
return this.pageContext.getI18nSupport().getText(new LocTextKey(
|
||||
VALIDATION_ERROR_KEY_PREFIX + fieldValidationError.errorType,
|
||||
(Object[]) fieldValidationError.getAttributes()));
|
||||
}
|
||||
|
||||
log.warn("Unexpected error happened while trying to set SEB configuration value: ", error);
|
||||
return VALIDATION_ERROR_KEY_PREFIX + "unexpected";
|
||||
}
|
||||
|
||||
@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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,132 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.widget.GridTable;
|
||||
import ch.ethz.seb.sebserver.gui.widget.GridTable.ColumnDef;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class InlineTableFieldBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected InlineTableFieldBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return attribute != null && attribute.type == AttributeType.INLINE_TABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final Orientation orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
final Composite innerGrid = InputFieldBuilder
|
||||
.createInnerGrid(parent, attribute, orientation);
|
||||
|
||||
final Map<String, String> defaultValues = StringUtils.isBlank(attribute.defaultValue)
|
||||
? Collections.emptyMap()
|
||||
: Arrays.asList(StringUtils.split(
|
||||
attribute.defaultValue,
|
||||
Constants.EMBEDDED_LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(valueString -> StringUtils.split(
|
||||
valueString,
|
||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
|
||||
.collect(Collectors.toMap(
|
||||
valueMap -> valueMap[0],
|
||||
valueMap -> (valueMap.length > 1) ? valueMap[1] : StringUtils.EMPTY));
|
||||
|
||||
final List<ColumnDef> columns = Arrays.asList(StringUtils.split(
|
||||
attribute.getResources(),
|
||||
Constants.EMBEDDED_LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(columnString -> ColumnDef.fromString(columnString, defaultValues))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final GridTable gridTable = new GridTable(
|
||||
innerGrid,
|
||||
columns,
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".",
|
||||
this.widgetFactory);
|
||||
|
||||
final InlineTableInputField inlineTableInputField = new InlineTableInputField(
|
||||
attribute,
|
||||
viewContext.getOrientation(attribute.id),
|
||||
gridTable);
|
||||
|
||||
if (viewContext.readonly) {
|
||||
gridTable.setEnabled(false);
|
||||
gridTable.setListener(event -> {
|
||||
});
|
||||
} else {
|
||||
gridTable.setListener(event -> viewContext.getValueChangeListener().valueChanged(
|
||||
viewContext,
|
||||
attribute,
|
||||
inlineTableInputField.getValue(),
|
||||
inlineTableInputField.listIndex));
|
||||
}
|
||||
|
||||
return inlineTableInputField;
|
||||
|
||||
}
|
||||
|
||||
static final class InlineTableInputField extends AbstractInputField<GridTable> {
|
||||
|
||||
protected InlineTableInputField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final GridTable control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
this.control.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.widget.GridTable;
|
||||
import ch.ethz.seb.sebserver.gui.widget.GridTable.ColumnDef;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class InlineTableFieldBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected InlineTableFieldBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return attribute != null && attribute.type == AttributeType.INLINE_TABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final Orientation orientation = viewContext
|
||||
.getOrientation(attribute.id);
|
||||
final Composite innerGrid = InputFieldBuilder
|
||||
.createInnerGrid(parent, attribute, orientation);
|
||||
|
||||
final Map<String, String> defaultValues = StringUtils.isBlank(attribute.defaultValue)
|
||||
? Collections.emptyMap()
|
||||
: Arrays.stream(StringUtils.split(
|
||||
attribute.defaultValue,
|
||||
Constants.EMBEDDED_LIST_SEPARATOR))
|
||||
.map(valueString -> StringUtils.split(
|
||||
valueString,
|
||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
|
||||
.collect(Collectors.toMap(
|
||||
valueMap -> valueMap[0],
|
||||
valueMap -> (valueMap.length > 1) ? valueMap[1] : StringUtils.EMPTY));
|
||||
|
||||
final List<ColumnDef> columns = Arrays.stream(StringUtils.split(
|
||||
attribute.getResources(),
|
||||
Constants.EMBEDDED_LIST_SEPARATOR))
|
||||
.map(columnString -> ColumnDef.fromString(columnString, defaultValues))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final GridTable gridTable = new GridTable(
|
||||
innerGrid,
|
||||
columns,
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".",
|
||||
this.widgetFactory);
|
||||
|
||||
final InlineTableInputField inlineTableInputField = new InlineTableInputField(
|
||||
attribute,
|
||||
viewContext.getOrientation(attribute.id),
|
||||
gridTable);
|
||||
|
||||
if (viewContext.readonly) {
|
||||
gridTable.setEnabled(false);
|
||||
gridTable.setListener(event -> {
|
||||
});
|
||||
} else {
|
||||
gridTable.setListener(event -> viewContext.getValueChangeListener().valueChanged(
|
||||
viewContext,
|
||||
attribute,
|
||||
inlineTableInputField.getValue(),
|
||||
inlineTableInputField.listIndex));
|
||||
}
|
||||
|
||||
return inlineTableInputField;
|
||||
|
||||
}
|
||||
|
||||
static final class InlineTableInputField extends AbstractInputField<GridTable> {
|
||||
|
||||
protected InlineTableInputField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final GridTable control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
this.control.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,47 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class InputFieldBuilderSupplier {
|
||||
|
||||
private final Collection<InputFieldBuilder> inputFieldBuilder;
|
||||
|
||||
protected InputFieldBuilderSupplier(final Collection<InputFieldBuilder> inputFieldBuilder) {
|
||||
this.inputFieldBuilder = inputFieldBuilder;
|
||||
inputFieldBuilder
|
||||
.stream()
|
||||
.forEach(builder -> builder.init(this));
|
||||
}
|
||||
|
||||
public InputFieldBuilder getInputFieldBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilder
|
||||
.stream()
|
||||
.filter(b -> b.builderFor(attribute, orientation))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NoSuchElementException("No InputFieldBuilder found for : " + attribute.type));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class InputFieldBuilderSupplier {
|
||||
|
||||
private final Collection<InputFieldBuilder> inputFieldBuilder;
|
||||
|
||||
protected InputFieldBuilderSupplier(final Collection<InputFieldBuilder> inputFieldBuilder) {
|
||||
this.inputFieldBuilder = inputFieldBuilder;
|
||||
inputFieldBuilder
|
||||
.forEach(builder -> builder.init(this));
|
||||
}
|
||||
|
||||
public InputFieldBuilder getInputFieldBuilder(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
return this.inputFieldBuilder
|
||||
.stream()
|
||||
.filter(b -> b.builderFor(attribute, orientation))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NoSuchElementException("No InputFieldBuilder found for : " + attribute.type));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,86 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class LabelBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected LabelBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return attribute.type == AttributeType.LABEL;
|
||||
};
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final Label label = this.widgetFactory.labelLocalized(
|
||||
parent,
|
||||
ExamConfigurationService.attributeNameLocKey(attribute));
|
||||
|
||||
return new LabelField(
|
||||
attribute,
|
||||
viewContext.getOrientation(attribute.id),
|
||||
label);
|
||||
}
|
||||
|
||||
static final class LabelField extends AbstractInputField<Label> {
|
||||
|
||||
LabelField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Label control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
// Does Nothing, Label has no default value
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getText();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class LabelBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected LabelBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return attribute.type == AttributeType.LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final Label label = this.widgetFactory.labelLocalized(
|
||||
parent,
|
||||
ExamConfigurationService.attributeNameLocKey(attribute));
|
||||
|
||||
return new LabelField(
|
||||
attribute,
|
||||
viewContext.getOrientation(attribute.id),
|
||||
label);
|
||||
}
|
||||
|
||||
static final class LabelField extends AbstractInputField<Label> {
|
||||
|
||||
LabelField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Label control) {
|
||||
|
||||
super(attribute, orientation, control, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
// Does Nothing, Label has no default value
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.control.getText();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ public class PasswordFieldBuilder implements InputFieldBuilder {
|
|||
final CharSequence pwd = passwordInput.getValue();
|
||||
final CharSequence confirm = confirmInput.getValue();
|
||||
|
||||
if (passwordInputField.initValue != null && passwordInputField.initValue.equals(pwd)) {
|
||||
if (passwordInputField.initValue != null && passwordInputField.initValue.contentEquals(pwd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,75 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
|
||||
public abstract class SelectionFieldBuilder {
|
||||
|
||||
protected List<Tuple<String>> getLocalizedResources(
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
return getLocalizedRes(attribute, viewContext, false);
|
||||
}
|
||||
|
||||
protected List<Tuple<String>> getLocalizedResourcesAsToolTip(
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
return getLocalizedRes(attribute, viewContext, true);
|
||||
}
|
||||
|
||||
private List<Tuple<String>> getLocalizedRes(
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext,
|
||||
final boolean toolTipResources) {
|
||||
|
||||
if (attribute == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final String prefix =
|
||||
(ConfigurationAttribute.hasDependency(
|
||||
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
|
||||
attribute))
|
||||
? ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
|
||||
attribute) + "."
|
||||
: ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".";
|
||||
|
||||
return Arrays.asList(StringUtils.split(
|
||||
attribute.resources,
|
||||
Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(value -> {
|
||||
final String key = prefix + value + ((toolTipResources)
|
||||
? ExamConfigurationService.TOOL_TIP_SUFFIX
|
||||
: "");
|
||||
final String text = viewContext.i18nSupport.getText(key, "");
|
||||
return new Tuple<>(value, (StringUtils.isBlank(text))
|
||||
? (toolTipResources)
|
||||
? text
|
||||
: value
|
||||
: text);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
|
||||
public abstract class SelectionFieldBuilder {
|
||||
|
||||
protected List<Tuple<String>> getLocalizedResources(
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
return getLocalizedRes(attribute, viewContext, false);
|
||||
}
|
||||
|
||||
protected List<Tuple<String>> getLocalizedResourcesAsToolTip(
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
return getLocalizedRes(attribute, viewContext, true);
|
||||
}
|
||||
|
||||
private List<Tuple<String>> getLocalizedRes(
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext,
|
||||
final boolean toolTipResources) {
|
||||
|
||||
if (attribute == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final String prefix =
|
||||
(ConfigurationAttribute.hasDependency(
|
||||
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
|
||||
attribute))
|
||||
? ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
|
||||
attribute) + "."
|
||||
: ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".";
|
||||
|
||||
return Arrays.stream(StringUtils.split(
|
||||
attribute.resources,
|
||||
Constants.LIST_SEPARATOR))
|
||||
.map(value -> {
|
||||
final String key = prefix + value + ((toolTipResources)
|
||||
? ExamConfigurationService.TOOL_TIP_SUFFIX
|
||||
: "");
|
||||
final String text = viewContext.i18nSupport.getText(key, "");
|
||||
return new Tuple<>(value, (StringUtils.isBlank(text))
|
||||
? (toolTipResources)
|
||||
? text
|
||||
: value
|
||||
: text);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,226 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
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.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
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.InputField;
|
||||
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.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class TableFieldBuilder extends AbstractTableFieldBuilder {
|
||||
|
||||
private static final String TOOLTIP_SUFFIX = ".tooltip";
|
||||
private static final String ADD_TOOLTIP_SUFFIX = ".add" + TOOLTIP_SUFFIX;
|
||||
private static final String REMOVE_TOOLTIP_SUFFIX = ".remove" + TOOLTIP_SUFFIX;
|
||||
|
||||
protected TableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
super(restService, widgetFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return AttributeType.TABLE == attribute.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final TableContext tableContext = createTableContext(attribute, viewContext);
|
||||
final Table table = createTable(parent, tableContext);
|
||||
|
||||
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
|
||||
final TableColumn column = this.widgetFactory.tableColumnLocalized(
|
||||
table,
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name),
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name +
|
||||
TOOLTIP_SUFFIX));
|
||||
column.setWidth(100);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
}
|
||||
|
||||
final TableInputField tableField = new TableInputField(
|
||||
tableContext,
|
||||
table);
|
||||
if (!viewContext.readonly) {
|
||||
TableColumn column = new TableColumn(table, SWT.NONE);
|
||||
column.setImage(ImageIcon.ADD_BOX_WHITE.getImage(parent.getDisplay()));
|
||||
column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name +
|
||||
ADD_TOOLTIP_SUFFIX,
|
||||
"Add new")));
|
||||
column.setWidth(20);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
|
||||
column.addListener(SWT.Selection, event -> {
|
||||
tableField.addRow();
|
||||
});
|
||||
|
||||
column = new TableColumn(table, SWT.NONE);
|
||||
column.setImage(ImageIcon.REMOVE_BOX_WHITE.getImage(parent.getDisplay()));
|
||||
column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name +
|
||||
REMOVE_TOOLTIP_SUFFIX,
|
||||
"Remove Selected")));
|
||||
column.setWidth(20);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
|
||||
column.addListener(SWT.Selection, event -> {
|
||||
final int selectionIndex = table.getSelectionIndex();
|
||||
if (selectionIndex >= 0) {
|
||||
tableField.deleteRow(selectionIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setSelectionListener(table, tableField);
|
||||
return tableField;
|
||||
}
|
||||
|
||||
static final class TableInputField extends AbstractTableInputField {
|
||||
|
||||
private final List<Map<Long, TableValue>> values;
|
||||
|
||||
TableInputField(
|
||||
final TableContext tableContext,
|
||||
final Table control) {
|
||||
|
||||
super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
|
||||
this.values = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
void initValue(final List<TableValue> tableValues) {
|
||||
valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
|
||||
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);
|
||||
this.values.remove(selectionIndex);
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values));
|
||||
}
|
||||
|
||||
private void addRow() {
|
||||
final int index = this.values.size();
|
||||
// create new values form default values
|
||||
final Map<Long, TableValue> rowValues = this.tableContext.getRowAttributes()
|
||||
.stream()
|
||||
.map(attr -> new TableValue(attr.id, index, attr.defaultValue))
|
||||
.collect(Collectors.toMap(
|
||||
tv -> tv.attributeId,
|
||||
Function.identity()));
|
||||
|
||||
this.values.add(rowValues);
|
||||
addTableRow(this.values.size() - 1, rowValues);
|
||||
this.control.layout();
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values));
|
||||
}
|
||||
|
||||
protected void addTableRow(final int index, final Map<Long, TableValue> rowValues) {
|
||||
new TableItem(this.control, SWT.NONE);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTableRowValues(final int 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()) {
|
||||
if (rowValues.containsKey(attr.id)) {
|
||||
final TableValue tableValue = rowValues.get(attr.id);
|
||||
setValueToCell(this.tableContext, item, cellIndex, attr, tableValue);
|
||||
}
|
||||
cellIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openForm(final int selectionIndex) {
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
rowValues,
|
||||
selectionIndex);
|
||||
|
||||
new ModalInputDialog<Map<Long, TableValue>>(
|
||||
this.control.getShell(),
|
||||
this.tableContext.getWidgetFactory())
|
||||
.setDialogWidth(600)
|
||||
.setDialogHeight(550)
|
||||
.open(
|
||||
ExamConfigurationService.getTablePopupTitleKey(
|
||||
this.attribute,
|
||||
this.tableContext.getViewContext().i18nSupport),
|
||||
(Consumer<Map<Long, TableValue>>) rowVals -> applyFormValues(
|
||||
this.values,
|
||||
rowVals,
|
||||
selectionIndex),
|
||||
() -> this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values)),
|
||||
builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
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.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
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.InputField;
|
||||
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.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class TableFieldBuilder extends AbstractTableFieldBuilder {
|
||||
|
||||
private static final String TOOLTIP_SUFFIX = ".tooltip";
|
||||
private static final String ADD_TOOLTIP_SUFFIX = ".add" + TOOLTIP_SUFFIX;
|
||||
private static final String REMOVE_TOOLTIP_SUFFIX = ".remove" + TOOLTIP_SUFFIX;
|
||||
|
||||
protected TableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
super(restService, widgetFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return AttributeType.TABLE == attribute.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final TableContext tableContext = createTableContext(attribute, viewContext);
|
||||
final Table table = createTable(parent, tableContext);
|
||||
|
||||
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
|
||||
final TableColumn column = this.widgetFactory.tableColumnLocalized(
|
||||
table,
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name),
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name +
|
||||
TOOLTIP_SUFFIX));
|
||||
column.setWidth(100);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
}
|
||||
|
||||
final TableInputField tableField = new TableInputField(
|
||||
tableContext,
|
||||
table);
|
||||
if (!viewContext.readonly) {
|
||||
TableColumn column = new TableColumn(table, SWT.NONE);
|
||||
column.setImage(ImageIcon.ADD_BOX_WHITE.getImage(parent.getDisplay()));
|
||||
column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name +
|
||||
ADD_TOOLTIP_SUFFIX,
|
||||
"Add new")));
|
||||
column.setWidth(20);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
|
||||
column.addListener(SWT.Selection, event -> tableField.addRow());
|
||||
|
||||
column = new TableColumn(table, SWT.NONE);
|
||||
column.setImage(ImageIcon.REMOVE_BOX_WHITE.getImage(parent.getDisplay()));
|
||||
column.setToolTipText(Utils.formatLineBreaks(viewContext.i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name +
|
||||
REMOVE_TOOLTIP_SUFFIX,
|
||||
"Remove Selected")));
|
||||
column.setWidth(20);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
|
||||
column.addListener(SWT.Selection, event -> {
|
||||
final int selectionIndex = table.getSelectionIndex();
|
||||
if (selectionIndex >= 0) {
|
||||
tableField.deleteRow(selectionIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setSelectionListener(table, tableField);
|
||||
return tableField;
|
||||
}
|
||||
|
||||
static final class TableInputField extends AbstractTableInputField {
|
||||
|
||||
private final List<Map<Long, TableValue>> values;
|
||||
|
||||
TableInputField(
|
||||
final TableContext tableContext,
|
||||
final Table control) {
|
||||
|
||||
super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
|
||||
this.values = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
void initValue(final List<TableValue> tableValues) {
|
||||
valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
|
||||
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);
|
||||
this.values.remove(selectionIndex);
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values));
|
||||
}
|
||||
|
||||
private void addRow() {
|
||||
final int index = this.values.size();
|
||||
// create new values form default values
|
||||
final Map<Long, TableValue> rowValues = this.tableContext.getRowAttributes()
|
||||
.stream()
|
||||
.map(attr -> new TableValue(attr.id, index, attr.defaultValue))
|
||||
.collect(Collectors.toMap(
|
||||
tv -> tv.attributeId,
|
||||
Function.identity()));
|
||||
|
||||
this.values.add(rowValues);
|
||||
addTableRow(this.values.size() - 1, rowValues);
|
||||
this.control.layout();
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values));
|
||||
}
|
||||
|
||||
protected void addTableRow(final int index, final Map<Long, TableValue> rowValues) {
|
||||
new TableItem(this.control, SWT.NONE);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTableRowValues(final int 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()) {
|
||||
if (rowValues.containsKey(attr.id)) {
|
||||
final TableValue tableValue = rowValues.get(attr.id);
|
||||
setValueToCell(this.tableContext, item, cellIndex, attr, tableValue);
|
||||
}
|
||||
cellIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openForm(final int selectionIndex) {
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
rowValues,
|
||||
selectionIndex);
|
||||
|
||||
new ModalInputDialog<Map<Long, TableValue>>(
|
||||
this.control.getShell(),
|
||||
this.tableContext.getWidgetFactory())
|
||||
.setDialogWidth(600)
|
||||
.setDialogHeight(550)
|
||||
.open(
|
||||
ExamConfigurationService.getTablePopupTitleKey(
|
||||
this.attribute,
|
||||
this.tableContext.getViewContext().i18nSupport),
|
||||
(Consumer<Map<Long, TableValue>>) _rowValues -> applyFormValues(
|
||||
this.values,
|
||||
_rowValues,
|
||||
selectionIndex),
|
||||
() -> this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values)),
|
||||
builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,162 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
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.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, TableValue>> {
|
||||
|
||||
private final TableContext tableContext;
|
||||
private final Map<Long, TableValue> rowValues;
|
||||
private final int listIndex;
|
||||
private final String rowGroupId;
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final int listIndex) {
|
||||
|
||||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = listIndex;
|
||||
this.rowGroupId = null;
|
||||
}
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final String rowGroupId) {
|
||||
|
||||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = 0;
|
||||
this.rowGroupId = rowGroupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Map<Long, TableValue>> compose(final Composite parent) {
|
||||
|
||||
final Composite grid = PageService.createManagedVScrolledComposite(
|
||||
parent,
|
||||
scrolledComposite -> {
|
||||
final Composite result = this.tableContext
|
||||
.getWidgetFactory()
|
||||
.formGrid(scrolledComposite, 2);
|
||||
final GridLayout layout = (GridLayout) result.getLayout();
|
||||
layout.verticalSpacing = 0;
|
||||
return result;
|
||||
},
|
||||
false);
|
||||
|
||||
final List<InputField> inputFields = new ArrayList<>();
|
||||
for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes(this.rowGroupId)) {
|
||||
createLabel(grid, attribute);
|
||||
inputFields.add(createInputField(grid, attribute));
|
||||
}
|
||||
|
||||
for (final InputField inputField : inputFields) {
|
||||
final ConfigurationAttribute attribute = inputField.getAttribute();
|
||||
this.tableContext.getValueChangeListener().notifyGUI(
|
||||
this.tableContext.getViewContext(),
|
||||
attribute,
|
||||
new ConfigurationValue(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
attribute.id,
|
||||
this.listIndex,
|
||||
inputField.getValue()));
|
||||
}
|
||||
|
||||
// when the pop-up gets closed we have to remove the input fields from the view context
|
||||
grid.addDisposeListener(event -> {
|
||||
this.tableContext.flushInputFields(this.rowValues.keySet());
|
||||
});
|
||||
|
||||
return () -> inputFields.stream()
|
||||
.map(field -> (field.hasError())
|
||||
? this.rowValues.get(field.getAttribute().id)
|
||||
: new TableValue(
|
||||
field.getAttribute().id,
|
||||
this.listIndex,
|
||||
field.getValue()))
|
||||
.collect(Collectors.toMap(
|
||||
tv -> tv.attributeId,
|
||||
Function.identity()));
|
||||
}
|
||||
|
||||
private InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
if (attribute.type == AttributeType.TABLE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Table type is currently not supported within a table row form view!");
|
||||
}
|
||||
|
||||
final Orientation orientation = this.tableContext
|
||||
.getOrientation(attribute.id);
|
||||
final InputFieldBuilder inputFieldBuilder = this.tableContext
|
||||
.getInputFieldBuilder(attribute, orientation);
|
||||
final InputField inputField = inputFieldBuilder.createInputField(
|
||||
parent,
|
||||
attribute,
|
||||
this.tableContext.getViewContext());
|
||||
|
||||
final TableValue initValue = this.rowValues.get(attribute.id);
|
||||
inputField.initValue((initValue != null) ? initValue.value : null, this.listIndex);
|
||||
// we have to register the input field within the ViewContext to receive error messages
|
||||
this.tableContext.registerInputField(inputField);
|
||||
|
||||
return inputField;
|
||||
}
|
||||
|
||||
private void createLabel(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
final LocTextKey locTextKey = new LocTextKey(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name,
|
||||
attribute.name);
|
||||
final Label label = this.tableContext
|
||||
.getWidgetFactory()
|
||||
.labelLocalized(parent, locTextKey);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
gridData.verticalIndent = 4;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
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.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, TableValue>> {
|
||||
|
||||
private final TableContext tableContext;
|
||||
private final Map<Long, TableValue> rowValues;
|
||||
private final int listIndex;
|
||||
private final String rowGroupId;
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final int listIndex) {
|
||||
|
||||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = listIndex;
|
||||
this.rowGroupId = null;
|
||||
}
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final String rowGroupId) {
|
||||
|
||||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = 0;
|
||||
this.rowGroupId = rowGroupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Map<Long, TableValue>> compose(final Composite parent) {
|
||||
|
||||
final Composite grid = PageService.createManagedVScrolledComposite(
|
||||
parent,
|
||||
scrolledComposite -> {
|
||||
final Composite result = this.tableContext
|
||||
.getWidgetFactory()
|
||||
.formGrid(scrolledComposite, 2);
|
||||
final GridLayout layout = (GridLayout) result.getLayout();
|
||||
layout.verticalSpacing = 0;
|
||||
return result;
|
||||
},
|
||||
false);
|
||||
|
||||
final List<InputField> inputFields = new ArrayList<>();
|
||||
for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes(this.rowGroupId)) {
|
||||
createLabel(grid, attribute);
|
||||
inputFields.add(createInputField(grid, attribute));
|
||||
}
|
||||
|
||||
for (final InputField inputField : inputFields) {
|
||||
final ConfigurationAttribute attribute = inputField.getAttribute();
|
||||
this.tableContext.getValueChangeListener().notifyGUI(
|
||||
this.tableContext.getViewContext(),
|
||||
attribute,
|
||||
new ConfigurationValue(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
attribute.id,
|
||||
this.listIndex,
|
||||
inputField.getValue()));
|
||||
}
|
||||
|
||||
// when the pop-up gets closed we have to remove the input fields from the view context
|
||||
grid.addDisposeListener(event -> this.tableContext.flushInputFields(this.rowValues.keySet()));
|
||||
|
||||
return () -> inputFields.stream()
|
||||
.map(field -> (field.hasError())
|
||||
? this.rowValues.get(field.getAttribute().id)
|
||||
: new TableValue(
|
||||
field.getAttribute().id,
|
||||
this.listIndex,
|
||||
field.getValue()))
|
||||
.collect(Collectors.toMap(
|
||||
tv -> tv.attributeId,
|
||||
Function.identity()));
|
||||
}
|
||||
|
||||
private InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
if (attribute.type == AttributeType.TABLE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Table type is currently not supported within a table row form view!");
|
||||
}
|
||||
|
||||
final Orientation orientation = this.tableContext
|
||||
.getOrientation(attribute.id);
|
||||
final InputFieldBuilder inputFieldBuilder = this.tableContext
|
||||
.getInputFieldBuilder(attribute, orientation);
|
||||
final InputField inputField = inputFieldBuilder.createInputField(
|
||||
parent,
|
||||
attribute,
|
||||
this.tableContext.getViewContext());
|
||||
|
||||
final TableValue initValue = this.rowValues.get(attribute.id);
|
||||
inputField.initValue((initValue != null) ? initValue.value : null, this.listIndex);
|
||||
// we have to register the input field within the ViewContext to receive error messages
|
||||
this.tableContext.registerInputField(inputField);
|
||||
|
||||
return inputField;
|
||||
}
|
||||
|
||||
private void createLabel(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
final LocTextKey locTextKey = new LocTextKey(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.name,
|
||||
attribute.name);
|
||||
final Label label = this.tableContext
|
||||
.getWidgetFactory()
|
||||
.labelLocalized(parent, locTextKey);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
gridData.verticalIndent = 4;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,250 +1,248 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
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.ValueChangeListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
|
||||
public final class ViewContext {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ViewContext.class);
|
||||
|
||||
private final Configuration configuration;
|
||||
private final View view;
|
||||
private final int rows;
|
||||
|
||||
final AttributeMapping attributeMapping;
|
||||
final Map<Long, InputField> inputFieldMapping;
|
||||
final ValueChangeListener valueChangeListener;
|
||||
final I18nSupport i18nSupport;
|
||||
final boolean readonly;
|
||||
|
||||
ViewContext(
|
||||
final Configuration configuration,
|
||||
final View view,
|
||||
final int rows,
|
||||
final AttributeMapping attributeContext,
|
||||
final ValueChangeListener valueChangeListener,
|
||||
final I18nSupport i18nSupport,
|
||||
final boolean readonly) {
|
||||
|
||||
Objects.requireNonNull(configuration);
|
||||
Objects.requireNonNull(view);
|
||||
Objects.requireNonNull(attributeContext);
|
||||
Objects.requireNonNull(valueChangeListener);
|
||||
|
||||
this.configuration = configuration;
|
||||
this.view = view;
|
||||
this.rows = rows;
|
||||
|
||||
this.attributeMapping = attributeContext;
|
||||
this.inputFieldMapping = new HashMap<>();
|
||||
this.valueChangeListener = valueChangeListener;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
public I18nSupport getI18nSupport() {
|
||||
return this.i18nSupport;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.view.id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.view.name;
|
||||
}
|
||||
|
||||
public Long getConfigurationId() {
|
||||
return this.configuration.id;
|
||||
}
|
||||
|
||||
public Long getInstitutionId() {
|
||||
return this.configuration.institutionId;
|
||||
}
|
||||
|
||||
public int getColumns() {
|
||||
return this.view.columns;
|
||||
}
|
||||
|
||||
public int getRows() {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
public Collection<ConfigurationAttribute> getChildAttributes(final Long id) {
|
||||
return this.attributeMapping.childAttributeMapping.get(id);
|
||||
}
|
||||
|
||||
public Collection<ConfigurationAttribute> getAttributes() {
|
||||
return this.attributeMapping.getAttributes();
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttribute(final Long attributeId) {
|
||||
return this.attributeMapping.getAttribute(attributeId);
|
||||
}
|
||||
|
||||
public Long getAttributeIdByName(final String name) {
|
||||
return this.attributeMapping.attributeNameIdMapping.get(name);
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttributeByName(final String name) {
|
||||
final Long attributeId = this.attributeMapping.attributeNameIdMapping.get(name);
|
||||
if (attributeId != null) {
|
||||
return getAttribute(attributeId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<Orientation> getOrientationsOfGroup(final ConfigurationAttribute attribute) {
|
||||
return this.attributeMapping.getOrientationsOfGroup(attribute);
|
||||
}
|
||||
|
||||
public Orientation getOrientation(final Long attributeId) {
|
||||
return this.attributeMapping.getOrientation(attributeId);
|
||||
}
|
||||
|
||||
public ValueChangeListener getValueChangeListener() {
|
||||
return this.valueChangeListener;
|
||||
}
|
||||
|
||||
public void disable(final String attributeName) {
|
||||
disable(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void disable(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.disable(false);
|
||||
}
|
||||
|
||||
public void enable(final String attributeName) {
|
||||
enable(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void enable(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.enable(false);
|
||||
}
|
||||
|
||||
public void disableGroup(final String attributeName) {
|
||||
disableGroup(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void disableGroup(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.disable(true);
|
||||
|
||||
try {
|
||||
this.attributeMapping.attributeGroupMapping
|
||||
.get(inputField.getOrientation().groupId)
|
||||
.stream()
|
||||
.map(ConfigurationAttribute::getId)
|
||||
.map(this.inputFieldMapping::get)
|
||||
.forEach(InputField::setDefaultValue);
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to send attribute value update to server: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void enableGroup(final String attributeName) {
|
||||
enableGroup(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void enableGroup(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.enable(true);
|
||||
}
|
||||
|
||||
public void showError(final Long attributeId, final String errorMessage) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.showError(errorMessage);
|
||||
}
|
||||
|
||||
public void clearError(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.clearError();
|
||||
}
|
||||
|
||||
public void registerInputField(final InputField inputField) {
|
||||
this.inputFieldMapping.put(
|
||||
inputField.getAttribute().id,
|
||||
inputField);
|
||||
}
|
||||
|
||||
void setValuesToInputFields(final Collection<ConfigurationValue> values) {
|
||||
this.inputFieldMapping
|
||||
.values()
|
||||
.stream()
|
||||
.forEach(field -> {
|
||||
final ConfigurationValue initValue = field.initValue(values);
|
||||
if (initValue != null) {
|
||||
this.valueChangeListener.notifyGUI(this, field.getAttribute(), initValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Removes all registered InputFields with the given attribute ids
|
||||
*
|
||||
* @param values Collection of attribute ids */
|
||||
void flushInputFields(final Collection<Long> values) {
|
||||
if (values == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
values.stream()
|
||||
.forEach(attrId -> this.inputFieldMapping.remove(attrId));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
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.ValueChangeListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
|
||||
public final class ViewContext {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ViewContext.class);
|
||||
|
||||
private final Configuration configuration;
|
||||
private final View view;
|
||||
private final int rows;
|
||||
|
||||
final AttributeMapping attributeMapping;
|
||||
final Map<Long, InputField> inputFieldMapping;
|
||||
final ValueChangeListener valueChangeListener;
|
||||
final I18nSupport i18nSupport;
|
||||
final boolean readonly;
|
||||
|
||||
ViewContext(
|
||||
final Configuration configuration,
|
||||
final View view,
|
||||
final int rows,
|
||||
final AttributeMapping attributeContext,
|
||||
final ValueChangeListener valueChangeListener,
|
||||
final I18nSupport i18nSupport,
|
||||
final boolean readonly) {
|
||||
|
||||
Objects.requireNonNull(configuration);
|
||||
Objects.requireNonNull(view);
|
||||
Objects.requireNonNull(attributeContext);
|
||||
Objects.requireNonNull(valueChangeListener);
|
||||
|
||||
this.configuration = configuration;
|
||||
this.view = view;
|
||||
this.rows = rows;
|
||||
|
||||
this.attributeMapping = attributeContext;
|
||||
this.inputFieldMapping = new HashMap<>();
|
||||
this.valueChangeListener = valueChangeListener;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
public I18nSupport getI18nSupport() {
|
||||
return this.i18nSupport;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.view.id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.view.name;
|
||||
}
|
||||
|
||||
public Long getConfigurationId() {
|
||||
return this.configuration.id;
|
||||
}
|
||||
|
||||
public Long getInstitutionId() {
|
||||
return this.configuration.institutionId;
|
||||
}
|
||||
|
||||
public int getColumns() {
|
||||
return this.view.columns;
|
||||
}
|
||||
|
||||
public int getRows() {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
public Collection<ConfigurationAttribute> getChildAttributes(final Long id) {
|
||||
return this.attributeMapping.childAttributeMapping.get(id);
|
||||
}
|
||||
|
||||
public Collection<ConfigurationAttribute> getAttributes() {
|
||||
return this.attributeMapping.getAttributes();
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttribute(final Long attributeId) {
|
||||
return this.attributeMapping.getAttribute(attributeId);
|
||||
}
|
||||
|
||||
public Long getAttributeIdByName(final String name) {
|
||||
return this.attributeMapping.attributeNameIdMapping.get(name);
|
||||
}
|
||||
|
||||
public ConfigurationAttribute getAttributeByName(final String name) {
|
||||
final Long attributeId = this.attributeMapping.attributeNameIdMapping.get(name);
|
||||
if (attributeId != null) {
|
||||
return getAttribute(attributeId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<Orientation> getOrientationsOfGroup(final ConfigurationAttribute attribute) {
|
||||
return this.attributeMapping.getOrientationsOfGroup(attribute);
|
||||
}
|
||||
|
||||
public Orientation getOrientation(final Long attributeId) {
|
||||
return this.attributeMapping.getOrientation(attributeId);
|
||||
}
|
||||
|
||||
public ValueChangeListener getValueChangeListener() {
|
||||
return this.valueChangeListener;
|
||||
}
|
||||
|
||||
public void disable(final String attributeName) {
|
||||
disable(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void disable(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.disable(false);
|
||||
}
|
||||
|
||||
public void enable(final String attributeName) {
|
||||
enable(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void enable(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.enable(false);
|
||||
}
|
||||
|
||||
public void disableGroup(final String attributeName) {
|
||||
disableGroup(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void disableGroup(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.disable(true);
|
||||
|
||||
try {
|
||||
this.attributeMapping.attributeGroupMapping
|
||||
.get(inputField.getOrientation().groupId)
|
||||
.stream()
|
||||
.map(ConfigurationAttribute::getId)
|
||||
.map(this.inputFieldMapping::get)
|
||||
.forEach(InputField::setDefaultValue);
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to send attribute value update to server: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void enableGroup(final String attributeName) {
|
||||
enableGroup(this.getAttributeIdByName(attributeName));
|
||||
}
|
||||
|
||||
public void enableGroup(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.enable(true);
|
||||
}
|
||||
|
||||
public void showError(final Long attributeId, final String errorMessage) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.showError(errorMessage);
|
||||
}
|
||||
|
||||
public void clearError(final Long attributeId) {
|
||||
final InputField inputField = this.inputFieldMapping.get(attributeId);
|
||||
if (inputField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputField.clearError();
|
||||
}
|
||||
|
||||
public void registerInputField(final InputField inputField) {
|
||||
this.inputFieldMapping.put(
|
||||
inputField.getAttribute().id,
|
||||
inputField);
|
||||
}
|
||||
|
||||
void setValuesToInputFields(final Collection<ConfigurationValue> values) {
|
||||
this.inputFieldMapping
|
||||
.values()
|
||||
.forEach(field -> {
|
||||
final ConfigurationValue initValue = field.initValue(values);
|
||||
if (initValue != null) {
|
||||
this.valueChangeListener.notifyGUI(this, field.getAttribute(), initValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Removes all registered InputFields with the given attribute ids
|
||||
*
|
||||
* @param values Collection of attribute ids */
|
||||
void flushInputFields(final Collection<Long> values) {
|
||||
if (values == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
values.forEach(this.inputFieldMapping::remove);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,213 +1,213 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.GroupCellFieldBuilderAdapter;
|
||||
|
||||
public class ViewGridBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ViewGridBuilder.class);
|
||||
|
||||
final ExamConfigurationService examConfigurationService;
|
||||
final Composite parent;
|
||||
final ViewContext viewContext;
|
||||
|
||||
private final CellFieldBuilderAdapter[][] grid;
|
||||
private final GroupCellFieldBuilderAdapter groupBuilderAdapter;
|
||||
private final Set<String> registeredGroups;
|
||||
|
||||
ViewGridBuilder(
|
||||
final Composite parent,
|
||||
final ViewContext viewContext,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
this.parent = parent;
|
||||
this.viewContext = viewContext;
|
||||
this.grid = new CellFieldBuilderAdapter[viewContext.getRows()][viewContext.getColumns()];
|
||||
this.groupBuilderAdapter = null;
|
||||
this.registeredGroups = new HashSet<>();
|
||||
}
|
||||
|
||||
ViewGridBuilder(
|
||||
final Composite parent,
|
||||
final ViewContext viewContext,
|
||||
final GroupCellFieldBuilderAdapter groupBuilderAdapter,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
this.parent = parent;
|
||||
this.viewContext = viewContext;
|
||||
this.groupBuilderAdapter = groupBuilderAdapter;
|
||||
this.grid = new CellFieldBuilderAdapter[groupBuilderAdapter.height - 1][groupBuilderAdapter.width];
|
||||
this.registeredGroups = null;
|
||||
}
|
||||
|
||||
ViewGridBuilder add(final ConfigurationAttribute attribute) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Add SEB Configuration Attribute: " + attribute);
|
||||
}
|
||||
|
||||
// ignore nested attributes here (if not propagated to show up in view)
|
||||
if (attribute.parentId != null &&
|
||||
!BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_SHOW_IN_VIEW,
|
||||
attribute))) {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
final Orientation orientation = this.viewContext
|
||||
.getOrientation(attribute.id);
|
||||
|
||||
// create group if this is not a group builder
|
||||
if (this.groupBuilderAdapter == null && StringUtils.isNotBlank(orientation.groupId)) {
|
||||
if (this.registeredGroups.contains(orientation.groupId)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final GroupCellFieldBuilderAdapter groupBuilder =
|
||||
new GroupCellFieldBuilderAdapter(this.viewContext.getOrientationsOfGroup(attribute));
|
||||
|
||||
fillDummy(groupBuilder.x, groupBuilder.y, groupBuilder.width, groupBuilder.height);
|
||||
this.grid[groupBuilder.y][groupBuilder.x] = groupBuilder;
|
||||
this.registeredGroups.add(orientation.groupId);
|
||||
return this;
|
||||
}
|
||||
|
||||
// create single input field with label
|
||||
final int xpos = orientation.xpos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.x : 0);
|
||||
final int ypos = orientation.ypos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.y : 0);
|
||||
|
||||
if (orientation.width > 1 || orientation.height > 1) {
|
||||
fillDummy(xpos, ypos, orientation.width, orientation.height);
|
||||
}
|
||||
|
||||
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
|
||||
this.grid[ypos][xpos] = CellFieldBuilderAdapter.fieldBuilderAdapter(
|
||||
inputFieldBuilder,
|
||||
attribute);
|
||||
|
||||
try {
|
||||
switch (orientation.title) {
|
||||
case RIGHT:
|
||||
case RIGHT_SPAN: {
|
||||
this.grid[ypos][xpos + 1] = CellFieldBuilderAdapter.labelBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
break;
|
||||
}
|
||||
case LEFT:
|
||||
case LEFT_SPAN: {
|
||||
this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
// special case for password, also add confirm label
|
||||
if (attribute.type == AttributeType.PASSWORD_FIELD) {
|
||||
this.grid[ypos + 1][xpos - 1] = CellFieldBuilderAdapter.passwordConfirmLabel(
|
||||
attribute,
|
||||
orientation);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOP: {
|
||||
fillDummy(xpos, ypos - 1, orientation.width, 1);
|
||||
this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (final ArrayIndexOutOfBoundsException e) {
|
||||
log.error("Failed to set title as configured in: {} for attribute: {}", orientation, attribute, e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void compose() {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Compose grid view: \n" + gridToString());
|
||||
}
|
||||
|
||||
// balance grid (optimize span and grab empty spaces for labels where applicable)
|
||||
for (int y = 0; y < this.grid.length; y++) {
|
||||
for (int x = 0; x < this.grid[y].length; x++) {
|
||||
if (this.grid[y][x] != null) {
|
||||
this.grid[y][x].balanceGrid(this.grid, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < this.grid.length; y++) {
|
||||
for (int x = 0; x < this.grid[y].length; x++) {
|
||||
if (this.grid[y][x] == null) {
|
||||
final Label empty = new Label(this.parent, SWT.LEFT);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
gridData.verticalIndent = 8;
|
||||
empty.setLayoutData(gridData);
|
||||
empty.setText(StringUtils.EMPTY /* "empty " + x + " " + y */);
|
||||
} else {
|
||||
this.grid[y][x].createCell(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillDummy(final int x, final int y, final int width, final int height) {
|
||||
final int upperBoundX = x + width;
|
||||
final int upperBoundY = y + height;
|
||||
for (int _y = y; _y < upperBoundY; _y++) {
|
||||
for (int _x = x; _x < upperBoundX; _x++) {
|
||||
if (_y < 0 || _x < 0 || _y >= this.grid.length || _x >= this.grid[_y].length) {
|
||||
log.warn("Out of bounds: {} {}", _x, _y);
|
||||
continue;
|
||||
}
|
||||
this.grid[_y][_x] = CellFieldBuilderAdapter.DUMMY_BUILDER_ADAPTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String gridToString() {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < this.grid.length; i++) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(",\n");
|
||||
}
|
||||
sb.append(Arrays.toString(this.grid[i]));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.GroupCellFieldBuilderAdapter;
|
||||
|
||||
public class ViewGridBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ViewGridBuilder.class);
|
||||
|
||||
final ExamConfigurationService examConfigurationService;
|
||||
final Composite parent;
|
||||
final ViewContext viewContext;
|
||||
|
||||
private final CellFieldBuilderAdapter[][] grid;
|
||||
private final GroupCellFieldBuilderAdapter groupBuilderAdapter;
|
||||
private final Set<String> registeredGroups;
|
||||
|
||||
ViewGridBuilder(
|
||||
final Composite parent,
|
||||
final ViewContext viewContext,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
this.parent = parent;
|
||||
this.viewContext = viewContext;
|
||||
this.grid = new CellFieldBuilderAdapter[viewContext.getRows()][viewContext.getColumns()];
|
||||
this.groupBuilderAdapter = null;
|
||||
this.registeredGroups = new HashSet<>();
|
||||
}
|
||||
|
||||
ViewGridBuilder(
|
||||
final Composite parent,
|
||||
final ViewContext viewContext,
|
||||
final GroupCellFieldBuilderAdapter groupBuilderAdapter,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
this.parent = parent;
|
||||
this.viewContext = viewContext;
|
||||
this.groupBuilderAdapter = groupBuilderAdapter;
|
||||
this.grid = new CellFieldBuilderAdapter[groupBuilderAdapter.height - 1][groupBuilderAdapter.width];
|
||||
this.registeredGroups = null;
|
||||
}
|
||||
|
||||
ViewGridBuilder add(final ConfigurationAttribute attribute) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Add SEB Configuration Attribute: " + attribute);
|
||||
}
|
||||
|
||||
// ignore nested attributes here (if not propagated to show up in view)
|
||||
if (attribute.parentId != null &&
|
||||
!BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_SHOW_IN_VIEW,
|
||||
attribute))) {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
final Orientation orientation = this.viewContext
|
||||
.getOrientation(attribute.id);
|
||||
|
||||
// create group if this is not a group builder
|
||||
if (this.groupBuilderAdapter == null && StringUtils.isNotBlank(orientation.groupId)) {
|
||||
if (this.registeredGroups.contains(orientation.groupId)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final GroupCellFieldBuilderAdapter groupBuilder =
|
||||
new GroupCellFieldBuilderAdapter(this.viewContext.getOrientationsOfGroup(attribute));
|
||||
|
||||
fillDummy(groupBuilder.x, groupBuilder.y, groupBuilder.width, groupBuilder.height);
|
||||
this.grid[groupBuilder.y][groupBuilder.x] = groupBuilder;
|
||||
this.registeredGroups.add(orientation.groupId);
|
||||
return this;
|
||||
}
|
||||
|
||||
// create single input field with label
|
||||
final int xpos = orientation.xpos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.x : 0);
|
||||
final int ypos = orientation.ypos() + ((this.groupBuilderAdapter != null) ? -this.groupBuilderAdapter.y : 0);
|
||||
|
||||
if (orientation.width > 1 || orientation.height > 1) {
|
||||
fillDummy(xpos, ypos, orientation.width, orientation.height);
|
||||
}
|
||||
|
||||
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
|
||||
this.grid[ypos][xpos] = CellFieldBuilderAdapter.fieldBuilderAdapter(
|
||||
inputFieldBuilder,
|
||||
attribute);
|
||||
|
||||
try {
|
||||
switch (orientation.title) {
|
||||
case RIGHT:
|
||||
case RIGHT_SPAN: {
|
||||
this.grid[ypos][xpos + 1] = CellFieldBuilderAdapter.labelBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
break;
|
||||
}
|
||||
case LEFT:
|
||||
case LEFT_SPAN: {
|
||||
this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
// special case for password, also add confirm label
|
||||
if (attribute.type == AttributeType.PASSWORD_FIELD) {
|
||||
this.grid[ypos + 1][xpos - 1] = CellFieldBuilderAdapter.passwordConfirmLabel(
|
||||
attribute,
|
||||
orientation);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOP: {
|
||||
fillDummy(xpos, ypos - 1, orientation.width, 1);
|
||||
this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder(
|
||||
attribute,
|
||||
orientation);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (final ArrayIndexOutOfBoundsException e) {
|
||||
log.error("Failed to set title as configured in: {} for attribute: {}", orientation, attribute, e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void compose() {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Compose grid view: \n" + gridToString());
|
||||
}
|
||||
|
||||
// balance grid (optimize span and grab empty spaces for labels where applicable)
|
||||
for (int y = 0; y < this.grid.length; y++) {
|
||||
for (int x = 0; x < this.grid[y].length; x++) {
|
||||
if (this.grid[y][x] != null) {
|
||||
this.grid[y][x].balanceGrid(this.grid, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < this.grid.length; y++) {
|
||||
for (int x = 0; x < this.grid[y].length; x++) {
|
||||
if (this.grid[y][x] == null) {
|
||||
final Label empty = new Label(this.parent, SWT.LEFT);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
gridData.verticalIndent = 8;
|
||||
empty.setLayoutData(gridData);
|
||||
empty.setText(StringUtils.EMPTY /* "empty " + x + " " + y */);
|
||||
} else {
|
||||
this.grid[y][x].createCell(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillDummy(final int x, final int y, final int width, final int height) {
|
||||
final int upperBoundX = x + width;
|
||||
final int upperBoundY = y + height;
|
||||
for (int _y = y; _y < upperBoundY; _y++) {
|
||||
for (int _x = x; _x < upperBoundX; _x++) {
|
||||
if (_y < 0 || _x < 0 || _y >= this.grid.length || _x >= this.grid[_y].length) {
|
||||
log.warn("Out of bounds: {} {}", _x, _y);
|
||||
continue;
|
||||
}
|
||||
this.grid[_y][_x] = CellFieldBuilderAdapter.DUMMY_BUILDER_ADAPTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String gridToString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < this.grid.length; i++) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(",\n");
|
||||
}
|
||||
sb.append(Arrays.toString(this.grid[i]));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,78 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl.rules;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
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.impl.ViewContext;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class BrowserViewModeRule implements ValueChangeRule {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BrowserViewModeRule.class);
|
||||
|
||||
public static final String KEY_BROWSER_VIEW_MODE = "browserViewMode";
|
||||
public static final String KEY_TOUCH_EXIT = "enableTouchExit";
|
||||
public static final String KEY_MAIN_WINDOW_GROUP = "mainBrowserWindowWidth";
|
||||
|
||||
@Override
|
||||
public boolean observesAttribute(final ConfigurationAttribute attribute) {
|
||||
return KEY_BROWSER_VIEW_MODE.equals(attribute.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (StringUtils.isBlank(value.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
context.enable(KEY_TOUCH_EXIT);
|
||||
context.enableGroup(KEY_MAIN_WINDOW_GROUP);
|
||||
|
||||
switch (Integer.parseInt(value.value)) {
|
||||
case 0: {
|
||||
context.disable(KEY_TOUCH_EXIT);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
context.disable(KEY_TOUCH_EXIT);
|
||||
context.disableGroup(KEY_MAIN_WINDOW_GROUP);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
context.disableGroup(KEY_MAIN_WINDOW_GROUP);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
context.disable(KEY_TOUCH_EXIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to apply rule: ", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl.rules;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
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.impl.ViewContext;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class BrowserViewModeRule implements ValueChangeRule {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BrowserViewModeRule.class);
|
||||
|
||||
public static final String KEY_BROWSER_VIEW_MODE = "browserViewMode";
|
||||
public static final String KEY_TOUCH_EXIT = "enableTouchExit";
|
||||
public static final String KEY_MAIN_WINDOW_GROUP = "mainBrowserWindowWidth";
|
||||
|
||||
@Override
|
||||
public boolean observesAttribute(final ConfigurationAttribute attribute) {
|
||||
return KEY_BROWSER_VIEW_MODE.equals(attribute.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (StringUtils.isBlank(value.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
context.enable(KEY_TOUCH_EXIT);
|
||||
context.enableGroup(KEY_MAIN_WINDOW_GROUP);
|
||||
|
||||
switch (Integer.parseInt(value.value)) {
|
||||
case 1: {
|
||||
context.disable(KEY_TOUCH_EXIT);
|
||||
context.disableGroup(KEY_MAIN_WINDOW_GROUP);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
context.disableGroup(KEY_MAIN_WINDOW_GROUP);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
context.disable(KEY_TOUCH_EXIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to apply rule: ", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
|
|||
|
||||
public interface I18nSupport {
|
||||
|
||||
public static final String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages";
|
||||
public static final String MULTILINGUAL_KEY = "sebserver.gui.multilingual";
|
||||
public static final String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat";
|
||||
public static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE";
|
||||
String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages";
|
||||
String MULTILINGUAL_KEY = "sebserver.gui.multilingual";
|
||||
String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat";
|
||||
String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE";
|
||||
|
||||
/** Get all supported languages as a collection of Locale
|
||||
*
|
||||
|
@ -40,7 +40,7 @@ public interface I18nSupport {
|
|||
Locale getUsersFormatLocale();
|
||||
|
||||
/** 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
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** 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
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
*
|
||||
* 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 */
|
||||
default String formatDisplayDate(final Long timestamp) {
|
||||
return formatDisplayDate(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** 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
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** 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
|
||||
*
|
||||
* 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 */
|
||||
default String formatDisplayDateTime(final Long timestamp) {
|
||||
return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** 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
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** 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
|
||||
*
|
||||
* 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 */
|
||||
default String formatDisplayTime(final Long timestamp) {
|
||||
return formatDisplayTime(Utils.toDateTimeUTC(timestamp));
|
||||
|
|
|
@ -39,34 +39,116 @@ public interface PolyglotPageService {
|
|||
* @param locale the Locale to set */
|
||||
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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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(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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Used to create the page language selector if needed
|
||||
*
|
||||
* @param composerCtx the PageContext
|
||||
*/
|
||||
void createLanguageSelector(PageContext composerCtx);
|
||||
|
||||
}
|
|
@ -1,186 +1,185 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
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.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class I18nSupportImpl implements I18nSupport {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(I18nSupportImpl.class);
|
||||
|
||||
private final Locale defaultFormatLocale;
|
||||
private final CurrentUser currentUser;
|
||||
private final MessageSource messageSource;
|
||||
private final Locale defaultLocale = Locale.ENGLISH;
|
||||
private final Collection<Locale> supportedLanguages;
|
||||
|
||||
public I18nSupportImpl(
|
||||
final CurrentUser currentUser,
|
||||
final MessageSource messageSource,
|
||||
final Environment environment) {
|
||||
|
||||
this.currentUser = currentUser;
|
||||
this.messageSource = messageSource;
|
||||
|
||||
final String defaultForamtLocaleString = environment.getProperty(
|
||||
FORMAL_LOCALE_KEY,
|
||||
Constants.DEFAULT_LANG_CODE);
|
||||
|
||||
this.defaultFormatLocale = Locale.forLanguageTag(defaultForamtLocaleString);
|
||||
|
||||
final boolean multilingual = BooleanUtils.toBoolean(environment.getProperty(
|
||||
MULTILINGUAL_KEY,
|
||||
Constants.FALSE_STRING));
|
||||
if (multilingual) {
|
||||
final String languagesString = environment.getProperty(
|
||||
SUPPORTED_LANGUAGES_KEY,
|
||||
Locale.ENGLISH.getLanguage());
|
||||
|
||||
this.supportedLanguages = Utils.immutableCollectionOf(
|
||||
Arrays.asList(StringUtils.split(languagesString, Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(s -> Locale.forLanguageTag(s))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
} else {
|
||||
this.supportedLanguages = Utils.immutableCollectionOf(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Locale> supportedLanguages() {
|
||||
return this.supportedLanguages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getUsersFormatLocale() {
|
||||
// TODO here also a user based format locale can be verified on the future
|
||||
return this.defaultFormatLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getUsersLanguageLocale() {
|
||||
// first session-locale if available
|
||||
try {
|
||||
final Locale sessionLocale = (Locale) RWT.getUISession()
|
||||
.getHttpSession()
|
||||
.getAttribute(ATTR_CURRENT_SESSION_LOCALE);
|
||||
if (sessionLocale != null) {
|
||||
return sessionLocale;
|
||||
}
|
||||
} catch (final IllegalStateException e) {
|
||||
log.warn("Get current locale for session failed: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// second user-locale if available
|
||||
if (this.currentUser.isAvailable()) {
|
||||
return this.currentUser.get().language;
|
||||
}
|
||||
|
||||
// last the default locale
|
||||
return this.defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDisplayDate(final DateTime date) {
|
||||
final String pattern = DateTimeFormat.patternForStyle("M-", getUsersFormatLocale());
|
||||
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDisplayDateTime(final DateTime date) {
|
||||
final String pattern = DateTimeFormat.patternForStyle("MS", getUsersFormatLocale());
|
||||
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDisplayTime(final DateTime date) {
|
||||
final String pattern = DateTimeFormat.patternForStyle("-S", getUsersFormatLocale());
|
||||
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsersTimeZoneTitleSuffix() {
|
||||
final UserInfo userInfo = this.currentUser.get();
|
||||
if (userInfo.timeZone == null || userInfo.timeZone.equals(DateTimeZone.UTC)) {
|
||||
return "";
|
||||
} else {
|
||||
return "(" + this.currentUser.get().timeZone.getID() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(final String key, final String def, final Object... args) {
|
||||
return this.messageSource.getMessage(key, args, def, this.getUsersLanguageLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(final String key, final Locale locale, final String def, final Object... args) {
|
||||
return this.messageSource.getMessage(key, args, def, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasText(final LocTextKey key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return StringUtils.isNotBlank(getText(key.name, (String) null));
|
||||
}
|
||||
|
||||
private String formatDisplayDate(final DateTime date, final DateTimeFormatter formatter) {
|
||||
if (date == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
DateTime dateUTC = date;
|
||||
if (date.getZone() != DateTimeZone.UTC) {
|
||||
log.warn("Date that has not UTC timezone used. "
|
||||
+ "Reset to UTC timezone with any change on time instance for further processing");
|
||||
dateUTC = date.withZone(DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
final UserInfo userInfo = this.currentUser.get();
|
||||
if (userInfo != null && userInfo.timeZone != null && !userInfo.timeZone.equals(DateTimeZone.UTC)) {
|
||||
return dateUTC.toString(formatter.withZone(userInfo.timeZone));
|
||||
} else {
|
||||
return dateUTC.toString(formatter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
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.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class I18nSupportImpl implements I18nSupport {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(I18nSupportImpl.class);
|
||||
|
||||
private final Locale defaultFormatLocale;
|
||||
private final CurrentUser currentUser;
|
||||
private final MessageSource messageSource;
|
||||
private final Locale defaultLocale = Locale.ENGLISH;
|
||||
private final Collection<Locale> supportedLanguages;
|
||||
|
||||
public I18nSupportImpl(
|
||||
final CurrentUser currentUser,
|
||||
final MessageSource messageSource,
|
||||
final Environment environment) {
|
||||
|
||||
this.currentUser = currentUser;
|
||||
this.messageSource = messageSource;
|
||||
|
||||
final String defaultFormatLocaleString = environment.getProperty(
|
||||
FORMAL_LOCALE_KEY,
|
||||
Constants.DEFAULT_LANG_CODE);
|
||||
|
||||
this.defaultFormatLocale = Locale.forLanguageTag(defaultFormatLocaleString);
|
||||
|
||||
final boolean multilingual = BooleanUtils.toBoolean(environment.getProperty(
|
||||
MULTILINGUAL_KEY,
|
||||
Constants.FALSE_STRING));
|
||||
if (multilingual) {
|
||||
final String languagesString = environment.getProperty(
|
||||
SUPPORTED_LANGUAGES_KEY,
|
||||
Locale.ENGLISH.getLanguage());
|
||||
|
||||
this.supportedLanguages = Utils.immutableCollectionOf(
|
||||
Arrays.stream(StringUtils.split(languagesString, Constants.LIST_SEPARATOR))
|
||||
.map(Locale::forLanguageTag)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
} else {
|
||||
this.supportedLanguages = Utils.immutableCollectionOf(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Locale> supportedLanguages() {
|
||||
return this.supportedLanguages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getUsersFormatLocale() {
|
||||
// TODO here also a user based format locale can be verified on the future
|
||||
return this.defaultFormatLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getUsersLanguageLocale() {
|
||||
// first session-locale if available
|
||||
try {
|
||||
final Locale sessionLocale = (Locale) RWT.getUISession()
|
||||
.getHttpSession()
|
||||
.getAttribute(ATTR_CURRENT_SESSION_LOCALE);
|
||||
if (sessionLocale != null) {
|
||||
return sessionLocale;
|
||||
}
|
||||
} catch (final IllegalStateException e) {
|
||||
log.warn("Get current locale for session failed: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// second user-locale if available
|
||||
if (this.currentUser.isAvailable()) {
|
||||
return this.currentUser.get().language;
|
||||
}
|
||||
|
||||
// last the default locale
|
||||
return this.defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDisplayDate(final DateTime date) {
|
||||
final String pattern = DateTimeFormat.patternForStyle("M-", getUsersFormatLocale());
|
||||
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDisplayDateTime(final DateTime date) {
|
||||
final String pattern = DateTimeFormat.patternForStyle("MS", getUsersFormatLocale());
|
||||
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDisplayTime(final DateTime date) {
|
||||
final String pattern = DateTimeFormat.patternForStyle("-S", getUsersFormatLocale());
|
||||
return formatDisplayDate(date, DateTimeFormat.forPattern(pattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsersTimeZoneTitleSuffix() {
|
||||
final UserInfo userInfo = this.currentUser.get();
|
||||
if (userInfo.timeZone == null || userInfo.timeZone.equals(DateTimeZone.UTC)) {
|
||||
return "";
|
||||
} else {
|
||||
return "(" + this.currentUser.get().timeZone.getID() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(final String key, final String def, final Object... args) {
|
||||
return this.messageSource.getMessage(key, args, def, this.getUsersLanguageLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(final String key, final Locale locale, final String def, final Object... args) {
|
||||
return this.messageSource.getMessage(key, args, def, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasText(final LocTextKey key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return StringUtils.isNotBlank(getText(key.name, (String) null));
|
||||
}
|
||||
|
||||
private String formatDisplayDate(final DateTime date, final DateTimeFormatter formatter) {
|
||||
if (date == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
DateTime dateUTC = date;
|
||||
if (date.getZone() != DateTimeZone.UTC) {
|
||||
log.warn("Date that has not UTC timezone used. "
|
||||
+ "Reset to UTC timezone with any change on time instance for further processing");
|
||||
dateUTC = date.withZone(DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
final UserInfo userInfo = this.currentUser.get();
|
||||
if (userInfo != null && userInfo.timeZone != null && !userInfo.timeZone.equals(DateTimeZone.UTC)) {
|
||||
return dateUTC.toString(formatter.withZone(userInfo.timeZone));
|
||||
} else {
|
||||
return dateUTC.toString(formatter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
|
|
|
@ -1,202 +1,202 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
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.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
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.IllegalUserSessionStateException;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class ComposerServiceImpl implements ComposerService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ComposerServiceImpl.class);
|
||||
|
||||
private final Class<? extends PageDefinition> loginPageType = DefaultLoginPage.class;
|
||||
private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class;
|
||||
|
||||
final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final Map<String, TemplateComposer> composer;
|
||||
private final Map<String, PageDefinition> pages;
|
||||
|
||||
public ComposerServiceImpl(
|
||||
final AuthorizationContextHolder authorizationContextHolder,
|
||||
final I18nSupport i18nSupport,
|
||||
final Collection<TemplateComposer> composer,
|
||||
final Collection<PageDefinition> pageDefinitions) {
|
||||
|
||||
this.authorizationContextHolder = authorizationContextHolder;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.composer = composer
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
comp -> comp.getClass().getName(),
|
||||
Function.identity()));
|
||||
|
||||
this.pages = pageDefinitions
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
page -> page.getClass().getName(),
|
||||
Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageDefinition mainPage() {
|
||||
return this.pages.get(this.mainPageType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageDefinition loginPage() {
|
||||
return this.pages.get(this.loginPageType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(final String composerName, final PageContext pageContext) {
|
||||
if (!this.composer.containsKey(composerName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.composer
|
||||
.get(composerName)
|
||||
.validate(pageContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(
|
||||
final Class<? extends TemplateComposer> composerType,
|
||||
final PageContext pageContext) {
|
||||
|
||||
if (composerType != null && pageContext != null) {
|
||||
compose(composerType.getName(), pageContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(
|
||||
final String name,
|
||||
final PageContext pageContext) {
|
||||
|
||||
// Check first if there is still a valid authorization context
|
||||
if (!this.authorizationContextHolder.getAuthorizationContext().isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.composer.containsKey(name)) {
|
||||
log.error("No TemplateComposer with name: " + name + " found. Check Spring confiuration and beans");
|
||||
return;
|
||||
}
|
||||
|
||||
final TemplateComposer composer = this.composer.get(name);
|
||||
|
||||
if (composer.validate(pageContext)) {
|
||||
|
||||
PageService.clearComposite(pageContext.getParent());
|
||||
|
||||
try {
|
||||
composer.compose(pageContext);
|
||||
PageService.updateScrolledComposite(pageContext.getParent());
|
||||
|
||||
} catch (final IllegalUserSessionStateException e) {
|
||||
log.warn("Illegal user session state detected... ceanup user session and forward to login page.");
|
||||
pageContext.forwardToLoginPage();
|
||||
final MessageBox logoutSuccess = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("sebserver.logout"),
|
||||
this.i18nSupport.getText("sebserver.logout.invalid-session.message"),
|
||||
SWT.ICON_INFORMATION,
|
||||
this.i18nSupport);
|
||||
logoutSuccess.open(null);
|
||||
return;
|
||||
} catch (final RuntimeException e) {
|
||||
log.warn("Failed to compose: {}, pageContext: {}", name, pageContext, e);
|
||||
pageContext.notifyError(new LocTextKey("sebserver.error.unexpected"), e);
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to compose: {}, pageContext: {}", name, pageContext, e);
|
||||
}
|
||||
|
||||
try {
|
||||
pageContext.getParent().layout();
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to layout new composition: {}, pageContext: {}", name, pageContext, e);
|
||||
}
|
||||
|
||||
} else {
|
||||
log.error(
|
||||
"Invalid or missing mandatory attributes to handle compose request of ViewComposer: {} pageContext: {}",
|
||||
name,
|
||||
pageContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void composePage(
|
||||
final PageDefinition pageDefinition,
|
||||
final Composite root) {
|
||||
|
||||
compose(
|
||||
pageDefinition.composer(),
|
||||
pageDefinition.applyPageContext(createPageContext(root)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void composePage(
|
||||
final Class<? extends PageDefinition> pageType,
|
||||
final Composite root) {
|
||||
|
||||
final String pageName = pageType.getName();
|
||||
if (!this.pages.containsKey(pageName)) {
|
||||
log.error("Unknown page with name: {}", pageName);
|
||||
return;
|
||||
}
|
||||
|
||||
final PageDefinition pageDefinition = this.pages.get(pageName);
|
||||
compose(
|
||||
pageDefinition.composer(),
|
||||
pageDefinition.applyPageContext(createPageContext(root)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadLoginPage(final Composite parent) {
|
||||
composePage(this.loginPageType, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMainPage(final Composite parent) {
|
||||
composePage(this.mainPageType, parent);
|
||||
}
|
||||
|
||||
private PageContext createPageContext(final Composite root) {
|
||||
return new PageContextImpl(this.i18nSupport, this, root, root, null);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
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.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
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.IllegalUserSessionStateException;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class ComposerServiceImpl implements ComposerService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ComposerServiceImpl.class);
|
||||
|
||||
private final Class<? extends PageDefinition> loginPageType = DefaultLoginPage.class;
|
||||
private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class;
|
||||
|
||||
final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final Map<String, TemplateComposer> composer;
|
||||
private final Map<String, PageDefinition> pages;
|
||||
|
||||
public ComposerServiceImpl(
|
||||
final AuthorizationContextHolder authorizationContextHolder,
|
||||
final I18nSupport i18nSupport,
|
||||
final Collection<TemplateComposer> composer,
|
||||
final Collection<PageDefinition> pageDefinitions) {
|
||||
|
||||
this.authorizationContextHolder = authorizationContextHolder;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.composer = composer
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
comp -> comp.getClass().getName(),
|
||||
Function.identity()));
|
||||
|
||||
this.pages = pageDefinitions
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
page -> page.getClass().getName(),
|
||||
Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageDefinition mainPage() {
|
||||
return this.pages.get(this.mainPageType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageDefinition loginPage() {
|
||||
return this.pages.get(this.loginPageType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(final String composerName, final PageContext pageContext) {
|
||||
if (!this.composer.containsKey(composerName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.composer
|
||||
.get(composerName)
|
||||
.validate(pageContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(
|
||||
final Class<? extends TemplateComposer> composerType,
|
||||
final PageContext pageContext) {
|
||||
|
||||
if (composerType != null && pageContext != null) {
|
||||
compose(composerType.getName(), pageContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(
|
||||
final String name,
|
||||
final PageContext pageContext) {
|
||||
|
||||
// Check first if there is still a valid authorization context
|
||||
if (!this.authorizationContextHolder.getAuthorizationContext().isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.composer.containsKey(name)) {
|
||||
log.error("No TemplateComposer with name: " + name + " found. Check Spring configuration and beans");
|
||||
return;
|
||||
}
|
||||
|
||||
final TemplateComposer composer = this.composer.get(name);
|
||||
|
||||
if (composer.validate(pageContext)) {
|
||||
|
||||
PageService.clearComposite(pageContext.getParent());
|
||||
|
||||
try {
|
||||
composer.compose(pageContext);
|
||||
PageService.updateScrolledComposite(pageContext.getParent());
|
||||
|
||||
} catch (final IllegalUserSessionStateException e) {
|
||||
log.warn("Illegal user session state detected... cleanup user session and forward to login page.");
|
||||
pageContext.forwardToLoginPage();
|
||||
final MessageBox logoutSuccess = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("sebserver.logout"),
|
||||
this.i18nSupport.getText("sebserver.logout.invalid-session.message"),
|
||||
SWT.ICON_INFORMATION,
|
||||
this.i18nSupport);
|
||||
logoutSuccess.open(null);
|
||||
return;
|
||||
} catch (final RuntimeException e) {
|
||||
log.warn("Failed to compose: {}, pageContext: {}", name, pageContext, e);
|
||||
pageContext.notifyError(new LocTextKey("sebserver.error.unexpected"), e);
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to compose: {}, pageContext: {}", name, pageContext, e);
|
||||
}
|
||||
|
||||
try {
|
||||
pageContext.getParent().layout();
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to layout new composition: {}, pageContext: {}", name, pageContext, e);
|
||||
}
|
||||
|
||||
} else {
|
||||
log.error(
|
||||
"Invalid or missing mandatory attributes to handle compose request of ViewComposer: {} pageContext: {}",
|
||||
name,
|
||||
pageContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void composePage(
|
||||
final PageDefinition pageDefinition,
|
||||
final Composite root) {
|
||||
|
||||
compose(
|
||||
pageDefinition.composer(),
|
||||
pageDefinition.applyPageContext(createPageContext(root)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void composePage(
|
||||
final Class<? extends PageDefinition> pageType,
|
||||
final Composite root) {
|
||||
|
||||
final String pageName = pageType.getName();
|
||||
if (!this.pages.containsKey(pageName)) {
|
||||
log.error("Unknown page with name: {}", pageName);
|
||||
return;
|
||||
}
|
||||
|
||||
final PageDefinition pageDefinition = this.pages.get(pageName);
|
||||
compose(
|
||||
pageDefinition.composer(),
|
||||
pageDefinition.applyPageContext(createPageContext(root)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadLoginPage(final Composite parent) {
|
||||
composePage(this.loginPageType, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMainPage(final Composite parent) {
|
||||
composePage(this.mainPageType, parent);
|
||||
}
|
||||
|
||||
private PageContext createPageContext(final Composite root) {
|
||||
return new PageContextImpl(this.i18nSupport, this, root, root, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue