SEBSERV-58 implemented

This commit is contained in:
anhefti 2019-11-27 09:33:32 +01:00
parent e3b0d2251e
commit 3e8b52acb9
8 changed files with 113 additions and 85 deletions

View file

@ -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;
}
} }

View file

@ -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();
} }

View file

@ -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);

View file

@ -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;
}
} }

View file

@ -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")
; ;

View file

@ -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;
} }

View file

@ -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));
}
} }

View file

@ -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));
}
}