diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java index 6559e536..279c8319 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java @@ -31,6 +31,8 @@ public final class Constants { public static final String FORM_URL_ENCODED_SEPARATOR = "&"; public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = "="; + public static final String PERCENTAGE = "%"; + public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; public static final String DEFAULT_DISPLAY_DATE_FORMAT = "MM-dd-yyy HH:mm"; public static final String TIME_ZONE_OFFSET_TAIL_FORMAT = "|ZZ"; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/EntityType.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/EntityType.java index c35d8470..557919e7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/EntityType.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/EntityType.java @@ -2,7 +2,7 @@ package ch.ethz.seb.sebserver.gbl.api; import javax.annotation.Generated; -@Generated(value="org.mybatis.generator.api.MyBatisGenerator",comments="ch.ethz.seb.sebserver.gen.DomainModelNameReferencePlugin",date="2019-04-30T14:19:48.997+02:00") +@Generated(value="org.mybatis.generator.api.MyBatisGenerator",comments="ch.ethz.seb.sebserver.gen.DomainModelNameReferencePlugin",date="2019-05-13T14:59:57.056+02:00") public enum EntityType { CONFIGURATION_ATTRIBUTE, CONFIGURATION_VALUE, diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/async/AsyncService.java b/src/main/java/ch/ethz/seb/sebserver/gbl/async/AsyncService.java index 1d2b2b24..87632603 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/async/AsyncService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/async/AsyncService.java @@ -10,8 +10,6 @@ package ch.ethz.seb.sebserver.gbl.async; import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -19,8 +17,6 @@ import org.springframework.stereotype.Service; @Service public class AsyncService { - private static final Logger log = LoggerFactory.getLogger(AsyncService.class); - private final AsyncRunner asyncRunner; protected AsyncService(final AsyncRunner asyncRunner) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Domain.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Domain.java index 99b97513..e4c24736 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Domain.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Domain.java @@ -5,7 +5,7 @@ import javax.annotation.Generated; /** Defines the global names of the domain model and domain model fields. * This shall be used as a static overall domain model names reference within SEB Server Web-Service as well as within the integrated GUI * This file is generated by the org.eth.demo.sebserver.gen.DomainModelNameReferencePlugin and must not be edited manually.**/ -@Generated(value="org.mybatis.generator.api.MyBatisGenerator",comments="ch.ethz.seb.sebserver.gen.DomainModelNameReferencePlugin",date="2019-04-30T14:19:48.912+02:00") +@Generated(value="org.mybatis.generator.api.MyBatisGenerator",comments="ch.ethz.seb.sebserver.gen.DomainModelNameReferencePlugin",date="2019-05-13T14:59:57.013+02:00") public interface Domain { interface CONFIGURATION_ATTRIBUTE { @@ -38,6 +38,7 @@ public interface Domain { String REFERENCE_NAME = "views"; String ATTR_ID = "id"; String ATTR_NAME = "name"; + String ATTR_COLUMNS = "columns"; String ATTR_POSITION = "position"; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/AttributeType.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/AttributeType.java index c8032071..3f687af1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/AttributeType.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/AttributeType.java @@ -23,8 +23,8 @@ public enum AttributeType { TEXT_AREA(TEXT), /** Check Box or boolean type */ CHECKBOX(TEXT), - /** Check Box or boolean type without label (e.g.: used in a table) */ - CHECK_FIELD(TEXT), + + SLIDER(TEXT), /** Integer number type */ INTEGER(TEXT), @@ -32,10 +32,14 @@ public enum AttributeType { DECIMAL(TEXT), /** Single selection type (Drop-down) */ SINGLE_SELECTION(TEXT), - /** Multiple selection type */ - MULTI_SELECTION(LIST), + + COMBO_SELECTION(TEXT), /** Radio selection type (like single selection but with check-boxes) */ RADIO_SELECTION(TEXT), + /** Multiple selection type */ + MULTI_SELECTION(LIST), + /** Multiple selection with checkbox type */ + MULTI_CHECKBOX_SELECTION(LIST), FILE_UPLOAD(BASE64_BINARY), diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/ConfigurationAttribute.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/ConfigurationAttribute.java index 71997f45..4ccbb267 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/ConfigurationAttribute.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/ConfigurationAttribute.java @@ -24,6 +24,8 @@ import ch.ethz.seb.sebserver.gbl.model.Entity; @JsonIgnoreProperties(ignoreUnknown = true) public final class ConfigurationAttribute implements Entity { + public static final String DEPENDENCY_RESOURCE_LOC_TEXT_KEY = "resourceLocTextKey"; + public static final String FILTER_ATTR_PARENT_ID = "parentId"; public static final String FILTER_ATTR_TYPE = "type"; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TitleOrientation.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TitleOrientation.java index e4b33088..e1d77b98 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TitleOrientation.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/TitleOrientation.java @@ -1,6 +1,6 @@ /* * 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/. @@ -11,6 +11,8 @@ package ch.ethz.seb.sebserver.gbl.model.sebconfig; public enum TitleOrientation { NONE, LEFT, + LEFT_SPAN, RIGHT, + RIGHT_SPAN, TOP } \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java index 322f0014..e2d25742 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/View.java @@ -28,6 +28,10 @@ public class View implements Entity { @JsonProperty(VIEW.ATTR_NAME) public final String name; + @NotNull + @JsonProperty(VIEW.ATTR_COLUMNS) + public final Integer columns; + @NotNull @JsonProperty(VIEW.ATTR_POSITION) public final Integer position; @@ -35,16 +39,19 @@ public class View implements Entity { public View( @JsonProperty(VIEW.ATTR_ID) final Long id, @JsonProperty(VIEW.ATTR_NAME) final String name, + @JsonProperty(VIEW.ATTR_COLUMNS) final Integer columns, @JsonProperty(VIEW.ATTR_POSITION) final Integer position) { this.id = id; this.name = name; + this.columns = columns; this.position = position; } public View(final POSTMapper postParams) { this.id = null; this.name = postParams.getString(Domain.VIEW.ATTR_NAME); + this.columns = postParams.getInteger(Domain.VIEW.ATTR_COLUMNS); this.position = postParams.getInteger(Domain.VIEW.ATTR_POSITION); } @@ -52,6 +59,10 @@ public class View implements Entity { return this.position; } + public Integer getColumns() { + return this.columns; + } + public Long getId() { return this.id; } @@ -75,15 +86,8 @@ public class View implements Entity { @Override public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("View [id="); - builder.append(this.id); - builder.append(", name="); - builder.append(this.name); - builder.append(", position="); - builder.append(this.position); - builder.append("]"); - return builder.toString(); + return "View [id=" + this.id + ", name=" + this.name + ", columns=" + this.columns + ", position=" + + this.position + "]"; } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java index efe9b465..4e3f0ae2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java @@ -34,6 +34,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; public final class Utils { @@ -293,4 +294,22 @@ public final class Utils { return toCharArray(CharBuffer.wrap(chars)); } + public static Map getAttributeDependencyMap(final ConfigurationAttribute attribute) { + if (StringUtils.isBlank(attribute.dependencies)) { + return Collections.emptyMap(); + } + + try { + return Arrays.asList(StringUtils.split(attribute.dependencies, Constants.LIST_SEPARATOR)) + .stream() + .map(s -> StringUtils.split(s, Constants.EMBEDDED_LIST_SEPARATOR)) + .collect(Collectors.toMap(pair -> pair[0], pair -> pair[1])); + } catch (final Exception e) { + log.error("Unexpected error while trying to parse dependency map of ConfigurationAttribute: {}", + attribute, + e); + return Collections.emptyMap(); + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropertiesForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropertiesForm.java index 8d141037..f4350aab 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropertiesForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropertiesForm.java @@ -16,6 +16,8 @@ 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; @@ -45,8 +47,10 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @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_PREFIX = "tooltip"; + private static final String VIEW_TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip"; private static final LocTextKey TITLE_TEXT_KEY = new LocTextKey("sebserver.examconfig.props.from.title"); @@ -75,58 +79,63 @@ public class SebExamConfigPropertiesForm implements TemplateComposer { final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey parentEntityKey = pageContext.getParentEntityKey(); - 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 Composite content = widgetFactory.defaultPageLayout( pageContext.getParent(), TITLE_TEXT_KEY); - final AttributeMapping attributes = this.examConfigurationService - .getAttributes(configNode.templateId) - .onError(pageContext::notifyError) - .getOrThrow(); + try { - final List views = this.examConfigurationService.getViews(attributes); + final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class) + .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) + .call() + .onError(pageContext::notifyError) + .getOrThrow(); - final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content); - tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + 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 List viewContexts = new ArrayList<>(); - for (final View view : views) { - final ViewContext viewContext = this.examConfigurationService.createViewContext( - pageContext, - configuration, - view, - attributes, - 4, - 20); - viewContexts.add(viewContext); + final AttributeMapping attributes = this.examConfigurationService + .getAttributes(configNode.templateId) + .onError(pageContext::notifyError) + .getOrThrow(); - final Composite viewGrid = this.examConfigurationService.createViewGrid( - tabFolder, - viewContext); + final List views = this.examConfigurationService.getViews(attributes); - final TabItem tabItem = widgetFactory.tabItemLocalized( - tabFolder, - new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name), - new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name + VIEW_TOOLTIP_TEXT_KEY_PREFIX)); - tabItem.setControl(viewGrid); + final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content); + tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + final List 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); } - this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts); - } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java index 1f662239..4ffdf43e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ExamConfigurationService.java @@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.examconfig; import java.util.Collection; import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.widgets.Composite; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; @@ -20,6 +21,8 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; +import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -27,6 +30,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"; WidgetFactory getWidgetFactory(); @@ -43,7 +47,6 @@ public interface ExamConfigurationService { Configuration configuration, View view, AttributeMapping attributeMapping, - int columns, int rows); Composite createViewGrid( @@ -54,4 +57,32 @@ public interface ExamConfigurationService { Long configurationId, Collection viewContexts); + static String attributeNameKey(final ConfigurationAttribute attribute) { + if (attribute == null) { + return null; + } + + return ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name; + } + + static LocTextKey attributeNameLocKey(final ConfigurationAttribute attribute) { + if (attribute == null) { + return null; + } + + return new LocTextKey(attributeNameKey(attribute)); + } + + static LocTextKey getToolTipKey( + final ConfigurationAttribute attribute, + final I18nSupport i18nSupport) { + + final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute) + TOOL_TIP_SUFFIX; + if (StringUtils.isBlank(i18nSupport.getText(attributeNameKey, ""))) { + return null; + } else { + return new LocTextKey(attributeNameKey); + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputField.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputField.java index dac89599..994adae9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputField.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputField.java @@ -21,7 +21,7 @@ public interface InputField { Orientation getOrientation(); - void initValue(Collection values); + ConfigurationValue initValue(Collection values); void initValue(final String value, final Integer listIndex); @@ -31,8 +31,10 @@ public interface InputField { void clearError(); - void disable(); + void disable(boolean group); - void enable(); + void enable(boolean group); + + void setDefaultValue(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputFieldBuilder.java index f672847a..e9a5421f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/InputFieldBuilder.java @@ -62,6 +62,8 @@ public interface InputFieldBuilder { final GridLayout gridLayout = new GridLayout(numColumns, true); gridLayout.verticalSpacing = 0; gridLayout.marginHeight = 1; + gridLayout.marginWidth = 0; + gridLayout.marginRight = 5; comp.setLayout(gridLayout); final GridData gridData = new GridData( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ValueChangeListener.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ValueChangeListener.java index 155806f2..eda7afee 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ValueChangeListener.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/ValueChangeListener.java @@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.gui.service.examconfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; public interface ValueChangeListener { @@ -22,4 +23,9 @@ public interface ValueChangeListener { void tableChanged(ConfigurationTableValues tableValue); + void notifyGUI( + ViewContext viewContext, + ConfigurationAttribute attribute, + ConfigurationValue initValue); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractInputField.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractInputField.java index c2d51700..d4adaee1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractInputField.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AbstractInputField.java @@ -10,8 +10,12 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl; import java.util.Collection; +import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; @@ -20,6 +24,8 @@ import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; public abstract class AbstractInputField implements InputField { + private static final Logger log = LoggerFactory.getLogger(AbstractInputField.class); + protected final ConfigurationAttribute attribute; protected final Orientation orientation; protected final T control; @@ -46,17 +52,25 @@ public abstract class AbstractInputField implements InputFiel } @Override - public void disable() { + public void disable(final boolean group) { if (this.control.isEnabled()) { - setDefaultValue(); - this.control.setEnabled(false); + if (group) { + this.control.getParent().getParent().setEnabled(false); + } else { + setDefaultValue(); + this.control.setEnabled(false); + } } } @Override - public void enable() { + public void enable(final boolean group) { if (!this.control.isEnabled()) { - this.control.setEnabled(true); + if (group) { + this.control.getParent().getParent().setEnabled(true); + } else { + this.control.setEnabled(true); + } } } @@ -86,11 +100,15 @@ public abstract class AbstractInputField implements InputFiel } @Override - public void initValue(final Collection values) { - values.stream() + public ConfigurationValue initValue(final Collection values) { + return values.stream() .filter(a -> this.attribute.id.equals(a.attributeId)) .findFirst() - .ifPresent(v -> initValue(v.value, v.listIndex)); + .map(v -> { + initValue(v.value, v.listIndex); + return v; + }) + .orElse(null); } @Override @@ -100,8 +118,16 @@ public abstract class AbstractInputField implements InputFiel setValueToControl(this.initValue); } - protected void setDefaultValue() { + @Override + public void setDefaultValue() { setValueToControl(this.attribute.defaultValue); + final Event event = new Event(); + try { + this.control.notifyListeners(SWT.Selection, event); + this.control.notifyListeners(SWT.FocusOut, event); + } catch (final Exception e) { + log.warn("Failed to send value update to server: {}", this.attribute, e); + } } protected abstract void setValueToControl(String value); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AttributeMapping.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AttributeMapping.java index 65985da9..e4b5ef05 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AttributeMapping.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/AttributeMapping.java @@ -77,6 +77,7 @@ public class AttributeMapping { this.attributeGroupMapping = Utils.immutableMapOf(orientations .stream() + .filter(o -> o.groupId != null) .map(o -> o.groupId) .collect(Collectors.toSet()) .stream() @@ -176,6 +177,9 @@ public class AttributeMapping { } private List getAttributesOfGroup(final String groupName) { + if (groupName == null) { + return Collections.emptyList(); + } return this.orientationAttributeMapping .values() .stream() diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java new file mode 100644 index 00000000..cb3718e9 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CellFieldBuilderAdapter.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.examconfig.impl; + +import java.util.Collection; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; + +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; +import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; +import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; +import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; + +interface CellFieldBuilderAdapter { + + void createCell(ViewGridBuilder builder); + + static CellFieldBuilderAdapter dummyBuilderAdapter() { + return new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + } + + @Override + public String toString() { + return "[DUMMY]"; + } + }; + } + + static CellFieldBuilderAdapter fieldBuilderAdapter( + final InputFieldBuilder inputFieldBuilder, + final ConfigurationAttribute attribute) { + + return new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + + final InputField inputField = inputFieldBuilder.createInputField( + builder.parent, + attribute, + builder.viewContext); + + if (inputField != null) { + builder.viewContext.registerInputField(inputField); + } + } + + @Override + public String toString() { + return "[FIELD]"; + } + }; + } + + static CellFieldBuilderAdapter labelBuilder( + final ConfigurationAttribute attribute, + final Orientation orientation) { + + return new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + + final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); + final Label label = widgetFactory.labelLocalized( + builder.parent, + new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name, + attribute.name)); + + final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); + switch (orientation.title) { + case LEFT: + case RIGHT: { + label.setAlignment(SWT.LEFT); + gridData.verticalIndent = 5; + break; + } + case LEFT_SPAN: + 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); + break; + } + + default: { + label.setAlignment(SWT.LEFT); + } + } + label.setLayoutData(gridData); + label.pack(); + } + + @Override + public String toString() { + return "[LABEL]"; + } + }; + } + + static CellFieldBuilderAdapter passwordConfirmLabel( + final ConfigurationAttribute attribute, + final Orientation orientation) { + + return new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); + final Label label = widgetFactory.labelLocalized( + builder.parent, + new LocTextKey( + ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + + ".confirm")); + final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false); + label.setAlignment(SWT.LEFT); + gridData.verticalIndent = 20; + label.setLayoutData(gridData); + //label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key); + } + + @Override + public String toString() { + return "[PASSWORD CONFIRM LABEL]"; + } + }; + } + + static class GroupCellFieldBuilderAdapter implements CellFieldBuilderAdapter { + + final Collection orientationsOfGroup; + + int x = 100; + int y = 100; + int width = 1; + int height = 1; + + GroupCellFieldBuilderAdapter(final Collection orientationsOfGroup) { + this.orientationsOfGroup = orientationsOfGroup; + + for (final Orientation o : this.orientationsOfGroup) { + final int xpos = o.xPosition - ((o.title == TitleOrientation.LEFT) ? 1 : 0); + this.x = (xpos < this.x) ? xpos : this.x; + final int ypos = o.yPosition - ((o.title == TitleOrientation.TOP) ? 1 : 0); + this.y = (ypos < this.y) ? ypos : this.y; + this.width = (this.width < o.xpos() + o.width()) ? o.xpos() + o.width() : this.width; + this.height = (this.height < o.ypos() + o.height()) ? o.ypos() + o.height() : this.height; + } + + this.width = this.width - this.x; + this.height = this.height - this.y + 1; + } + + @Override + public void createCell(final ViewGridBuilder builder) { + final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); + final Orientation o = this.orientationsOfGroup.stream().findFirst().get(); + final LocTextKey groupLabelKey = new LocTextKey( + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + o.groupId, + o.groupId); + + final Group group = widgetFactory.groupLocalized( + builder.parent, + this.width, + groupLabelKey); + group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, this.width, this.height)); + + final ViewGridBuilder groupBuilder = new ViewGridBuilder( + group, + builder.viewContext, + this, + builder.examConfigurationService); + + for (final Orientation orientation : this.orientationsOfGroup) { + final ConfigurationAttribute attribute = builder.viewContext.getAttribute(orientation.attributeId); + groupBuilder.add(attribute); + } + groupBuilder.compose(); + } + } +} \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java index 2ef55fcd..8da9807a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/CheckBoxBuilder.java @@ -21,14 +21,23 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; +import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @Lazy @Component @GuiProfile public class CheckBoxBuilder implements InputFieldBuilder { + private final WidgetFactory widgetFactory; + + protected CheckBoxBuilder(final WidgetFactory widgetFactory) { + this.widgetFactory = widgetFactory; + } + @Override public boolean builderFor( final ConfigurationAttribute attribute, @@ -38,8 +47,7 @@ public class CheckBoxBuilder implements InputFieldBuilder { return false; } - return attribute.type == AttributeType.CHECK_FIELD || - attribute.type == AttributeType.CHECKBOX; + return attribute.type == AttributeType.CHECKBOX; } @Override @@ -52,23 +60,32 @@ public class CheckBoxBuilder implements InputFieldBuilder { Objects.requireNonNull(attribute); Objects.requireNonNull(viewContext); - final Button checkbox = new Button(parent, SWT.CHECK); - if (attribute.type == AttributeType.CHECKBOX) { - checkbox.setText(attribute.name); - } + final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); + final Orientation orientation = viewContext + .getOrientation(attribute.id); + final Composite innerGrid = InputFieldBuilder + .createInnerGrid(parent, orientation); + + final Button checkbox = this.widgetFactory.buttonLocalized( + innerGrid, + SWT.CHECK, + ExamConfigurationService.attributeNameLocKey(attribute), + ExamConfigurationService.getToolTipKey(attribute, i18nSupport)); + + final CheckboxField checkboxField = new CheckboxField( + attribute, + viewContext.getOrientation(attribute.id), + checkbox); checkbox.addListener( SWT.Selection, event -> viewContext.getValueChangeListener().valueChanged( viewContext, attribute, - String.valueOf(checkbox.getSelection()), - 0)); + checkboxField.getValue(), + checkboxField.listIndex)); - return new CheckboxField( - attribute, - viewContext.getOrientation(attribute.id), - checkbox); + return checkboxField; } static final class CheckboxField extends AbstractInputField