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 type is a list of a composite of single types */
TABLE(COMPOSITE_LIST), TABLE(COMPOSITE_LIST),
STATIC_TABLE(COMPOSITE_LIST); INLINE_TABLE(COMPOSITE_LIST),
;
public final AttributeValueType attributeValueType; public final AttributeValueType attributeValueType;

View file

@ -8,33 +8,38 @@
package ch.ethz.seb.sebserver.gui.content; 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.Composite;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; 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.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;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.ResourceService; 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.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; 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.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;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@ -44,127 +49,92 @@ public class SebExamConfigForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigForm.class); private static final Logger log = LoggerFactory.getLogger(SebExamConfigForm.class);
private static final LocTextKey FORM_TITLE_NEW = private static final String VIEW_TEXT_KEY_PREFIX = "sebserver.examconfig.props.form.views.";
new LocTextKey("sebserver.examconfig.form.title.new"); private static final String VIEW_TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip";
private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.examconfig.form.title"); private static final LocTextKey TITLE_TEXT_KEY =
private static final LocTextKey FORM_NAME_TEXT_KEY = new LocTextKey("sebserver.examconfig.props.from.title");
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 PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ExamConfigurationService examConfigurationService;
protected SebExamConfigForm( protected SebExamConfigForm(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser) { final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.examConfigurationService = examConfigurationService;
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); 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 entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey(); 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( final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(), pageContext.getParent(),
titleKey); TITLE_TEXT_KEY);
// The SebClientConfig form try {
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()) 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) final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.publishIf(() -> writeGrant && isReadonly) .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) final AttributeMapping attributes = this.examConfigurationService
.withEntityKey(entityKey) .getAttributes(configNode.templateId)
.publishIf(() -> modifyGrant && isReadonly) .onError(pageContext::notifyError)
.getOrThrow();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE) final List<View> views = this.examConfigurationService.getViews(attributes);
.withEntityKey(entityKey)
.withExec(formHandle::processFormSave)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_CANCEL_MODIFY) final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content);
.withEntityKey(entityKey) tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
.withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
action, final List<ViewContext> viewContexts = new ArrayList<>();
ActionDefinition.SEB_EXAM_CONFIG_LIST)) for (final View view : views) {
.publishIf(() -> !isReadonly); 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, this.statusFilter,
true)) true))
.withDefaultAction(pageActionBuilder .withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.create()) .create())
.compose(content); .compose(content);
@ -147,15 +147,15 @@ public class SebExamConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW) .newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(examConfigGrant::iw) .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) .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent()) .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) .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent()) .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) .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent()); .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( SEB_EXAM_CONFIG_NEW(
new LocTextKey("sebserver.examconfig.action.list.new"), new LocTextKey("sebserver.examconfig.action.list.new"),
ImageIcon.NEW, ImageIcon.NEW,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT), PageStateDefinition.SEB_EXAM_CONFIG_PROP_EDIT),
SEB_EXAM_CONFIG_VIEW_FROM_LIST( SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.view"), new LocTextKey("sebserver.examconfig.action.list.view"),
ImageIcon.SHOW, ImageIcon.SHOW,
PageStateDefinition.SEB_EXAM_CONFIG_VIEW, PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.SEB_EXAM_CONFIG_LIST), ActionCategory.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_MODIFY_FROM_LIST( SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify"), new LocTextKey("sebserver.examconfig.action.list.modify.properties"),
ImageIcon.EDIT, ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT, PageStateDefinition.SEB_EXAM_CONFIG_PROP_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST), 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( SEB_EXAM_CONFIG_MODIFY(
new LocTextKey("sebserver.examconfig.action.modify"), new LocTextKey("sebserver.examconfig.action.modify"),
ImageIcon.EDIT, ImageIcon.EDIT,
@ -334,10 +339,10 @@ public enum ActionDefinition {
PageStateDefinition.SEB_EXAM_CONFIG_VIEW, PageStateDefinition.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM), ActionCategory.FORM),
SEB_EXAM_CONFIG_MODIFY_PROPERTIES_FROM_LIST( SEB_EXAM_CONFIG_MODIFY_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify.properties"), new LocTextKey("sebserver.examconfig.action.list.modify"),
ImageIcon.EDIT, ImageIcon.EDIT,
PageStateDefinition.SEB_EXAM_CONFIG_PROPERTIES_EDIT, PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST), 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.SebClientConfigList;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigForm; import ch.ethz.seb.sebserver.gui.content.SebExamConfigForm;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList; 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.UserAccountChangePasswordForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountForm; import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountList; 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_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_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_VIEW(Type.FORM_VIEW, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_EDIT(Type.FORM_EDIT, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_PROP_EDIT(Type.FORM_EDIT, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_PROPERTIES_EDIT(Type.FORM_VIEW, SebExamConfigPropertiesForm.class, SEB_EXAM_CONFIG_EDIT(Type.FORM_VIEW, SebExamConfigForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
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 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 GROUP_LABEL_LOC_TEXT_PREFIX = "sebserver.examconfig.props.group.";
public static final String TOOL_TIP_SUFFIX = ".tooltip"; public static final String TOOL_TIP_SUFFIX = ".tooltip";
public static final String TABLE_ROW_TITLE_SUFFIX = ".row.title";
WidgetFactory getWidgetFactory(); 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 getValue();
String getReadableValue();
void showError(String errorMessage); void showError(String errorMessage);
void clearError(); void clearError();

View file

@ -48,13 +48,15 @@ public interface InputFieldBuilder {
static Composite createInnerGrid( static Composite createInnerGrid(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute,
final Orientation orientation) { final Orientation orientation) {
return createInnerGrid(parent, orientation, 1); return createInnerGrid(parent, attribute, orientation, 1);
} }
static Composite createInnerGrid( static Composite createInnerGrid(
final Composite parent, final Composite parent,
final ConfigurationAttribute attribute,
final Orientation orientation, final Orientation orientation,
final int numColumns) { final int numColumns) {
@ -69,8 +71,8 @@ public interface InputFieldBuilder {
final GridData gridData = new GridData( final GridData gridData = new GridData(
SWT.FILL, SWT.FILL, SWT.FILL, SWT.FILL,
true, false, true, false,
(orientation != null) ? orientation.width() : 1, (orientation != null && attribute.parentId == null) ? orientation.width() : 1,
(orientation != null) ? orientation.height() : 1); (orientation != null && attribute.parentId == null) ? orientation.height() : 1);
comp.setLayoutData(gridData); comp.setLayoutData(gridData);
return comp; 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); protected abstract void setValueToControl(String value);
} }

View file

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

View file

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

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
import java.util.Objects; import java.util.Objects;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -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.AttributeType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
@ -64,14 +66,20 @@ public class CheckBoxBuilder implements InputFieldBuilder {
final Orientation orientation = viewContext final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation); .createInnerGrid(parent, attribute, orientation);
final Button checkbox = this.widgetFactory.buttonLocalized( final Button checkbox = this.widgetFactory.buttonLocalized(
innerGrid, innerGrid,
SWT.CHECK, SWT.CHECK,
ExamConfigurationService.attributeNameLocKey(attribute), (orientation.title == TitleOrientation.NONE)
? ExamConfigurationService.attributeNameLocKey(attribute)
: null,
ExamConfigurationService.getToolTipKey(attribute, i18nSupport)); 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( final CheckboxField checkboxField = new CheckboxField(
attribute, attribute,
viewContext.getOrientation(attribute.id), viewContext.getOrientation(attribute.id),
@ -95,9 +103,7 @@ public class CheckBoxBuilder implements InputFieldBuilder {
final Orientation orientation, final Orientation orientation,
final Button control) { final Button control) {
super(attribute, orientation, control, (orientation.groupId == null) super(attribute, orientation, control, null);
? InputFieldBuilder.createErrorLabel(control.getParent())
: null);
} }
@Override @Override
@ -111,6 +117,14 @@ public class CheckBoxBuilder implements InputFieldBuilder {
? Constants.TRUE_STRING ? Constants.TRUE_STRING
: Constants.FALSE_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 final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation); .createInnerGrid(parent, attribute, orientation);
final MultiSelectionCheckbox selection = this.widgetFactory.selectionLocalized( final MultiSelectionCheckbox selection = this.widgetFactory.selectionLocalized(
Selection.Type.MULTI_CHECKBOX, Selection.Type.MULTI_CHECKBOX,
innerGrid, innerGrid,
() -> this.getLocalizedResources(attribute, i18nSupport), () -> this.getLocalizedResources(attribute, viewContext),
null, null,
() -> this.getLocalizedResourcesAsToolTip(attribute, i18nSupport)) () -> this.getLocalizedResourcesAsToolTip(attribute, viewContext))
.getTypeInstance(); .getTypeInstance();
selection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 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 final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation); .createInnerGrid(parent, attribute, orientation);
final Text passwordInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD); final Text passwordInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
passwordInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 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 final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation); .createInnerGrid(parent, attribute, orientation);
final RadioSelection selection = this.widgetFactory.selectionLocalized( final RadioSelection selection = this.widgetFactory.selectionLocalized(
Selection.Type.RADIO, Selection.Type.RADIO,
innerGrid, innerGrid,
() -> this.getLocalizedResources(attribute, i18nSupport), () -> this.getLocalizedResources(attribute, viewContext),
null, null,
() -> this.getLocalizedResourcesAsToolTip(attribute, i18nSupport)) () -> this.getLocalizedResourcesAsToolTip(attribute, viewContext))
.getTypeInstance(); .getTypeInstance();
selection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); selection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
@ -71,7 +71,7 @@ public class RadioSelectionFieldBuilder extends SelectionFieldBuilder implements
attribute, attribute,
orientation, orientation,
selection, selection,
InputFieldBuilder.createErrorLabel(innerGrid)); null);
selection.setSelectionListener(event -> { selection.setSelectionListener(event -> {
radioSelectionInputField.clearError(); 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.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
public abstract class SelectionFieldBuilder { public abstract class SelectionFieldBuilder {
protected List<Tuple<String>> getLocalizedResources( protected List<Tuple<String>> getLocalizedResources(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) { final ViewContext viewContext) {
return getLocalizedRes(attribute, i18nSupport, false); return getLocalizedRes(attribute, viewContext, false);
} }
protected List<Tuple<String>> getLocalizedResourcesAsToolTip( protected List<Tuple<String>> getLocalizedResourcesAsToolTip(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final I18nSupport i18nSupport) { final ViewContext viewContext) {
return getLocalizedRes(attribute, i18nSupport, true); return getLocalizedRes(attribute, viewContext, true);
} }
private List<Tuple<String>> getLocalizedRes( private List<Tuple<String>> getLocalizedRes(
final ConfigurationAttribute attribute, final ConfigurationAttribute attribute,
final I18nSupport i18nSupport, final ViewContext viewContext,
final boolean toolTipResources) { final boolean toolTipResources) {
if (attribute == null) { if (attribute == null) {
@ -62,7 +61,7 @@ public abstract class SelectionFieldBuilder {
final String key = prefix + value + ((toolTipResources) final String key = prefix + value + ((toolTipResources)
? ExamConfigurationService.TOOL_TIP_SUFFIX ? ExamConfigurationService.TOOL_TIP_SUFFIX
: ""); : "");
final String text = i18nSupport.getText(key, ""); final String text = viewContext.i18nSupport.getText(key, "");
return new Tuple<>(value, (StringUtils.isBlank(text)) return new Tuple<>(value, (StringUtils.isBlank(text))
? (toolTipResources) ? (toolTipResources)
? text ? text

View file

@ -57,14 +57,14 @@ public class SingleSelectionFieldBuilder extends SelectionFieldBuilder implement
final Orientation orientation = viewContext final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation); .createInnerGrid(parent, attribute, orientation);
final SingleSelection selection = this.widgetFactory.selectionLocalized( final SingleSelection selection = this.widgetFactory.selectionLocalized(
(attribute.type == AttributeType.COMBO_SELECTION) (attribute.type == AttributeType.COMBO_SELECTION)
? Selection.Type.SINGLE_COMBO ? Selection.Type.SINGLE_COMBO
: Selection.Type.SINGLE, : Selection.Type.SINGLE,
innerGrid, innerGrid,
() -> this.getLocalizedResources(attribute, i18nSupport), () -> this.getLocalizedResources(attribute, viewContext),
ExamConfigurationService.getToolTipKey(attribute, i18nSupport)) ExamConfigurationService.getToolTipKey(attribute, i18nSupport))
.getTypeInstance(); .getTypeInstance();
@ -107,6 +107,14 @@ public class SingleSelectionFieldBuilder extends SelectionFieldBuilder implement
protected void setValueToControl(final String value) { protected void setValueToControl(final String value) {
this.control.select(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 final Orientation orientation = viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final Composite innerGrid = InputFieldBuilder final Composite innerGrid = InputFieldBuilder
.createInnerGrid(parent, orientation); .createInnerGrid(parent, attribute, orientation);
final Slider slider = new Slider(innerGrid, SWT.NONE); final Slider slider = new Slider(innerGrid, SWT.NONE);
slider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 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.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener; import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
@ -58,8 +60,8 @@ public class TableContext {
this.attribute = Objects.requireNonNull(attribute); this.attribute = Objects.requireNonNull(attribute);
this.viewContext = Objects.requireNonNull(viewContext); this.viewContext = Objects.requireNonNull(viewContext);
this.orientation = viewContext this.orientation = Objects.requireNonNull(viewContext
.getOrientation(attribute.id); .getOrientation(attribute.id));
this.rowAttributes = viewContext.getChildAttributes(attribute.id) this.rowAttributes = viewContext.getChildAttributes(attribute.id)
.stream() .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.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TableItem;
@ -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.InputField;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@ -105,15 +103,16 @@ public class TableFieldBuilder implements InputFieldBuilder {
true, false, true, false,
(tableContext.orientation != null) ? tableContext.orientation.width() : 1, (tableContext.orientation != null) ? tableContext.orientation.width() : 1,
(tableContext.orientation != null) ? tableContext.orientation.height() : 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.setLayoutData(gridData);
table.setHeaderVisible(true); table.setHeaderVisible(true);
table.addListener(SWT.Resize, this::adaptColumnWidth); table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) { for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
final TableColumn column = new TableColumn(table, SWT.NONE); final TableColumn column = new TableColumn(table, SWT.NONE);
final String text = i18nSupport.getText( final String text = i18nSupport.getText(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + columnAttribute.name, ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
columnAttribute.name,
columnAttribute.name); columnAttribute.name);
column.setText(text); column.setText(text);
column.setWidth(100); column.setWidth(100);
@ -159,14 +158,25 @@ public class TableFieldBuilder implements InputFieldBuilder {
return tableField; return tableField;
} }
private void adaptColumnWidth(final Event event) { private void adaptColumnWidth(
final Table table,
final TableContext tableContext) {
try { try {
final Table table = (Table) event.widget;
final int currentTableWidth = table.getClientArea().width - 50; final int currentTableWidth = table.getClientArea().width - 50;
final TableColumn[] columns = table.getColumns(); final TableColumn[] columns = table.getColumns();
final int 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++) { 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) { } catch (final Exception e) {
log.warn("Failed to adaptColumnWidth: ", e); log.warn("Failed to adaptColumnWidth: ", e);
@ -196,6 +206,12 @@ public class TableFieldBuilder implements InputFieldBuilder {
.map(TableValue::of) .map(TableValue::of)
.collect(Collectors.toList()); .collect(Collectors.toList());
initValue(tableValues);
return null;
}
void initValue(final List<TableValue> tableValues) {
final Map<Integer, Map<Long, TableValue>> _initValue = new HashMap<>(); final Map<Integer, Map<Long, TableValue>> _initValue = new HashMap<>();
for (final TableValue tableValue : tableValues) { for (final TableValue tableValue : tableValues) {
final Map<Long, TableValue> rowValues = _initValue.computeIfAbsent( final Map<Long, TableValue> rowValues = _initValue.computeIfAbsent(
@ -215,13 +231,24 @@ public class TableFieldBuilder implements InputFieldBuilder {
this.values.add(rowValues); this.values.add(rowValues);
addTableRow(rowValues); addTableRow(rowValues);
}); });
return null;
} }
private boolean isChildValue(final ConfigurationValue value) { private boolean isChildValue(final ConfigurationValue value) {
return this.attribute.id.equals( if (!this.tableContext.getViewContext().attributeMapping.attributeIdMapping
this.tableContext.getAttribute(value.attributeId).parentId); .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) { private void deleteRow(final int selectionIndex) {
@ -254,22 +281,7 @@ public class TableFieldBuilder implements InputFieldBuilder {
final TableItem tableItem = new TableItem(this.control, SWT.NONE); final TableItem tableItem = new TableItem(this.control, SWT.NONE);
applyTableRowValues(this.values.size() - 1); applyTableRowValues(this.values.size() - 1);
// TODO delete icon is not working on row as expected // TODO try to add delete button within table row?
// 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);
} }
private void applyTableRowValues(final int index) { private void applyTableRowValues(final int index) {
@ -279,7 +291,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
int cellIndex = 0; int cellIndex = 0;
for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) { for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) {
if (rowValues.containsKey(attr.id)) { if (rowValues.containsKey(attr.id)) {
item.setText(cellIndex, rowValues.get(attr.id).value); item.setText(
cellIndex,
this.tableContext.getRowValue(rowValues.get(attr.id)));
} }
cellIndex++; cellIndex++;
} }
@ -299,7 +313,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
this.tableContext.getWidgetFactory()) this.tableContext.getWidgetFactory())
.setDialogWidth(500) .setDialogWidth(500)
.open( .open(
new LocTextKey("Title"), ExamConfigurationService.getTablePopupTitleKey(
this.attribute,
this.tableContext.getViewContext().i18nSupport),
values -> applyFormValues(values, selectionIndex), values -> applyFormValues(values, selectionIndex),
builder); builder);
} }
@ -313,6 +329,9 @@ public class TableFieldBuilder implements InputFieldBuilder {
this.values.remove(index); this.values.remove(index);
this.values.add(index, tableRowValues); this.values.add(index, tableRowValues);
applyTableRowValues(index); applyTableRowValues(index);
// send new values to web-service
this.tableContext.getValueChangeListener()
.tableChanged(extractTableValue());
} }
private ConfigurationTableValues extractTableValue() { private ConfigurationTableValues extractTableValue() {
@ -353,12 +372,13 @@ public class TableFieldBuilder implements InputFieldBuilder {
@Override @Override
protected void setValueToControl(final String value) { protected void setValueToControl(final String value) {
throw new UnsupportedOperationException(); //throw new UnsupportedOperationException();
} }
@Override @Override
public String getValue() { 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.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.TableFieldBuilder.TableInputField;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer; import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; 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 Composite parent,
final ConfigurationAttribute attribute) { final ConfigurationAttribute attribute) {
if (attribute.type == AttributeType.TABLE) { // if (attribute.type == AttributeType.TABLE) {
throw new UnsupportedOperationException( // throw new UnsupportedOperationException(
"Table type is currently not supported within a table row form view!"); // "Table type is currently not supported within a table row form view!");
} // }
final Orientation orientation = this.tableContext final Orientation orientation = this.tableContext
.getOrientation(attribute.id); .getOrientation(attribute.id);
final InputFieldBuilder inputFieldBuilder = this.tableContext final InputFieldBuilder inputFieldBuilder = this.tableContext
.getInputFieldBuilder(attribute, orientation); .getInputFieldBuilder(attribute, orientation);
final InputField inputField = inputFieldBuilder.createInputField( final InputField inputField = inputFieldBuilder.createInputField(
parent, parent,
attribute, attribute,
this.tableContext.getViewContext()); this.tableContext.getViewContext());
inputField.initValue( if (attribute.type == AttributeType.TABLE) {
this.rowValues.get(attribute.id).value, ((TableInputField) inputField).initValue(new ArrayList<>(this.rowValues.values()));
this.listIndex); } 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 // we have to register the input field within the ViewContext to receive error messages
this.tableContext.registerInputField(inputField); this.tableContext.registerInputField(inputField);
@ -108,9 +111,13 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
return inputField; 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( final LocTextKey locTextKey = new LocTextKey(
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name, ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
attribute.name,
attribute.name); attribute.name);
final Label label = this.tableContext final Label label = this.tableContext
.getWidgetFactory() .getWidgetFactory()

View file

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

View file

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

View file

@ -67,6 +67,10 @@ public class ViewGridBuilder {
} }
ViewGridBuilder add(final ConfigurationAttribute attribute) { ViewGridBuilder add(final ConfigurationAttribute attribute) {
if (log.isDebugEnabled()) {
log.debug("Add SEB Configuration Attribute: " + attribute);
}
// ignore nested attributes here // ignore nested attributes here
if (attribute.parentId != null) { if (attribute.parentId != null) {
return this; return this;
@ -115,7 +119,8 @@ public class ViewGridBuilder {
orientation); orientation);
break; break;
} }
case LEFT: { case LEFT:
case LEFT_SPAN: {
this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder( this.grid[ypos][xpos - 1] = CellFieldBuilderAdapter.labelBuilder(
attribute, attribute,
orientation); orientation);
@ -127,17 +132,17 @@ public class ViewGridBuilder {
} }
break; break;
} }
case LEFT_SPAN: { // case LEFT_SPAN: {
int spanxpos = xpos - orientation.width; // int spanxpos = xpos - orientation.width;
if (spanxpos < 0) { // if (spanxpos < 0) {
spanxpos = 0; // spanxpos = 0;
} // }
fillDummy(spanxpos, ypos, orientation.width, 1); // fillDummy(spanxpos, ypos, orientation.width, 1);
this.grid[ypos][spanxpos] = CellFieldBuilderAdapter.labelBuilder( // this.grid[ypos][spanxpos] = CellFieldBuilderAdapter.labelBuilder(
attribute, // attribute,
orientation); // orientation);
break; // break;
} // }
case TOP: { case TOP: {
fillDummy(xpos, ypos - 1, orientation.width, 1); fillDummy(xpos, ypos - 1, orientation.width, 1);
this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder( this.grid[ypos - 1][xpos] = CellFieldBuilderAdapter.labelBuilder(
@ -160,9 +165,11 @@ public class ViewGridBuilder {
log.debug("Compose grid view: \n" + gridToString()); 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 y = 0; y < this.grid.length; y++) {
for (int x = 0; x < this.grid[y].length; x++) { for (int x = 0; x < this.grid[y].length; x++) {
if (this.grid[y][x] != null) { if (this.grid[y][x] != null) {
this.grid[y][x].balanceGrid(this.grid, x, y);
} }
} }
} }
@ -174,7 +181,7 @@ public class ViewGridBuilder {
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
gridData.verticalIndent = 8; gridData.verticalIndent = 8;
empty.setLayoutData(gridData); empty.setLayoutData(gridData);
empty.setText(""); empty.setText("" /* "empty " + x + " " + y */);
} else { } else {
this.grid[y][x].createCell(this); 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(); String getSelectionValue();
default String getSelectionReadableValue() {
return getSelectionValue();
}
void clear(); void clear();
void setVisible(boolean visible); 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.Composite;
import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Tuple;
public final class SingleSelection extends Combo implements Selection { 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); 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 @Override
public void clear() { public void clear() {
super.clearSelection(); super.clearSelection();

View file

@ -56,7 +56,7 @@ public class ExitKeySequenceValidator implements ConfigurationValueValidator {
} }
try { try {
return this.configurationValueRecordMapper.selectByExample() return !this.configurationValueRecordMapper.selectByExample()
.join(ConfigurationAttributeRecordDynamicSqlSupport.configurationAttributeRecord) .join(ConfigurationAttributeRecordDynamicSqlSupport.configurationAttributeRecord)
.on( .on(
ConfigurationAttributeRecordDynamicSqlSupport.id, ConfigurationAttributeRecordDynamicSqlSupport.id,
@ -75,7 +75,7 @@ public class ExitKeySequenceValidator implements ConfigurationValueValidator {
.stream() .stream()
.filter(val -> value.value.equals(val.getValue())) .filter(val -> value.value.equals(val.getValue()))
.findFirst() .findFirst()
.isEmpty(); .isPresent();
} catch (final Exception e) { } catch (final Exception e) {
log.error("unexpected error while trying to validate SEB exam configuration attributes: {}", ATTR_NAMES, e); log.error("unexpected error while trying to validate SEB exam configuration attributes: {}", ATTR_NAMES, e);
return true; 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=Edit
sebserver.examconfig.action.list.modify.properties=Edit Properties sebserver.examconfig.action.list.modify.properties=Edit Properties
sebserver.examconfig.action.modify=Edit sebserver.examconfig.action.modify=Edit
sebserver.examconfig.action.modify.properties=Edit Properties
sebserver.examconfig.action.save=Save sebserver.examconfig.action.save=Save
sebserver.examconfig.form.title.new=New Exam Configuration 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.browser=Browser
sebserver.examconfig.props.form.views.down_upload=Down/Uploads sebserver.examconfig.props.form.views.down_upload=Down/Uploads
sebserver.examconfig.props.form.views.exam=Exam 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=Administrator password
sebserver.examconfig.props.label.hashedAdminPassword.confirm=Confirm 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.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.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.password.confirm=Please enter correct confirm password
sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly