SEBSERV-45 added applications view

This commit is contained in:
anhefti 2019-05-20 15:30:14 +02:00
parent 3654366dc8
commit 3a2a7847ee
32 changed files with 619 additions and 369 deletions

View file

@ -46,7 +46,9 @@ public enum AttributeType {
/** Table type is a list of a composite of single types */
TABLE(COMPOSITE_LIST),
STATIC_TABLE(COMPOSITE_LIST);
INLINE_TABLE(COMPOSITE_LIST),
;
public final AttributeValueType attributeValueType;

View file

@ -8,33 +8,38 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain;
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.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.ResourceService;
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.impl.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
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.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@ -44,127 +49,92 @@ public class SebExamConfigForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigForm.class);
private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.examconfig.form.title.new");
private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.examconfig.form.title");
private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.name");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.description");
private static final LocTextKey FORM_STATUS_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.status");
private static final String VIEW_TEXT_KEY_PREFIX = "sebserver.examconfig.props.form.views.";
private static final String VIEW_TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip";
private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.props.from.title");
private final PageService pageService;
private final RestService restService;
private final CurrentUser currentUser;
private final ExamConfigurationService examConfigurationService;
protected SebExamConfigForm(
final PageService pageService,
final RestService restService,
final CurrentUser currentUser) {
final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) {
this.pageService = pageService;
this.restService = restService;
this.currentUser = currentUser;
this.examConfigurationService = examConfigurationService;
}
@Override
public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final ResourceService resourceService = this.pageService.getResourceService();
final UserInfo user = this.currentUser.get();
final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean isNew = entityKey == null;
// get data or create new. Handle error if happen
final ConfigurationNode examConfig = (isNew)
? ConfigurationNode.createNewExamConfig((parentEntityKey != null)
? Long.valueOf(parentEntityKey.modelId)
: user.institutionId)
: this.restService
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (examConfig == null) {
log.error("Failed to get ConfigurationNode. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean writeGrant = entityGrant.w();
final boolean modifyGrant = entityGrant.m();
final boolean isReadonly = pageContext.isReadonly();
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
// the default page layout with interactive title
final LocTextKey titleKey = (isNew)
? FORM_TITLE_NEW
: FORM_TITLE;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);
pageContext.getParent(),
TITLE_TEXT_KEY);
// The SebClientConfig form
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.CONFIGURATION_NODE.ATTR_ID,
examConfig.getModelId())
.putStaticValue(
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
String.valueOf(examConfig.getInstitutionId()))
.putStaticValue(
Domain.CONFIGURATION_NODE.ATTR_TYPE,
ConfigurationType.EXAM_CONFIG.name())
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_NAME,
FORM_NAME_TEXT_KEY,
examConfig.name))
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
examConfig.description).asArea())
.addField(FormBuilder.singleSelection(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
FORM_STATUS_TEXT_KEY,
examConfig.status.name(),
resourceService::examConfigStatusResources))
.buildFor((isNew)
? this.restService.getRestCall(NewExamConfig.class)
: this.restService.getRestCall(SaveExamConfig.class));
try {
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.onError(pageContext::notifyError)
.getOrThrow();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(() -> writeGrant && isReadonly)
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configNode.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call()
.map(Utils::toSingleton)
.onError(pageContext::notifyError)
.getOrThrow();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
final AttributeMapping attributes = this.examConfigurationService
.getAttributes(configNode.templateId)
.onError(pageContext::notifyError)
.getOrThrow();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE)
.withEntityKey(entityKey)
.withExec(formHandle::processFormSave)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
final List<View> views = this.examConfigurationService.getViews(attributes);
.newAction(ActionDefinition.SEB_EXAM_CONFIG_CANCEL_MODIFY)
.withEntityKey(entityKey)
.withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
action,
ActionDefinition.SEB_EXAM_CONFIG_LIST))
.publishIf(() -> !isReadonly);
final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content);
tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final List<ViewContext> viewContexts = new ArrayList<>();
for (final View view : views) {
final ViewContext viewContext = this.examConfigurationService.createViewContext(
pageContext,
configuration,
view,
attributes,
20);
viewContexts.add(viewContext);
final Composite viewGrid = this.examConfigurationService.createViewGrid(
tabFolder,
viewContext);
final TabItem tabItem = widgetFactory.tabItemLocalized(
tabFolder,
new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name));
tabItem.setControl(viewGrid);
}
this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts);
} catch (final Exception e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
pageContext.notifyError(e);
}
}

View file

@ -136,7 +136,7 @@ public class SebExamConfigList implements TemplateComposer {
this.statusFilter,
true))
.withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_FROM_LIST)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.create())
.compose(content);
@ -147,15 +147,15 @@ public class SebExamConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_FROM_LIST)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROPERTIES_FROM_LIST)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent());
}

View file

@ -0,0 +1,175 @@
/*
* 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.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component
@GuiProfile
public class SebExamConfigPropForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPropForm.class);
private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.examconfig.form.title.new");
private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.examconfig.form.title");
private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.name");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.description");
private static final LocTextKey FORM_STATUS_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.status");
private final PageService pageService;
private final RestService restService;
private final CurrentUser currentUser;
protected SebExamConfigPropForm(
final PageService pageService,
final RestService restService,
final CurrentUser currentUser) {
this.pageService = pageService;
this.restService = restService;
this.currentUser = currentUser;
}
@Override
public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final ResourceService resourceService = this.pageService.getResourceService();
final UserInfo user = this.currentUser.get();
final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean isNew = entityKey == null;
// get data or create new. Handle error if happen
final ConfigurationNode examConfig = (isNew)
? ConfigurationNode.createNewExamConfig((parentEntityKey != null)
? Long.valueOf(parentEntityKey.modelId)
: user.institutionId)
: this.restService
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (examConfig == null) {
log.error("Failed to get ConfigurationNode. "
+ "Error was notified to the User. "
+ "See previous logs for more infomation");
return;
}
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean writeGrant = entityGrant.w();
final boolean modifyGrant = entityGrant.m();
final boolean isReadonly = pageContext.isReadonly();
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
// the default page layout with interactive title
final LocTextKey titleKey = (isNew)
? FORM_TITLE_NEW
: FORM_TITLE;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);
// The SebClientConfig form
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.CONFIGURATION_NODE.ATTR_ID,
examConfig.getModelId())
.putStaticValue(
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
String.valueOf(examConfig.getInstitutionId()))
.putStaticValue(
Domain.CONFIGURATION_NODE.ATTR_TYPE,
ConfigurationType.EXAM_CONFIG.name())
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_NAME,
FORM_NAME_TEXT_KEY,
examConfig.name))
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
examConfig.description).asArea())
.addField(FormBuilder.singleSelection(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
FORM_STATUS_TEXT_KEY,
examConfig.status.name(),
resourceService::examConfigStatusResources))
.buildFor((isNew)
? this.restService.getRestCall(NewExamConfig.class)
: this.restService.getRestCall(SaveExamConfig.class));
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(() -> writeGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE)
.withEntityKey(entityKey)
.withExec(formHandle::processFormSave)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_CANCEL_MODIFY)
.withEntityKey(entityKey)
.withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
action,
ActionDefinition.SEB_EXAM_CONFIG_LIST))
.publishIf(() -> !isReadonly);
}
}

View file

@ -1,141 +0,0 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.content;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
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.impl.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
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.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component
@GuiProfile
public class SebExamConfigPropertiesForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPropertiesForm.class);
private static final String VIEW_TEXT_KEY_PREFIX = "sebserver.examconfig.props.form.views.";
private static final String VIEW_TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip";
private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.props.from.title");
private final PageService pageService;
private final RestService restService;
private final CurrentUser currentUser;
private final ExamConfigurationService examConfigurationService;
protected SebExamConfigPropertiesForm(
final PageService pageService,
final RestService restService,
final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) {
this.pageService = pageService;
this.restService = restService;
this.currentUser = currentUser;
this.examConfigurationService = examConfigurationService;
}
@Override
public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(),
TITLE_TEXT_KEY);
try {
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.onError(pageContext::notifyError)
.getOrThrow();
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configNode.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call()
.map(Utils::toSingleton)
.onError(pageContext::notifyError)
.getOrThrow();
final AttributeMapping attributes = this.examConfigurationService
.getAttributes(configNode.templateId)
.onError(pageContext::notifyError)
.getOrThrow();
final List<View> views = this.examConfigurationService.getViews(attributes);
final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content);
tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final List<ViewContext> viewContexts = new ArrayList<>();
for (final View view : views) {
final ViewContext viewContext = this.examConfigurationService.createViewContext(
pageContext,
configuration,
view,
attributes,
20);
viewContexts.add(viewContext);
final Composite viewGrid = this.examConfigurationService.createViewGrid(
tabFolder,
viewContext);
final TabItem tabItem = widgetFactory.tabItemLocalized(
tabFolder,
new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name));
tabItem.setControl(viewGrid);
}
this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts);
} catch (final Exception e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
pageContext.notifyError(e);
}
}
}

View file

@ -307,17 +307,22 @@ public enum ActionDefinition {
SEB_EXAM_CONFIG_NEW(
new LocTextKey("sebserver.examconfig.action.list.new"),
ImageIcon.NEW,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT),
SEB_EXAM_CONFIG_VIEW_FROM_LIST(
PageStateDefinition.SEB_EXAM_CONFIG_PROP_EDIT),
SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.view"),
ImageIcon.SHOW,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_MODIFY_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify"),
SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify.properties"),
ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_PROP_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_PROP_MODIFY(
new LocTextKey("sebserver.examconfig.action.modify.properties"),
ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_PROP_EDIT,
ActionCategory.FORM),
SEB_EXAM_CONFIG_MODIFY(
new LocTextKey("sebserver.examconfig.action.modify"),
ImageIcon.EDIT,
@ -334,10 +339,10 @@ public enum ActionDefinition {
PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_MODIFY_PROPERTIES_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify.properties"),
SEB_EXAM_CONFIG_MODIFY_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify"),
ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_PROPERTIES_EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST),
;

View file

@ -20,7 +20,7 @@ import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigForm;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropertiesForm;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
@ -56,10 +56,9 @@ public enum PageStateDefinition implements PageState {
SEB_CLIENT_CONFIG_EDIT(Type.FORM_EDIT, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG),
SEB_EXAM_CONFIG_LIST(Type.LIST_VIEW, SebExamConfigList.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_EDIT(Type.FORM_EDIT, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_PROPERTIES_EDIT(Type.FORM_VIEW, SebExamConfigPropertiesForm.class,
ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_PROP_EDIT(Type.FORM_EDIT, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_EDIT(Type.FORM_VIEW, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
;

View file

@ -31,6 +31,7 @@ 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();
@ -85,4 +86,11 @@ public interface ExamConfigurationService {
}
}
static LocTextKey getTablePopupTitleKey(
final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) {
return new LocTextKey(ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + TABLE_ROW_TITLE_SUFFIX);
}
}

View file

@ -27,6 +27,8 @@ public interface InputField {
String getValue();
String getReadableValue();
void showError(String errorMessage);
void clearError();

View file

@ -48,13 +48,15 @@ public interface InputFieldBuilder {
static Composite createInnerGrid(
final Composite parent,
final ConfigurationAttribute attribute,
final Orientation orientation) {
return createInnerGrid(parent, orientation, 1);
return createInnerGrid(parent, attribute, orientation, 1);
}
static Composite createInnerGrid(
final Composite parent,
final ConfigurationAttribute attribute,
final Orientation orientation,
final int numColumns) {
@ -69,8 +71,8 @@ public interface InputFieldBuilder {
final GridData gridData = new GridData(
SWT.FILL, SWT.FILL,
true, false,
(orientation != null) ? orientation.width() : 1,
(orientation != null) ? orientation.height() : 1);
(orientation != null && attribute.parentId == null) ? orientation.width() : 1,
(orientation != null && attribute.parentId == null) ? orientation.height() : 1);
comp.setLayoutData(gridData);
return comp;
}

View file

@ -129,6 +129,12 @@ public abstract class AbstractInputField<T extends Control> implements InputFiel
}
}
@Override
public String getReadableValue() {
return getValue();
}
protected abstract void setValueToControl(String value);
}

View file

@ -45,11 +45,6 @@ public class AttributeMapping {
Objects.requireNonNull(orientations);
this.templateId = templateId;
this.attributeIdMapping = Utils.immutableMapOf(attributes
.stream()
.collect(Collectors.toMap(
attr -> attr.id,
Function.identity())));
this.orientationAttributeMapping = Utils.immutableMapOf(orientations
.stream()
@ -57,8 +52,16 @@ public class AttributeMapping {
o -> o.attributeId,
Function.identity())));
this.attributeIdMapping = Utils.immutableMapOf(attributes
.stream()
.filter(attr -> this.orientationAttributeMapping.containsKey(attr.id))
.collect(Collectors.toMap(
attr -> attr.id,
Function.identity())));
this.attributeNameIdMapping = Utils.immutableMapOf(attributes
.stream()
.filter(attr -> this.orientationAttributeMapping.containsKey(attr.id))
.collect(Collectors.toMap(
attr -> attr.name,
attr -> attr.id)));
@ -71,6 +74,7 @@ public class AttributeMapping {
this.childAttributeMapping = Utils.immutableMapOf(attributes
.stream()
.filter(attr -> this.orientationAttributeMapping.containsKey(attr.id))
.collect(Collectors.toMap(
attr -> attr.id,
this::getChildAttributes)));
@ -184,7 +188,7 @@ public class AttributeMapping {
.values()
.stream()
.filter(o -> groupName.equals(o.groupId))
.sorted((o1, o2) -> (o1.yPosition == o2.yPosition)
.sorted((o1, o2) -> (o1.yPosition != null && o1.yPosition.equals(o2.yPosition))
? o1.xPosition.compareTo(o2.xPosition)
: o1.yPosition.compareTo(o2.yPosition))
.map(o -> this.attributeIdMapping.get(o.attributeId))

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import static ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.dummyBuilderAdapter;
import java.util.Collection;
import org.eclipse.swt.SWT;
@ -28,6 +30,10 @@ interface CellFieldBuilderAdapter {
void createCell(ViewGridBuilder builder);
default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) {
}
static CellFieldBuilderAdapter dummyBuilderAdapter() {
return new CellFieldBuilderAdapter() {
@Override
@ -71,6 +77,9 @@ interface CellFieldBuilderAdapter {
final Orientation orientation) {
return new CellFieldBuilderAdapter() {
private int span = 1;
@Override
public void createCell(final ViewGridBuilder builder) {
@ -88,21 +97,16 @@ interface CellFieldBuilderAdapter {
gridData.verticalIndent = 5;
break;
}
case RIGHT_SPAN:
case LEFT_SPAN: {
label.setAlignment(SWT.LEFT);
gridData.horizontalSpan = orientation.width;
gridData.horizontalSpan = (span > 1) ? span : orientation.width;
gridData.verticalIndent = 5;
break;
}
case RIGHT_SPAN: {
label.setAlignment(SWT.LEFT);
gridData.verticalIndent = 5;
gridData.horizontalSpan = orientation.width;
break;
}
case TOP: {
gridData.horizontalSpan = orientation.width;
label.setAlignment(SWT.LEFT);
gridData.verticalAlignment = SWT.BOTTOM;
break;
}
@ -114,6 +118,22 @@ interface CellFieldBuilderAdapter {
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] = dummyBuilderAdapter();
this.span++;
xpos--;
}
}
}
@Override
public String toString() {
return "[LABEL]";
@ -185,7 +205,7 @@ interface CellFieldBuilderAdapter {
builder.parent,
this.width,
groupLabelKey);
group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, this.width, this.height));
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, this.width, this.height));
final ViewGridBuilder groupBuilder = new ViewGridBuilder(
group,

View file

@ -11,6 +11,7 @@ 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;
@ -20,6 +21,7 @@ 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;
@ -64,14 +66,20 @@ public class CheckBoxBuilder implements InputFieldBuilder {
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final Button checkbox = this.widgetFactory.buttonLocalized(
innerGrid,
SWT.CHECK,
ExamConfigurationService.attributeNameLocKey(attribute),
(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),
@ -95,9 +103,7 @@ public class CheckBoxBuilder implements InputFieldBuilder {
final Orientation orientation,
final Button control) {
super(attribute, orientation, control, (orientation.groupId == null)
? InputFieldBuilder.createErrorLabel(control.getParent())
: null);
super(attribute, orientation, control, null);
}
@Override
@ -111,6 +117,14 @@ public class CheckBoxBuilder implements InputFieldBuilder {
? Constants.TRUE_STRING
: Constants.FALSE_STRING;
}
@Override
public String getReadableValue() {
return this.control.getSelection()
? "Active"
: "Inactive";
}
}
}

View file

@ -0,0 +1,17 @@
/*
* 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;
public class InlineTableFieldBuilder {
public InlineTableFieldBuilder() {
// TODO Auto-generated constructor stub
}
}

View file

@ -54,14 +54,14 @@ public class MultiCheckboxSelection extends SelectionFieldBuilder implements Inp
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final MultiSelectionCheckbox selection = this.widgetFactory.selectionLocalized(
Selection.Type.MULTI_CHECKBOX,
innerGrid,
() -> this.getLocalizedResources(attribute, i18nSupport),
() -> this.getLocalizedResources(attribute, viewContext),
null,
() -> this.getLocalizedResourcesAsToolTip(attribute, i18nSupport))
() -> this.getLocalizedResourcesAsToolTip(attribute, viewContext))
.getTypeInstance();
selection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

View file

@ -64,7 +64,7 @@ public class PassworFieldBuilder implements InputFieldBuilder {
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final Text passwordInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
passwordInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

View file

@ -56,14 +56,14 @@ public class RadioSelectionFieldBuilder extends SelectionFieldBuilder implements
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final RadioSelection selection = this.widgetFactory.selectionLocalized(
Selection.Type.RADIO,
innerGrid,
() -> this.getLocalizedResources(attribute, i18nSupport),
() -> this.getLocalizedResources(attribute, viewContext),
null,
() -> this.getLocalizedResourcesAsToolTip(attribute, i18nSupport))
() -> this.getLocalizedResourcesAsToolTip(attribute, viewContext))
.getTypeInstance();
selection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
@ -71,7 +71,7 @@ public class RadioSelectionFieldBuilder extends SelectionFieldBuilder implements
attribute,
orientation,
selection,
InputFieldBuilder.createErrorLabel(innerGrid));
null);
selection.setSelectionListener(event -> {
radioSelectionInputField.clearError();

View file

@ -21,27 +21,26 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
public abstract class SelectionFieldBuilder {
protected List<Tuple<String>> getLocalizedResources(
final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) {
final ViewContext viewContext) {
return getLocalizedRes(attribute, i18nSupport, false);
return getLocalizedRes(attribute, viewContext, false);
}
protected List<Tuple<String>> getLocalizedResourcesAsToolTip(
final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) {
final ViewContext viewContext) {
return getLocalizedRes(attribute, i18nSupport, true);
return getLocalizedRes(attribute, viewContext, true);
}
private List<Tuple<String>> getLocalizedRes(
final ConfigurationAttribute attribute,
final I18nSupport i18nSupport,
final ViewContext viewContext,
final boolean toolTipResources) {
if (attribute == null) {
@ -62,7 +61,7 @@ public abstract class SelectionFieldBuilder {
final String key = prefix + value + ((toolTipResources)
? ExamConfigurationService.TOOL_TIP_SUFFIX
: "");
final String text = i18nSupport.getText(key, "");
final String text = viewContext.i18nSupport.getText(key, "");
return new Tuple<>(value, (StringUtils.isBlank(text))
? (toolTipResources)
? text

View file

@ -57,14 +57,14 @@ public class SingleSelectionFieldBuilder extends SelectionFieldBuilder implement
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final SingleSelection selection = this.widgetFactory.selectionLocalized(
(attribute.type == AttributeType.COMBO_SELECTION)
? Selection.Type.SINGLE_COMBO
: Selection.Type.SINGLE,
innerGrid,
() -> this.getLocalizedResources(attribute, i18nSupport),
() -> this.getLocalizedResources(attribute, viewContext),
ExamConfigurationService.getToolTipKey(attribute, i18nSupport))
.getTypeInstance();
@ -107,6 +107,14 @@ public class SingleSelectionFieldBuilder extends SelectionFieldBuilder implement
protected void setValueToControl(final String value) {
this.control.select(value);
}
@Override
public String getReadableValue() {
// TODO Auto-generated method stub
return super.getReadableValue();
}
}
}

View file

@ -51,7 +51,7 @@ public class SliderFieldBuilder implements InputFieldBuilder {
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final Slider slider = new Slider(innerGrid, SWT.NONE);
slider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

View file

@ -16,6 +16,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -23,6 +24,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain;
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.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.examconfig.ValueChangeListener;
@ -58,8 +60,8 @@ public class TableContext {
this.attribute = Objects.requireNonNull(attribute);
this.viewContext = Objects.requireNonNull(viewContext);
this.orientation = viewContext
.getOrientation(attribute.id);
this.orientation = Objects.requireNonNull(viewContext
.getOrientation(attribute.id));
this.rowAttributes = viewContext.getChildAttributes(attribute.id)
.stream()
@ -183,4 +185,29 @@ public class TableContext {
};
}
public String getRowValue(final TableValue tableValue) {
final ConfigurationAttribute attribute = this.viewContext.getAttribute(tableValue.attributeId);
if (attribute != null) {
switch (attribute.type) {
case CHECKBOX: {
return BooleanUtils.toBoolean(tableValue.value)
? "Active"
: "Inactive";
}
case SINGLE_SELECTION: {
final ConfigurationAttribute tableAttr =
this.viewContext.attributeMapping.getAttribute(attribute.parentId);
final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
attribute.getName() + "." +
tableValue.value;
return this.viewContext.i18nSupport.getText(key, tableValue.value);
}
default:
return tableValue.value;
}
}
return tableValue.value;
}
}

View file

@ -20,7 +20,6 @@ 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.Event;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
@ -40,7 +39,6 @@ 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.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;
@ -105,15 +103,16 @@ public class TableFieldBuilder implements InputFieldBuilder {
true, false,
(tableContext.orientation != null) ? tableContext.orientation.width() : 1,
(tableContext.orientation != null) ? tableContext.orientation.height() : 1);
gridData.heightHint = tableContext.orientation.height * 40;
gridData.heightHint = tableContext.orientation.height * 20 + 40;
table.setLayoutData(gridData);
table.setHeaderVisible(true);
table.addListener(SWT.Resize, this::adaptColumnWidth);
table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
final TableColumn column = new TableColumn(table, SWT.NONE);
final String text = i18nSupport.getText(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + columnAttribute.name,
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
columnAttribute.name,
columnAttribute.name);
column.setText(text);
column.setWidth(100);
@ -159,14 +158,25 @@ public class TableFieldBuilder implements InputFieldBuilder {
return tableField;
}
private void adaptColumnWidth(final Event event) {
private void adaptColumnWidth(
final Table table,
final TableContext tableContext) {
try {
final Table table = (Table) event.widget;
final int currentTableWidth = table.getClientArea().width - 50;
final TableColumn[] columns = table.getColumns();
final int columnWidth = currentTableWidth / (columns.length - 2);
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 - 2; i++) {
columns[i].setWidth(columnWidth);
columns[i].setWidth(widthUnit * orientations.get(i).width);
}
} catch (final Exception e) {
log.warn("Failed to adaptColumnWidth: ", e);
@ -196,6 +206,12 @@ public class TableFieldBuilder implements InputFieldBuilder {
.map(TableValue::of)
.collect(Collectors.toList());
initValue(tableValues);
return null;
}
void initValue(final List<TableValue> tableValues) {
final Map<Integer, Map<Long, TableValue>> _initValue = new HashMap<>();
for (final TableValue tableValue : tableValues) {
final Map<Long, TableValue> rowValues = _initValue.computeIfAbsent(
@ -215,13 +231,24 @@ public class TableFieldBuilder implements InputFieldBuilder {
this.values.add(rowValues);
addTableRow(rowValues);
});
return null;
}
private boolean isChildValue(final ConfigurationValue value) {
return this.attribute.id.equals(
this.tableContext.getAttribute(value.attributeId).parentId);
if (!this.tableContext.getViewContext().attributeMapping.attributeIdMapping
.containsKey(value.attributeId)) {
return false;
}
ConfigurationAttribute attr = this.tableContext.getAttribute(value.attributeId);
while (attr.parentId != null) {
if (this.attribute.id.equals(attr.parentId)) {
return true;
}
attr = this.tableContext.getAttribute(attr.parentId);
}
return false;
}
private void deleteRow(final int selectionIndex) {
@ -254,22 +281,7 @@ public class TableFieldBuilder implements InputFieldBuilder {
final TableItem tableItem = new TableItem(this.control, SWT.NONE);
applyTableRowValues(this.values.size() - 1);
// TODO delete icon is not working on row as expected
// final TableEditor editor = new TableEditor(this.control);
// editor.horizontalAlignment = SWT.CENTER;
// editor.grabHorizontal = true;
// editor.minimumWidth = 20;
// final Image image = ImageIcon.REMOVE_BOX.getImage(this.control.getDisplay());
// final Label imageLabel = new Label(this.control, SWT.NONE);
// imageLabel.setAlignment(SWT.CENTER);
// imageLabel.setImage(image);
// imageLabel.addListener(SWT.MouseDown, event -> System.out.println("*************** removeRow"));
// editor.setEditor(imageLabel, tableItem, this.columnAttributes.size());
// tableItem.setData("EDITOR", editor);
//
// editor.layout();
// this.control.layout(true, true);
// TODO try to add delete button within table row?
}
private void applyTableRowValues(final int index) {
@ -279,7 +291,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
int cellIndex = 0;
for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) {
if (rowValues.containsKey(attr.id)) {
item.setText(cellIndex, rowValues.get(attr.id).value);
item.setText(
cellIndex,
this.tableContext.getRowValue(rowValues.get(attr.id)));
}
cellIndex++;
}
@ -299,7 +313,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
this.tableContext.getWidgetFactory())
.setDialogWidth(500)
.open(
new LocTextKey("Title"),
ExamConfigurationService.getTablePopupTitleKey(
this.attribute,
this.tableContext.getViewContext().i18nSupport),
values -> applyFormValues(values, selectionIndex),
builder);
}
@ -313,6 +329,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
this.values.remove(index);
this.values.add(index, tableRowValues);
applyTableRowValues(index);
// send new values to web-service
this.tableContext.getValueChangeListener()
.tableChanged(extractTableValue());
}
private ConfigurationTableValues extractTableValue() {
@ -353,12 +372,13 @@ public class TableFieldBuilder implements InputFieldBuilder {
@Override
protected void setValueToControl(final String value) {
throw new UnsupportedOperationException();
//throw new UnsupportedOperationException();
}
@Override
public String getValue() {
throw new UnsupportedOperationException();
return null;
//throw new UnsupportedOperationException();
}
}

View file

@ -29,6 +29,7 @@ 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.examconfig.impl.TableFieldBuilder.TableInputField;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@ -82,25 +83,27 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
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!");
}
// 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());
inputField.initValue(
this.rowValues.get(attribute.id).value,
this.listIndex);
if (attribute.type == AttributeType.TABLE) {
((TableInputField) inputField).initValue(new ArrayList<>(this.rowValues.values()));
} else {
inputField.initValue(
this.rowValues.get(attribute.id).value,
this.listIndex);
}
// we have to register the input field within the ViewContext to receive error messages
this.tableContext.registerInputField(inputField);
@ -108,9 +111,13 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
return inputField;
}
private void createLabel(final Composite parent, final ConfigurationAttribute attribute) {
private void createLabel(
final Composite parent,
final ConfigurationAttribute attribute) {
final LocTextKey locTextKey = new LocTextKey(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name,
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
attribute.name,
attribute.name);
final Label label = this.tableContext
.getWidgetFactory()

View file

@ -61,7 +61,7 @@ public class TextFieldBuilder implements InputFieldBuilder {
final Orientation orientation = viewContext
.getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation);
.createInnerGrid(parent, attribute, orientation);
final Text text;
if (attribute.type == AttributeType.INTEGER ||

View file

@ -33,10 +33,10 @@ public final class ViewContext {
private final View view;
private final int rows;
private final AttributeMapping attributeMapping;
private final Map<Long, InputField> inputFieldMapping;
private final ValueChangeListener valueChangeListener;
private final I18nSupport i18nSupport;
final AttributeMapping attributeMapping;
final Map<Long, InputField> inputFieldMapping;
final ValueChangeListener valueChangeListener;
final I18nSupport i18nSupport;
ViewContext(
final Configuration configuration,

View file

@ -67,6 +67,10 @@ public class ViewGridBuilder {
}
ViewGridBuilder add(final ConfigurationAttribute attribute) {
if (log.isDebugEnabled()) {
log.debug("Add SEB Configuration Attribute: " + attribute);
}
// ignore nested attributes here
if (attribute.parentId != null) {
return this;
@ -115,7 +119,8 @@ public class ViewGridBuilder {
orientation);
break;
}
case LEFT: {
case LEFT:
case LEFT_SPAN: {
this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder(
attribute,
orientation);
@ -127,17 +132,17 @@ public class ViewGridBuilder {
}
break;
}
case LEFT_SPAN: {
int spanxpos = xpos - orientation.width;
if (spanxpos < 0) {
spanxpos = 0;
}
fillDummy(spanxpos, ypos, orientation.width, 1);
this.grid[ypos][spanxpos] = CellFieldBuilderAdapter.labelBuilder(
attribute,
orientation);
break;
}
// case LEFT_SPAN: {
// int spanxpos = xpos - orientation.width;
// if (spanxpos < 0) {
// spanxpos = 0;
// }
// fillDummy(spanxpos, ypos, orientation.width, 1);
// this.grid[ypos][spanxpos] = CellFieldBuilderAdapter.labelBuilder(
// attribute,
// orientation);
// break;
// }
case TOP: {
fillDummy(xpos, ypos - 1, orientation.width, 1);
this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder(
@ -160,9 +165,11 @@ public class ViewGridBuilder {
log.debug("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);
}
}
}
@ -174,7 +181,7 @@ public class ViewGridBuilder {
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
gridData.verticalIndent = 8;
empty.setLayoutData(gridData);
empty.setText("");
empty.setText("" /* "empty " + x + " " + y */);
} else {
this.grid[y][x].createCell(this);
}

View file

@ -0,0 +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.rules;
import org.apache.commons.lang3.BooleanUtils;
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 AllowFlashFullscreenRule implements ValueChangeRule {
public static final String KEY_THIRD_PART = "allowSwitchToApplications";
public static final String KEY_FULL_SCREEN = "allowFlashFullscreen";
@Override
public boolean observesAttribute(final ConfigurationAttribute attribute) {
return KEY_THIRD_PART.equals(attribute.name);
}
@Override
public void applyRule(
final ViewContext context,
final ConfigurationAttribute attribut,
final ConfigurationValue value) {
if (BooleanUtils.toBoolean(value.value)) {
context.enable(KEY_FULL_SCREEN);
} else {
context.disable(KEY_FULL_SCREEN);
}
}
}

View file

@ -37,6 +37,10 @@ public interface Selection {
String getSelectionValue();
default String getSelectionReadableValue() {
return getSelectionValue();
}
void clear();
void setVisible(boolean visible);

View file

@ -17,6 +17,7 @@ import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
public final class SingleSelection extends Combo implements Selection {
@ -73,6 +74,16 @@ public final class SingleSelection extends Combo implements Selection {
return this.keyMapping.get(selectionindex);
}
@Override
public String getSelectionReadableValue() {
final int selectionindex = super.getSelectionIndex();
if (selectionindex < 0) {
return Constants.EMPTY_NOTE;
}
return this.valueMapping.get(selectionindex);
}
@Override
public void clear() {
super.clearSelection();

View file

@ -56,7 +56,7 @@ public class ExitKeySequenceValidator implements ConfigurationValueValidator {
}
try {
return this.configurationValueRecordMapper.selectByExample()
return !this.configurationValueRecordMapper.selectByExample()
.join(ConfigurationAttributeRecordDynamicSqlSupport.configurationAttributeRecord)
.on(
ConfigurationAttributeRecordDynamicSqlSupport.id,
@ -75,7 +75,7 @@ public class ExitKeySequenceValidator implements ConfigurationValueValidator {
.stream()
.filter(val -> value.value.equals(val.getValue()))
.findFirst()
.isEmpty();
.isPresent();
} catch (final Exception e) {
log.error("unexpected error while trying to validate SEB exam configuration attributes: {}", ATTR_NAMES, e);
return true;

View file

@ -358,6 +358,7 @@ sebserver.examconfig.action.list.view=View Configuration
sebserver.examconfig.action.list.modify=Edit
sebserver.examconfig.action.list.modify.properties=Edit Properties
sebserver.examconfig.action.modify=Edit
sebserver.examconfig.action.modify.properties=Edit Properties
sebserver.examconfig.action.save=Save
sebserver.examconfig.form.title.new=New Exam Configuration
@ -376,6 +377,7 @@ sebserver.examconfig.props.form.views.user_interface=User Interface
sebserver.examconfig.props.form.views.browser=Browser
sebserver.examconfig.props.form.views.down_upload=Down/Uploads
sebserver.examconfig.props.form.views.exam=Exam
sebserver.examconfig.props.form.views.applications=Applications
sebserver.examconfig.props.label.hashedAdminPassword=Administrator password
sebserver.examconfig.props.label.hashedAdminPassword.confirm=Confirm password
@ -532,6 +534,42 @@ sebserver.examconfig.props.label.restartExamURL=Enter custom URL or select 'Use
sebserver.examconfig.props.label.restartExamText=Title/tool tip text for the back to start button (leave empty for localized standard text)
sebserver.examconfig.props.label.restartExamPasswordProtected=Protect back to start button with the quit/unlock password
sebserver.examconfig.props.label.allowSwitchToApplications=Allow switching to third party application (Mac)
sebserver.examconfig.props.label.allowFlashFullscreen=Allow Flash to switch to fullscreen mode (Mac)
sebserver.examconfig.props.label.permittedProcesses.row.title=Permitted Processes
sebserver.examconfig.props.label.permittedProcesses=Permitted Processes
sebserver.examconfig.props.label.permittedProcesses.active=Activity
sebserver.examconfig.props.label.permittedProcesses.os=OS
sebserver.examconfig.props.label.permittedProcesses.os.0=Win
sebserver.examconfig.props.label.permittedProcesses.os.1=OS X
sebserver.examconfig.props.label.permittedProcesses.title=Title
sebserver.examconfig.props.label.permittedProcesses.description=Description
sebserver.examconfig.props.label.permittedProcesses.executable=Executable
sebserver.examconfig.props.label.permittedProcesses.originalName=Original Name
sebserver.examconfig.props.label.permittedProcesses.allowedExecutables=Window handling process
sebserver.examconfig.props.label.permittedProcesses.path=Path
sebserver.examconfig.props.label.permittedProcesses.arguments=Arguments
sebserver.examconfig.props.label.arguments.active=Activity
sebserver.examconfig.props.label.arguments.argument=Argument
sebserver.examconfig.props.label.permittedProcesses.identifier=Identifier
sebserver.examconfig.props.label.permittedProcesses.iconInTaskbar=Icon in taskbar
sebserver.examconfig.props.label.permittedProcesses.autostart=Autostart
sebserver.examconfig.props.label.permittedProcesses.runInBackground=Allow running in background
sebserver.examconfig.props.label.permittedProcesses.allowUserToChooseApp=Allow user to select location of application
sebserver.examconfig.props.label.permittedProcesses.strongKill=Force quit (risk of data loss)
sebserver.examconfig.props.label.prohibitedProcesses.row.title=Prohibited Processes
sebserver.examconfig.props.label.prohibitedProcesses=Prohibited Processes
sebserver.examconfig.props.label.prohibitedProcesses.active=Activity
sebserver.examconfig.props.label.prohibitedProcesses.os=OS
sebserver.examconfig.props.label.prohibitedProcesses.os.0=Win
sebserver.examconfig.props.label.prohibitedProcesses.os.1=OS X
sebserver.examconfig.props.label.prohibitedProcesses.description=Description
sebserver.examconfig.props.label.prohibitedProcesses.executable=Executable
sebserver.examconfig.props.label.prohibitedProcesses.originalName=Original Name
sebserver.examconfig.props.label.prohibitedProcesses.identifier=Identifier
sebserver.examconfig.props.label.prohibitedProcesses.strongKill=Force quit (risk of data loss)
sebserver.examconfig.props.validation.password.confirm=Please enter correct confirm password
sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly