SEBSERV-58 implemented
This commit is contained in:
parent
e3b0d2251e
commit
3e8b52acb9
8 changed files with 113 additions and 85 deletions
|
@ -44,6 +44,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
|
|
||||||
|
public static final int DARK_COLOR_THRESHOLD = 400;
|
||||||
public static final Predicate<?> TRUE_PREDICATE = v -> true;
|
public static final Predicate<?> TRUE_PREDICATE = v -> true;
|
||||||
public static final Predicate<?> FALSE_PREDICATE = v -> false;
|
public static final Predicate<?> FALSE_PREDICATE = v -> false;
|
||||||
public static final Runnable EMPTY_EXECUTION = () -> {
|
public static final Runnable EMPTY_EXECUTION = () -> {
|
||||||
|
@ -414,4 +415,35 @@ public final class Utils {
|
||||||
}
|
}
|
||||||
return e.getCause().getClass().getName() + " : " + e.getCause().getMessage();
|
return e.getCause().getClass().getName() + " : " + e.getCause().getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean darkColor(final RGB rgb) {
|
||||||
|
return rgb.red + rgb.green + rgb.blue > DARK_COLOR_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String parseColorString(final RGB color) {
|
||||||
|
if (color == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return toColorFractionString(color.red)
|
||||||
|
+ toColorFractionString(color.green)
|
||||||
|
+ toColorFractionString(color.blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RGB parseRGB(final String colorString) {
|
||||||
|
if (StringUtils.isBlank(colorString)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int r = Integer.parseInt(colorString.substring(0, 2), 16);
|
||||||
|
final int g = Integer.parseInt(colorString.substring(2, 4), 16);
|
||||||
|
final int b = Integer.parseInt(colorString.substring(4, 6), 16);
|
||||||
|
|
||||||
|
return new RGB(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toColorFractionString(final int fraction) {
|
||||||
|
final String hexString = Integer.toHexString(fraction);
|
||||||
|
return (hexString.length() < 2) ? "0" + hexString : hexString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||||
|
@ -266,9 +267,9 @@ public class ExamForm implements TemplateComposer {
|
||||||
exam.externalId)
|
exam.externalId)
|
||||||
|
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
Domain.EXAM.ATTR_EXTERNAL_ID,
|
QuizData.QUIZ_ATTR_NAME,
|
||||||
FORM_QUIZID_TEXT_KEY,
|
FORM_NAME_TEXT_KEY,
|
||||||
exam.externalId)
|
exam.name)
|
||||||
.readonly(true)
|
.readonly(true)
|
||||||
.withInputSpan(3)
|
.withInputSpan(3)
|
||||||
.withEmptyCellSeparation(false))
|
.withEmptyCellSeparation(false))
|
||||||
|
@ -298,19 +299,16 @@ public class ExamForm implements TemplateComposer {
|
||||||
.withEmptyCellSeparation(false))
|
.withEmptyCellSeparation(false))
|
||||||
|
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
QuizData.QUIZ_ATTR_NAME,
|
Domain.EXAM.ATTR_EXTERNAL_ID,
|
||||||
FORM_NAME_TEXT_KEY,
|
FORM_QUIZID_TEXT_KEY,
|
||||||
exam.name)
|
exam.externalId)
|
||||||
.readonly(true)
|
.readonly(true)
|
||||||
.withInputSpan(3)
|
|
||||||
.withEmptyCellSeparation(false))
|
.withEmptyCellSeparation(false))
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
QuizData.QUIZ_ATTR_START_URL,
|
QuizData.QUIZ_ATTR_START_URL,
|
||||||
FORM_QUIZ_URL_TEXT_KEY,
|
FORM_QUIZ_URL_TEXT_KEY,
|
||||||
exam.startURL)
|
exam.startURL)
|
||||||
.readonly(true)
|
.readonly(true))
|
||||||
.withInputSpan(3)
|
|
||||||
.withEmptyCellSeparation(false))
|
|
||||||
|
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
QuizData.QUIZ_ATTR_DESCRIPTION,
|
QuizData.QUIZ_ATTR_DESCRIPTION,
|
||||||
|
@ -318,8 +316,7 @@ public class ExamForm implements TemplateComposer {
|
||||||
exam.description)
|
exam.description)
|
||||||
.asArea()
|
.asArea()
|
||||||
.readonly(true)
|
.readonly(true)
|
||||||
.withInputSpan(6)
|
.withInputSpan(6))
|
||||||
.withEmptyCellSeparation(false))
|
|
||||||
|
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
Domain.EXAM.ATTR_STATUS + "_display",
|
Domain.EXAM.ATTR_STATUS + "_display",
|
||||||
|
@ -718,7 +715,6 @@ public class ExamForm implements TemplateComposer {
|
||||||
.getText(ResourceService.EXAM_INDICATOR_TYPE_PREFIX + indicator.type.name());
|
.getText(ResourceService.EXAM_INDICATOR_TYPE_PREFIX + indicator.type.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO find a better way to show a threshold value as text
|
|
||||||
private static String thresholdsValue(final Indicator indicator) {
|
private static String thresholdsValue(final Indicator indicator) {
|
||||||
if (indicator.thresholds.isEmpty()) {
|
if (indicator.thresholds.isEmpty()) {
|
||||||
return Constants.EMPTY_NOTE;
|
return Constants.EMPTY_NOTE;
|
||||||
|
@ -728,10 +724,17 @@ public class ExamForm implements TemplateComposer {
|
||||||
.stream()
|
.stream()
|
||||||
.reduce(
|
.reduce(
|
||||||
new StringBuilder(),
|
new StringBuilder(),
|
||||||
(sb, threshold) -> sb.append(threshold.value)
|
(sb, threshold) -> sb
|
||||||
.append(Constants.URL_PORT_SEPARATOR)
|
.append("<span style='padding: 2px 5px 2px 5px; background-color: #")
|
||||||
.append(threshold.color)
|
.append(threshold.color)
|
||||||
.append(Constants.EMBEDDED_LIST_SEPARATOR),
|
.append("; ")
|
||||||
|
.append((Utils.darkColor(Utils.parseRGB(threshold.color)))
|
||||||
|
? "color: #4a4a4a; "
|
||||||
|
: "color: #FFFFFF;")
|
||||||
|
.append("'>")
|
||||||
|
.append(threshold.value).append(" (").append(threshold.color).append(")")
|
||||||
|
.append("</span>")
|
||||||
|
.append(" | "),
|
||||||
(sb1, sb2) -> sb1.append(sb2))
|
(sb1, sb2) -> sb1.append(sb2))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ public class EntityTable<ROW extends Entity> {
|
||||||
this.table.setHeaderVisible(true);
|
this.table.setHeaderVisible(true);
|
||||||
this.table.setLinesVisible(true);
|
this.table.setLinesVisible(true);
|
||||||
this.table.setData(RWT.CUSTOM_ITEM_HEIGHT, ROW_HEIGHT);
|
this.table.setData(RWT.CUSTOM_ITEM_HEIGHT, ROW_HEIGHT);
|
||||||
|
this.table.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
|
||||||
|
|
||||||
if (defaultActionFunction != null) {
|
if (defaultActionFunction != null) {
|
||||||
final PageAction defaultAction = defaultActionFunction.apply(this);
|
final PageAction defaultAction = defaultActionFunction.apply(this);
|
||||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.widget;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.graphics.Color;
|
import org.eclipse.swt.graphics.Color;
|
||||||
import org.eclipse.swt.graphics.RGB;
|
import org.eclipse.swt.graphics.RGB;
|
||||||
|
@ -25,7 +26,9 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
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.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||||
|
|
||||||
public final class ColorSelection extends Composite implements Selection {
|
public final class ColorSelection extends Composite implements Selection {
|
||||||
|
@ -36,8 +39,10 @@ public final class ColorSelection extends Composite implements Selection {
|
||||||
private static final LocTextKey DEFAULT_SELECT_TOOLTIP_KEY = new LocTextKey("sebserver.overall.action.select");
|
private static final LocTextKey DEFAULT_SELECT_TOOLTIP_KEY = new LocTextKey("sebserver.overall.action.select");
|
||||||
|
|
||||||
private static final int ACTION_COLUMN_WIDTH = 20;
|
private static final int ACTION_COLUMN_WIDTH = 20;
|
||||||
|
private static final int ACTION_COLUMN_ADJUST = 10;
|
||||||
private final ColorDialog colorDialog;
|
private final ColorDialog colorDialog;
|
||||||
private final Composite colorField;
|
private final Composite colorField;
|
||||||
|
private final Label colorLabel;
|
||||||
private RGB selection;
|
private RGB selection;
|
||||||
|
|
||||||
private Listener listener = null;
|
private Listener listener = null;
|
||||||
|
@ -62,6 +67,15 @@ public final class ColorSelection extends Composite implements Selection {
|
||||||
final GridData colorCell = new GridData(SWT.FILL, SWT.TOP, true, false);
|
final GridData colorCell = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||||
colorCell.heightHint = 20;
|
colorCell.heightHint = 20;
|
||||||
this.colorField.setLayoutData(colorCell);
|
this.colorField.setLayoutData(colorCell);
|
||||||
|
final GridLayout colorCallLayout = new GridLayout();
|
||||||
|
colorCallLayout.horizontalSpacing = 5;
|
||||||
|
colorCallLayout.verticalSpacing = 0;
|
||||||
|
colorCallLayout.marginHeight = 0;
|
||||||
|
colorCallLayout.marginTop = 2;
|
||||||
|
this.colorField.setLayout(colorCallLayout);
|
||||||
|
this.colorLabel = new Label(this.colorField, SWT.NONE);
|
||||||
|
this.colorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, true, false));
|
||||||
|
this.colorLabel.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIGHT_COLOR_LABEL.key);
|
||||||
|
|
||||||
final Label imageButton = widgetFactory.imageButton(
|
final Label imageButton = widgetFactory.imageButton(
|
||||||
ImageIcon.COLOR,
|
ImageIcon.COLOR,
|
||||||
|
@ -94,13 +108,13 @@ public final class ColorSelection extends Composite implements Selection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void select(final String keys) {
|
public void select(final String keys) {
|
||||||
this.selection = parseRGB(keys);
|
this.selection = Utils.parseRGB(keys);
|
||||||
applySelection();
|
applySelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSelectionValue() {
|
public String getSelectionValue() {
|
||||||
return parseColorString(this.selection);
|
return Utils.parseColorString(this.selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,47 +139,27 @@ public final class ColorSelection extends Composite implements Selection {
|
||||||
private void applySelection() {
|
private void applySelection() {
|
||||||
if (this.selection != null) {
|
if (this.selection != null) {
|
||||||
this.colorField.setBackground(new Color(this.getDisplay(), this.selection));
|
this.colorField.setBackground(new Color(this.getDisplay(), this.selection));
|
||||||
|
this.colorLabel.setText(Utils.parseColorString(this.selection));
|
||||||
|
this.colorLabel.setData(RWT.CUSTOM_VARIANT, (Utils.darkColor(this.selection))
|
||||||
|
? CustomVariant.DARK_COLOR_LABEL.key
|
||||||
|
: CustomVariant.LIGHT_COLOR_LABEL.key);
|
||||||
} else {
|
} else {
|
||||||
this.colorField.setBackground(null);
|
this.colorField.setBackground(null);
|
||||||
|
this.colorLabel.setText(StringUtils.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.colorField.layout(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adaptColumnWidth(final Event event) {
|
private void adaptColumnWidth(final Event event) {
|
||||||
try {
|
try {
|
||||||
final int currentTableWidth = this.getClientArea().width;
|
final int currentTableWidth = this.getClientArea().width;
|
||||||
final GridData comboCell = (GridData) this.colorField.getLayoutData();
|
final GridData comboCell = (GridData) this.colorField.getLayoutData();
|
||||||
comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH;
|
comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH - ACTION_COLUMN_ADJUST;
|
||||||
this.layout();
|
this.layout();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("Failed to adaptColumnWidth: ", e);
|
log.warn("Failed to adaptColumnWidth: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static String parseColorString(final RGB color) {
|
|
||||||
if (color == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return toColorFractionString(color.red)
|
|
||||||
+ toColorFractionString(color.green)
|
|
||||||
+ toColorFractionString(color.blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RGB parseRGB(final String colorString) {
|
|
||||||
if (StringUtils.isBlank(colorString)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int r = Integer.parseInt(colorString.substring(0, 2), 16);
|
|
||||||
final int g = Integer.parseInt(colorString.substring(2, 4), 16);
|
|
||||||
final int b = Integer.parseInt(colorString.substring(4, 6), 16);
|
|
||||||
|
|
||||||
return new RGB(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String toColorFractionString(final int fraction) {
|
|
||||||
final String hexString = Integer.toHexString(fraction);
|
|
||||||
return (hexString.length() < 2) ? "0" + hexString : hexString;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,10 @@ public class WidgetFactory {
|
||||||
MESSAGE("message"),
|
MESSAGE("message"),
|
||||||
ERROR("error"),
|
ERROR("error"),
|
||||||
WARNING("warning"),
|
WARNING("warning"),
|
||||||
CONFIG_INPUT_READONLY("inputreadonly")
|
CONFIG_INPUT_READONLY("inputreadonly"),
|
||||||
|
|
||||||
|
DARK_COLOR_LABEL("colordark"),
|
||||||
|
LIGHT_COLOR_LABEL("colorlight")
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,18 @@ Label-SeparatorLine {
|
||||||
height: 1px;
|
height: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label.colordark {
|
||||||
|
font: 12px Arial, Helvetica, monospace;
|
||||||
|
letter-spacing: 3.25px;
|
||||||
|
color: #4a4a4a;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label.colorlight {
|
||||||
|
font: 12px Arial, Helvetica, monospace;
|
||||||
|
letter-spacing: 3.25px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
Composite.bordered {
|
Composite.bordered {
|
||||||
border: 2px;
|
border: 2px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.swt.graphics.RGB;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class UtilsTest {
|
public class UtilsTest {
|
||||||
|
@ -45,4 +46,24 @@ public class UtilsTest {
|
||||||
assertEquals("[ONE, TWO]", r5.toString());
|
assertEquals("[ONE, TWO]", r5.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseRGB() {
|
||||||
|
String colorString = "FFFFFF";
|
||||||
|
assertEquals(
|
||||||
|
"RGB {255, 255, 255}",
|
||||||
|
Utils.parseRGB(colorString).toString());
|
||||||
|
|
||||||
|
colorString = "FFaa34";
|
||||||
|
assertEquals(
|
||||||
|
"RGB {255, 170, 52}",
|
||||||
|
Utils.parseRGB(colorString).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseColorString() {
|
||||||
|
final RGB color = new RGB(255, 255, 255);
|
||||||
|
assertEquals("ffffff", Utils.parseColorString(color));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +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.widget;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
import org.eclipse.swt.graphics.RGB;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class ColorSelectionTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseRGB() {
|
|
||||||
String colorString = "FFFFFF";
|
|
||||||
assertEquals(
|
|
||||||
"RGB {255, 255, 255}",
|
|
||||||
ColorSelection.parseRGB(colorString).toString());
|
|
||||||
|
|
||||||
colorString = "FFaa34";
|
|
||||||
assertEquals(
|
|
||||||
"RGB {255, 170, 52}",
|
|
||||||
ColorSelection.parseRGB(colorString).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseColorString() {
|
|
||||||
final RGB color = new RGB(255, 255, 255);
|
|
||||||
assertEquals("ffffff", ColorSelection.parseColorString(color));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue