diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java index f72ddeb6..1299134d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java @@ -67,6 +67,7 @@ public final class API { public static final String CONFIGURATION_FOLLOWUP_PATH_SEGMENT = "/followup"; public static final String CONFIGURATION_ENDPOINT = "/configuration"; public static final String CONFIGURATION_SAVE_TO_HISTORY_PATH_SEGMENT = "/save_to_history"; + public static final String CONFIGURATION_UNDO_PATH_SEGMENT = "/undo"; public static final String CONFIGURATION_RESTORE_FROM_HISTORY_PATH_SEGMENT = "/restore"; public static final String CONFIGURATION_VALUE_ENDPOINT = "/configuration_value"; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigForm.java index 65f0b04f..40491be2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigForm.java @@ -23,12 +23,14 @@ 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.EntityType; 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.content.action.ActionDefinition; 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; @@ -39,7 +41,10 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SebExamConfigUndo; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @Lazy @@ -50,7 +55,10 @@ public class SebExamConfigForm implements TemplateComposer { private static final Logger log = LoggerFactory.getLogger(SebExamConfigForm.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 String KEY_SAVE_TO_HISTORY_SUCCESS = + "sebserver.examconfig.action.saveToHistory.success"; + private static final String KEY_UNDO_SUCCESS = + "sebserver.examconfig.action.undo.success"; private static final LocTextKey TITLE_TEXT_KEY = new LocTextKey("sebserver.examconfig.props.from.title"); @@ -77,7 +85,6 @@ public class SebExamConfigForm implements TemplateComposer { final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final EntityKey entityKey = pageContext.getEntityKey(); - final EntityKey parentEntityKey = pageContext.getParentEntityKey(); final Composite content = widgetFactory.defaultPageLayout( pageContext.getParent(), @@ -131,6 +138,36 @@ public class SebExamConfigForm implements TemplateComposer { this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts); + final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE); + this.pageService.pageActionBuilder(pageContext.clearEntityKeys()) + .newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE_TO_HISTORY) + .withEntityKey(entityKey) + .withExec(action -> { + this.restService.getBuilder(SaveExamConfigHistory.class) + .withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId()) + .call() + .onError(pageContext::notifyError) + .getOrThrow(); + return action; + }) + .withSuccess(KEY_SAVE_TO_HISTORY_SUCCESS) + .publishIf(() -> examConfigGrant.iw()) + + .newAction(ActionDefinition.SEB_EXAM_CONFIG_UNDO) + .withEntityKey(entityKey) + .withExec(action -> { + this.restService.getBuilder(SebExamConfigUndo.class) + .withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId()) + .call() + .onError(pageContext::notifyError) + .getOrThrow(); + return action; + }) + .withSuccess(KEY_UNDO_SUCCESS) + .publishIf(() -> examConfigGrant.iw()) + + ; + } catch (final Exception e) { log.error("Unexpected error while trying to fetch exam configuration data and create views", e); pageContext.notifyError(e); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index 7a958e9e..963b8d51 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -345,6 +345,17 @@ public enum ActionDefinition { PageStateDefinition.SEB_EXAM_CONFIG_EDIT, ActionCategory.SEB_EXAM_CONFIG_LIST), + SEB_EXAM_CONFIG_SAVE_TO_HISTORY( + new LocTextKey("sebserver.examconfig.action.saveToHistory"), + ImageIcon.SAVE, + PageStateDefinition.SEB_EXAM_CONFIG_EDIT, + ActionCategory.SEB_EXAM_CONFIG_LIST), + SEB_EXAM_CONFIG_UNDO( + new LocTextKey("sebserver.examconfig.action.undo"), + ImageIcon.SAVE, + PageStateDefinition.SEB_EXAM_CONFIG_EDIT, + ActionCategory.SEB_EXAM_CONFIG_LIST), + ; public final LocTextKey title; 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 index a8f15e56..426c3627 100644 --- 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 @@ -8,8 +8,6 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl; -import static ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.dummyBuilderAdapter; - import java.util.Collection; import org.eclipse.swt.SWT; @@ -28,23 +26,20 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; interface CellFieldBuilderAdapter { + static CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() { + @Override + public void createCell(final ViewGridBuilder builder) { + } + + @Override + public String toString() { + return "[DUMMY]"; + } + }; + void createCell(ViewGridBuilder builder); default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { - - } - - static CellFieldBuilderAdapter dummyBuilderAdapter() { - return new CellFieldBuilderAdapter() { - @Override - public void createCell(final ViewGridBuilder builder) { - } - - @Override - public String toString() { - return "[DUMMY]"; - } - }; } static CellFieldBuilderAdapter fieldBuilderAdapter( @@ -127,7 +122,7 @@ interface CellFieldBuilderAdapter { int xpos = x - 1; while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) { grid[y][xpos] = this; - grid[y][xpos + 1] = dummyBuilderAdapter(); + grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER; this.span++; xpos--; } @@ -198,13 +193,20 @@ interface CellFieldBuilderAdapter { 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, + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + + o.groupId, + o.groupId); + final LocTextKey groupTooltipKey = new LocTextKey( + ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + + o.groupId + + ExamConfigurationService.TOOL_TIP_SUFFIX, o.groupId); final Group group = widgetFactory.groupLocalized( builder.parent, this.width, - groupLabelKey); + groupLabelKey, + groupTooltipKey); group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, this.width, this.height)); final ViewGridBuilder groupBuilder = new ViewGridBuilder( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/MultiCheckboxSelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/MultiCheckboxSelection.java index 873f05ee..e4ee274e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/MultiCheckboxSelection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/MultiCheckboxSelection.java @@ -20,7 +20,6 @@ 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.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.MultiSelectionCheckbox; import ch.ethz.seb.sebserver.gui.widget.Selection; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -50,7 +49,6 @@ public class MultiCheckboxSelection extends SelectionFieldBuilder implements Inp final ConfigurationAttribute attribute, final ViewContext viewContext) { - final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); final Orientation orientation = viewContext .getOrientation(attribute.id); final Composite innerGrid = InputFieldBuilder diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/RadioSelectionFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/RadioSelectionFieldBuilder.java index 2b342858..9659a9dd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/RadioSelectionFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/RadioSelectionFieldBuilder.java @@ -21,7 +21,6 @@ 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.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.RadioSelection; import ch.ethz.seb.sebserver.gui.widget.Selection; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -52,7 +51,6 @@ public class RadioSelectionFieldBuilder extends SelectionFieldBuilder implements final ConfigurationAttribute attribute, final ViewContext viewContext) { - final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); final Orientation orientation = viewContext .getOrientation(attribute.id); final Composite innerGrid = InputFieldBuilder diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableContext.java index 17758443..099e2985 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableContext.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableContext.java @@ -24,6 +24,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gui.service.ResourceService; 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; @@ -191,12 +192,10 @@ public class TableContext { switch (attribute.type) { case CHECKBOX: { return BooleanUtils.toBoolean(tableValue.value) - ? "Active" - : "Inactive"; + ? this.viewContext.i18nSupport.getText(ResourceService.ACTIVE_TEXT_KEY) + : this.viewContext.i18nSupport.getText(ResourceService.INACTIVE_TEXT_KEY); } 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; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java index 64c49a6e..192723ae 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableFieldBuilder.java @@ -278,7 +278,7 @@ public class TableFieldBuilder implements InputFieldBuilder { } private void addTableRow(final Map rowValues) { - final TableItem tableItem = new TableItem(this.control, SWT.NONE); + new TableItem(this.control, SWT.NONE); applyTableRowValues(this.values.size() - 1); // TODO try to add delete button within table row? diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableRowFormBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableRowFormBuilder.java index 8341180a..347cd3da 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableRowFormBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/examconfig/impl/TableRowFormBuilder.java @@ -83,10 +83,10 @@ public class TableRowFormBuilder implements ModalInputDialogComposer= this.grid.length || _x >= this.grid[_y].length) { + log.warn("Out of bounds: {} {}", _x, _y); + continue; + } + this.grid[_y][_x] = CellFieldBuilderAdapter.DUMMY_BUILDER_ADAPTER; } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java index 51330c85..9ca1e046 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/I18nSupport.java @@ -41,6 +41,15 @@ public interface I18nSupport { * @return date/time column title suffix for current user */ String getUsersTimeZoneTitleSuffix(); + /** Get localized text of specified key for currently set Locale. + * + * @param key LocTextKey instance + * @param def default text + * @return the text in current language parsed from localized text */ + default String getText(final LocTextKey key, final String def) { + return getText(key.name, def, key.args); + } + /** Get localized text of specified key for currently set Locale. * * @param key LocTextKey instance diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java index ddd7775c..119c32fc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java @@ -31,6 +31,8 @@ public final class PageAction { private static final Logger log = LoggerFactory.getLogger(PageAction.class); + public static final LocTextKey SUCCESS_MSG_TITLE = new LocTextKey("sebserver.page.message"); + public final ActionDefinition definition; private final Supplier confirm; final LocTextKey successMessage; @@ -126,7 +128,11 @@ public final class PageAction { private Result exec() { try { - return Result.of(this.exec.apply(this)); + final PageAction apply = this.exec.apply(this); + if (this.successMessage != null) { + apply.pageContext.publishPageMessage(SUCCESS_MSG_TITLE, this.successMessage); + } + return Result.of(apply); } catch (final PageMessageException pme) { PageAction.this.pageContext.publishPageMessage(pme); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/SaveExamConfigHistory.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/SaveExamConfigHistory.java new file mode 100644 index 00000000..185aa321 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/SaveExamConfigHistory.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class SaveExamConfigHistory extends RestCall { + + protected SaveExamConfigHistory() { + super(new TypeKey<>( + CallType.SAVE, + EntityType.CONFIGURATION, + new TypeReference() { + }), + HttpMethod.POST, + MediaType.APPLICATION_FORM_URLENCODED, + API.CONFIGURATION_ENDPOINT + + API.CONFIGURATION_SAVE_TO_HISTORY_PATH_SEGMENT + + API.MODEL_ID_VAR_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/SebExamConfigUndo.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/SebExamConfigUndo.java new file mode 100644 index 00000000..a5c4979b --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/examconfig/SebExamConfigUndo.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class SebExamConfigUndo extends RestCall { + + protected SebExamConfigUndo() { + super(new TypeKey<>( + CallType.SAVE, + EntityType.CONFIGURATION, + new TypeReference() { + }), + HttpMethod.POST, + MediaType.APPLICATION_FORM_URLENCODED, + API.CONFIGURATION_ENDPOINT + + API.CONFIGURATION_UNDO_PATH_SEGMENT + + API.MODEL_ID_VAR_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java index 95586b99..ed43eb11 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java @@ -60,7 +60,6 @@ public class EntityTable { final I18nSupport i18nSupport; final List> columns; - final List actions; final LocTextKey emptyMessage; final Composite composite; @@ -82,7 +81,6 @@ public class EntityTable { final Function>.RestCallBuilder, RestCall>.RestCallBuilder> restCallAdapter, final PageService pageService, final List> columns, - final List actions, final int pageSize, final LocTextKey emptyMessage, final Function, PageAction> defaultActionFunction, @@ -95,7 +93,6 @@ public class EntityTable { this.restCall = restCall; this.restCallAdapter = (restCallAdapter != null) ? restCallAdapter : Function.identity(); this.columns = Utils.immutableListOf(columns); - this.actions = Utils.immutableListOf(actions); this.emptyMessage = emptyMessage; this.hideNavigation = hideNavigation; @@ -324,9 +321,6 @@ public class EntityTable { setValueToCell(item, index, column.valueSupplier.apply(row)); index++; } - if (this.actions != null) { - // TODO?? - } } return page; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java index 4b42e884..27b9bd41 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java @@ -29,13 +29,12 @@ public class TableBuilder { private final PageService pageService; final RestCall> restCall; final List> columns = new ArrayList<>(); - final List actions = new ArrayList<>(); LocTextKey emptyMessage; private Function, PageAction> defaultActionFunction; private int pageSize = -1; private int type = SWT.NONE; private boolean hideNavigation = false; - private Function>.RestCallBuilder, RestCall>.RestCallBuilder> restCallAdapter;; + private Function>.RestCallBuilder, RestCall>.RestCallBuilder> restCallAdapter; public TableBuilder( final PageService pageService, @@ -75,11 +74,6 @@ public class TableBuilder { return this; } - public TableBuilder withAction(final TableRowAction action) { - this.actions.add(action); - return this; - } - public TableBuilder withRestCallAdapter( final Function>.RestCallBuilder, RestCall>.RestCallBuilder> adapter) { this.restCallAdapter = adapter; @@ -120,7 +114,6 @@ public class TableBuilder { this.restCallAdapter, this.pageService, this.columns, - this.actions, this.pageSize, this.emptyMessage, this.defaultActionFunction, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableRowAction.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableRowAction.java deleted file mode 100644 index af86b255..00000000 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableRowAction.java +++ /dev/null @@ -1,13 +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.table; - -public class TableRowAction { - -} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java index 275473b6..0c77e755 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java @@ -17,6 +17,7 @@ import java.util.Locale; import java.util.function.Consumer; import java.util.function.Supplier; +import org.apache.commons.lang3.StringUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Device; @@ -309,6 +310,15 @@ public class WidgetFactory { final int columns, final LocTextKey locTextKey) { + return groupLocalized(parent, columns, locTextKey, null); + } + + public Group groupLocalized( + final Composite parent, + final int columns, + final LocTextKey locTextKey, + final LocTextKey locTooltipKey) { + final Group group = new Group(parent, SWT.NONE); final GridLayout gridLayout = new GridLayout(columns, true); gridLayout.verticalSpacing = 0; @@ -316,7 +326,7 @@ public class WidgetFactory { gridLayout.marginHeight = 0; group.setLayout(gridLayout); - this.injectI18n(group, locTextKey); + this.injectI18n(group, locTextKey, locTooltipKey); return group; } @@ -521,8 +531,8 @@ public class WidgetFactory { labelFunction.accept(label); } - public void injectI18n(final Group group, final LocTextKey locTextKey) { - final Consumer groupFunction = groupFunction(locTextKey, null, this.i18nSupport); + public void injectI18n(final Group group, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { + final Consumer groupFunction = groupFunction(locTextKey, locTooltipKey, this.i18nSupport); group.setData(POLYGLOT_WIDGET_FUNCTION_KEY, groupFunction); groupFunction.accept(group); } @@ -656,7 +666,7 @@ public class WidgetFactory { group.setText(i18nSupport.getText(locTextKey)); } if (locToolTipKey != null) { - group.setToolTipText(i18nSupport.getText(locToolTipKey)); + group.setToolTipText(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY)); } }; } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationDAO.java index e4574ab5..83367c88 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ConfigurationDAO.java @@ -42,6 +42,8 @@ public interface ConfigurationDAO extends EntityDAO saveToHistory(Long configurationNodeId); + Result undo(Long configurationNodeId); + /** Restores the current follow-up Configuration to the values of a given Configuration * in the history of the specified ConfigurationNode. * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationDAOImpl.java index 0fed03e1..88a9edd6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ConfigurationDAOImpl.java @@ -165,18 +165,7 @@ public class ConfigurationDAOImpl implements ConfigurationDAO { return Result.tryCatch(() -> { // get follow-up configuration... - final ConfigurationRecord followupConfig = this.configurationRecordMapper - .selectByExample() - .where( - ConfigurationRecordDynamicSqlSupport.configurationNodeId, - isEqualTo(configurationNodeId)) - .and( - ConfigurationRecordDynamicSqlSupport.followup, - isEqualTo(BooleanUtils.toInteger(true))) - .build() - .execute() - .stream() - .collect(Utils.toSingleton()); + final ConfigurationRecord followupConfig = getFollowupConfigurationRecord(configurationNodeId); // with actual attribute values final List allValues = this.configurationValueRecordMapper @@ -239,6 +228,41 @@ public class ConfigurationDAOImpl implements ConfigurationDAO { .onError(TransactionHandler::rollback); } + private ConfigurationRecord getFollowupConfigurationRecord(final Long configurationNodeId) { + return this.configurationRecordMapper + .selectByExample() + .where( + ConfigurationRecordDynamicSqlSupport.configurationNodeId, + isEqualTo(configurationNodeId)) + .and( + ConfigurationRecordDynamicSqlSupport.followup, + isEqualTo(BooleanUtils.toInteger(true))) + .build() + .execute() + .stream() + .collect(Utils.toSingleton()); + } + + @Override + @Transactional + public Result undo(final Long configurationNodeId) { + return Result.tryCatch(() -> { + // get all configurations of the node + final List configs = this.configurationRecordMapper + .selectByExample() + .where( + ConfigurationRecordDynamicSqlSupport.configurationNodeId, + isEqualTo(configurationNodeId)) + .orderBy(ConfigurationRecordDynamicSqlSupport.versionDate) + .build() + .execute(); + + return configs.get(configs.size() - 1); + }) + .flatMap(rec -> restoreToVersion(configurationNodeId, rec.getId())) + .onError(TransactionHandler::rollback); + } + @Override @Transactional public Result restoreToVersion(final Long configurationNodeId, final Long configId) { @@ -268,28 +292,17 @@ public class ConfigurationDAOImpl implements ConfigurationDAO { .execute(); // get follow-up configuration id - final ConfigurationRecord followup = this.configurationRecordMapper - .selectByExample() - .where( - ConfigurationRecordDynamicSqlSupport.configurationNodeId, - isEqualTo(configurationNodeId)) - .and( - ConfigurationRecordDynamicSqlSupport.followup, - isEqualTo(BooleanUtils.toInteger(true))) - .build() - .execute() - .stream() - .collect(Utils.toSingleton()); + final ConfigurationRecord followup = getFollowupConfigurationRecord(configurationNodeId); // restore all current values of the follow-up with historic values // TODO batch here for better performance historicValues.stream() .map(historicValRec -> new ConfigurationValueRecord( null, - null, - null, + followup.getInstitutionId(), + followup.getId(), historicValRec.getConfigurationAttributeId(), - null, + historicValRec.getListIndex(), historicValRec.getValue(), historicValRec.getText())) .forEach(newValRec -> this.configurationValueRecordMapper diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SebExamConfigService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SebExamConfigService.java index f1b5a342..5fcaefd0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SebExamConfigService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SebExamConfigService.java @@ -8,6 +8,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig; +import java.io.OutputStream; + import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; @@ -17,4 +19,8 @@ public interface SebExamConfigService { void validate(ConfigurationTableValues tableValue); + void exportXML(OutputStream out, Long configurationNodeId); + + void exportForExam(OutputStream out, Long configExamMappingId); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/XMLValueConverter.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/XMLValueConverter.java new file mode 100644 index 00000000..abdb18df --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/XMLValueConverter.java @@ -0,0 +1,25 @@ +/* + * 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.webservice.servicelayer.sebconfig; + +import java.io.OutputStream; + +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; + +public interface XMLValueConverter { + + String name(); + + void convertToXML( + OutputStream out, + ConfigurationAttribute attribute, + ConfigurationValue value); + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SebExamConfigServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SebExamConfigServiceImpl.java index 9f92c8a1..18ac19b9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SebExamConfigServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SebExamConfigServiceImpl.java @@ -8,6 +8,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl; +import java.io.OutputStream; import java.util.Collection; import org.slf4j.Logger; @@ -22,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService; +import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.XMLValueConverter; @Lazy @Service @@ -32,13 +34,16 @@ public class SebExamConfigServiceImpl implements SebExamConfigService { private final ConfigurationAttributeDAO configurationAttributeDAO; private final Collection validators; + private final Collection converters; protected SebExamConfigServiceImpl( final ConfigurationAttributeDAO configurationAttributeDAO, - final Collection validators) { + final Collection validators, + final Collection converters) { this.configurationAttributeDAO = configurationAttributeDAO; this.validators = validators; + this.converters = converters; } @Override @@ -65,4 +70,16 @@ public class SebExamConfigServiceImpl implements SebExamConfigService { } + @Override + public void exportXML(final OutputStream out, final Long configurationNodeId) { + // TODO Auto-generated method stub + + } + + @Override + public void exportForExam(final OutputStream out, final Long configExamMappingId) { + // TODO Auto-generated method stub + + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/converter/KioskModeConverter.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/converter/KioskModeConverter.java new file mode 100644 index 00000000..51fd9955 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/converter/KioskModeConverter.java @@ -0,0 +1,43 @@ +/* + * 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.webservice.servicelayer.sebconfig.impl.converter; + +import java.io.OutputStream; + +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +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.WebServiceProfile; +import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.XMLValueConverter; + +@Lazy +@Component +@WebServiceProfile +public class KioskModeConverter implements XMLValueConverter { + + public static final String NAME = "KioskModeConverter"; + + @Override + public String name() { + return NAME; + } + + @Override + public void convertToXML( + final OutputStream out, + final ConfigurationAttribute attribute, + final ConfigurationValue value) { + + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java index 7ee8ff2b..6530dea3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ConfigurationController.java @@ -64,24 +64,37 @@ public class ConfigurationController extends EntityController this.configurationDAO.saveToHistory(config.configurationNodeId)) .getOrThrow(); } + @RequestMapping( + path = API.CONFIGURATION_UNDO_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT, + method = RequestMethod.POST, + consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, + produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Configuration undo(@PathVariable final String modelId) { + + return this.entityDAO.byModelId(modelId) + .flatMap(this::checkModifyAccess) + .flatMap(config -> this.configurationDAO.undo(config.configurationNodeId)) + .getOrThrow(); + } + @RequestMapping( path = API.CONFIGURATION_RESTORE_FROM_HISTORY_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT, method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Configuration restoreFormHistory( - @PathVariable final String configId, + @PathVariable final String modelId, @RequestParam(name = API.PARAM_PARENT_MODEL_ID, required = true) final Long configurationNodeId) { - return this.entityDAO.byModelId(configId) + return this.entityDAO.byModelId(modelId) .flatMap(this::checkModifyAccess) .flatMap(config -> this.configurationDAO.restoreToVersion(configurationNodeId, config.getId())) .getOrThrow(); diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 389aa7be..07e2af78 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -360,6 +360,10 @@ sebserver.examconfig.action.list.modify.properties=Edit Properties sebserver.examconfig.action.modify=Edit sebserver.examconfig.action.modify.properties=Edit Properties sebserver.examconfig.action.save=Save +sebserver.examconfig.action.saveToHistory=Save In History +sebserver.examconfig.action.saveToHistory.success=Successfully saved in history +sebserver.examconfig.action.undo=Undo +sebserver.examconfig.action.undo.success=Successfully reverted to last saved state sebserver.examconfig.form.title.new=New Exam Configuration sebserver.examconfig.form.title=Exam Configuration @@ -378,6 +382,11 @@ sebserver.examconfig.props.form.views.browser=Browser sebserver.examconfig.props.form.views.down_upload=Down/Uploads sebserver.examconfig.props.form.views.exam=Exam sebserver.examconfig.props.form.views.applications=Applications +sebserver.examconfig.props.form.views.resources=Additional Resources +sebserver.examconfig.props.form.views.network=Network +sebserver.examconfig.props.form.views.security=Security +sebserver.examconfig.props.form.views.registry=Registry +sebserver.examconfig.props.form.views.hooked_keys=Hooked Keys sebserver.examconfig.props.label.hashedAdminPassword=Administrator password sebserver.examconfig.props.label.hashedAdminPassword.confirm=Confirm password @@ -570,6 +579,122 @@ 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.label.URLFilterEnable=Activate URL Filtering +sebserver.examconfig.props.label.URLFilterEnableContentFilter=Filter also embedded content +sebserver.examconfig.props.label.URLFilterRules=Filter +sebserver.examconfig.props.label.URLFilterRules.active=Activity +sebserver.examconfig.props.label.URLFilterRules.regex=Regex +sebserver.examconfig.props.label.URLFilterRules.expression=Expression +sebserver.examconfig.props.label.URLFilterRules.action=Action +sebserver.examconfig.props.label.URLFilterRules.action.0=Block +sebserver.examconfig.props.label.URLFilterRules.action.1=Allow + +sebserver.examconfig.props.group.servicePolicy=SEB Service policy +sebserver.examconfig.props.label.sebServicePolicy.0=allow to run SEB without service +sebserver.examconfig.props.label.sebServicePolicy.1=display warning when service is not running +sebserver.examconfig.props.label.sebServicePolicy.2=allow to use SEB only with service +sebserver.examconfig.props.label.sebServicePolicy.tooltip=Policy that applies when an exam client doesn't have the SEB client running + +sebserver.examconfig.props.group.kioskMode=Kiosk Mode +sebserver.examconfig.props.label.kioskMode.tooltip=The kiosk mode setting reflects how the computer is locked down into SEB. +sebserver.examconfig.props.label.kioskMode.0=Create new desktop +sebserver.examconfig.props.label.kioskMode.0.tooltip=This kiosk mode may prevent specific third party software to run correctly together with SEB, like some screen recording software or the Windows onscreen keyboard. +sebserver.examconfig.props.label.kioskMode.1=Disable explorer Shell +sebserver.examconfig.props.label.kioskMode.1.tooltip=This kiosk mode is compatible with some screen recording/proctoring software and the Windows onscreen keyboard. +sebserver.examconfig.props.label.kioskMode.2=None (for debugging only) +sebserver.examconfig.props.label.kioskMode.2.tooltip=SEB runs without kiosk mode, switching to other applications is possible. Use this for debugging purposes only. + +sebserver.examconfig.props.label.allowVirtualMachine=Allow to run inside virtual machine +sebserver.examconfig.props.label.allowVirtualMachine.tooltip=Indicates if SEB is allowed to run in a virtual machine or not (in order to prevent potential manipulation). +sebserver.examconfig.props.label.allowScreenSharing=Allow remote session/screen sharing +sebserver.examconfig.props.label.allowScreenSharing.tootlip=Allows Windows remote sessions and macOS screen sharing to be used +sebserver.examconfig.props.label.enablePrivateClipboard=Use private clipboard (Mac) +sebserver.examconfig.props.label.enablePrivateClipboard.tooltip=Private clipboard should always be used beside when working with third party application in managed/virtual machine + +sebserver.examconfig.props.group.logging=Logging +sebserver.examconfig.props.label.enableLogging=Enable logging +sebserver.examconfig.props.label.enableLogging.tooltip=The log can help debugging SEB (send it to the developers) and to find out about possible manipulations +sebserver.examconfig.props.label.logDirectoryWin=Log file directory on Windows +sebserver.examconfig.props.label.logDirectoryOSX=Log file directory on Mac + +sebserver.examconfig.props.group.macSettings=macOS specific settings +sebserver.examconfig.props.label.minMacOSVersion=Enforce minimal macOS version: +sebserver.examconfig.props.label.minMacOSVersion.0=OS X 10.7 Lion +sebserver.examconfig.props.label.minMacOSVersion.1=OS X 10.8 Mountain Lion +sebserver.examconfig.props.label.minMacOSVersion.2=OS X 10.9 Mavericks +sebserver.examconfig.props.label.minMacOSVersion.3=OS X 10.10 Yosemite +sebserver.examconfig.props.label.minMacOSVersion.4=OS X 10.11 El Capitan +sebserver.examconfig.props.label.minMacOSVersion.5=OS X 10.12 Sierra +sebserver.examconfig.props.label.minMacOSVersion.6=OS X 10.13 Hight Sierra +sebserver.examconfig.props.label.minMacOSVersion.7=OS X 10.14 Mojave +sebserver.examconfig.props.label.enableAppSwitcherCheck=Disable app switcher when starting +sebserver.examconfig.props.label.enableAppSwitcherCheck.tooltip=SEB checks for the command key being held down while SEB is starting up. This prevents using the application switcher to mess with SEB\'s kiosk mode +sebserver.examconfig.props.label.forceAppFolderInstall=Force installation in Applications folder +sebserver.examconfig.props.label.forceAppFolderInstall.tooltip=SEB enforces to be installed in an Applications folder (/Applications or ~/Applications) +sebserver.examconfig.props.label.allowUserAppFolderInstall=Allow also user's ~/Applications folder +sebserver.examconfig.props.label.allowUserAppFolderInstall.tooltip=SEB can also be installed in the Applications folder of the current user (~/Applications) +sebserver.examconfig.props.label.allowSiri=Allow to use Siri +sebserver.examconfig.props.label.allowSiri.tooltip=If enabled, Siri can be used by tapping th emenu bar icon, Touch Bar icon or shortcut set in System Preferences/Siri (default: hold command space). The Siri window won't be displayed though +sebserver.examconfig.props.label.detectStoppedProcess=Detect when SEB process was stopped +sebserver.examconfig.props.label.detectStoppedProcess.tooltip=SEB displays a lock screen (requiring to enter the quit/unlock password) if it detects its process was stopped, which can indicate manipulation +sebserver.examconfig.props.label.allowDisplayMirroring=Allow display mirroring (affects also AirPlay Display) +sebserver.examconfig.props.label.allowDisplayMirroring.tooltip=If not selected, SEB prevents to mirror the main display to another +sebserver.examconfig.props.label.allowedDisplaysMaxNumber=Maximum allowed number of connected displays +sebserver.examconfig.props.label.allowedDisplaysMaxNumber.tooltip=If more displays are connected, this are blanked with an orange full screen window +sebserver.examconfig.props.label.allowedDisplayBuiltin=Use built-in display +sebserver.examconfig.props.label.allowedDisplayBuiltin.tooltip=Use the built-in display (if available) when only one display is allowed or when switching off display mirroring + +sebserver.examconfig.props.group.registry=While running SEB +sebserver.examconfig.props.group.registry.tooltip=Options in the Windows Security Screen invoked by Ctrl-Alt-Del +sebserver.examconfig.props.label.insideSebEnableSwitchUser=Enable Switch User +sebserver.examconfig.props.label.insideSebEnableSwitchUser.tooltip=Activates the button "Switch User" +sebserver.examconfig.props.label.insideSebEnableLockThisComputer=Enable Lock this computer +sebserver.examconfig.props.label.insideSebEnableLockThisComputer.tooltip=Activates the button "Lock this computer" +sebserver.examconfig.props.label.insideSebEnableChangeAPassword=Enable Change a password +sebserver.examconfig.props.label.insideSebEnableChangeAPassword.tooltip=Activates the button "Change a password..." +sebserver.examconfig.props.label.insideSebEnableStartTaskManager=Enable Start Task Manager +sebserver.examconfig.props.label.insideSebEnableStartTaskManager.tooltip=Activates the button "Start Task Manager" +sebserver.examconfig.props.label.insideSebEnableLogOff=Enable Log off +sebserver.examconfig.props.label.insideSebEnableLogOff.tooltip=Activates the button "Log off" +sebserver.examconfig.props.label.insideSebEnableShutDown=Enable Shut down +sebserver.examconfig.props.label.insideSebEnableShutDown.tooltip=Activates the button "Shutdown" +sebserver.examconfig.props.label.insideSebEnableEaseOfAccess=Enable Ease of Access +sebserver.examconfig.props.label.insideSebEnableEaseOfAccess.tooltip=Shows options when the button "Ease of Access" in the lower left corner is clicked,\nwhich offers help e.g. to visually or aurally handicapped persons, like the Magnifier Glass. +sebserver.examconfig.props.label.insideSebEnableVmWareClientShade=Enable VMware Client Shade +sebserver.examconfig.props.label.insideSebEnableVmWareClientShade.tooltip=Activates the "Shade" bar at the upper edge of a virtual desktop, if existent. If you're not using VMware, this setting doesn't have any effect. +sebserver.examconfig.props.label.insideSebEnableNetworkConnectionSelector=Enable network connection selector +sebserver.examconfig.props.label.insideSebEnableNetworkConnectionSelector.tooltip=Activates the button which allows to connect to WiFi networks, introduces in Windows 10. + +sebserver.examconfig.props.group.specialKeys=Special Keys +sebserver.examconfig.props.group.specialKeys.tooltip=Settings to enable or block (hook) keys, key combinations and mouse buttons. +sebserver.examconfig.props.label.enableEsc=Enable Esc +sebserver.examconfig.props.label.enablePrintScreen=Enable Print Screen +sebserver.examconfig.props.label.enablePrintScreen.tooltip=Controls Print Screen and OS X screen capture, corresponds with Enable screen capture in Security settings. +sebserver.examconfig.props.label.enableCtrlEsc=Enable Ctrl-Esc +sebserver.examconfig.props.label.enableAltEsc=Enable Alt-Esc +sebserver.examconfig.props.label.enableAltTab=Enable Alt-Tap +sebserver.examconfig.props.label.enableAltF4=Enable Alt-F4 +sebserver.examconfig.props.label.enableStartMenu=Enable Start Menu +sebserver.examconfig.props.label.enableRightMouse=Enable Right Mouse +sebserver.examconfig.props.label.enableAltMouseWheel=Enable Alt-Mousewheel +sebserver.examconfig.props.label.enableAltMouseWheel.tooltip=Corresponds to 'Allow browsing back/forward' in Browser pane. Disabling browsing to previously visited pages may increase security, because browsing back might allow to leave an exam + +sebserver.examconfig.props.group.functionKeys=Function Keys +sebserver.examconfig.props.group.functionKeys.tooltip=Enable or block function keys. This doesn't have any effect on the SEB exit sequence. Depending on specific keyboards some function keys cannot be blocked. +sebserver.examconfig.props.label.enableF1=Enable F1 +sebserver.examconfig.props.label.enableF2=Enable F2 +sebserver.examconfig.props.label.enableF3=Enable F3 +sebserver.examconfig.props.label.enableF4=Enable F4 +sebserver.examconfig.props.label.enableF5=Enable F5 +sebserver.examconfig.props.label.enableF6=Enable F6 +sebserver.examconfig.props.label.enableF7=Enable F7 +sebserver.examconfig.props.label.enableF8=Enable F8 +sebserver.examconfig.props.label.enableF9=Enable F9 +sebserver.examconfig.props.label.enableF10=Enable F10 +sebserver.examconfig.props.label.enableF11=Enable F11 +sebserver.examconfig.props.label.enableF12=Enable F12 + + sebserver.examconfig.props.validation.password.confirm=Please enter correct confirm password sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly diff --git a/src/main/resources/static/css/sebserver.css b/src/main/resources/static/css/sebserver.css index 611ad3c6..510ccfba 100644 --- a/src/main/resources/static/css/sebserver.css +++ b/src/main/resources/static/css/sebserver.css @@ -604,7 +604,7 @@ TabItem { text-decoration: none; text-shadow: none; background-image: none; - margin: 1px 0px 0px -1px; + margin: 1px 0px 0px 0px; border: 1px solid #bdbdbd; border-bottom: none; border-left: none; @@ -734,15 +734,6 @@ Widget-ToolTip-Pointer { background-image: none; } - - - - - - - - - /* Table default theme */ Table { font: 12px Arial, Helvetica, sans-serif;