diff --git a/src/main/java/org/olat/modules/forms/model/xml/Rubric.java b/src/main/java/org/olat/modules/forms/model/xml/Rubric.java index e5f0588539aca4d4e27b2e16f17cf7365ad52e63..f9d7dda1ffa9d47d069421a055ba1d015296ab4d 100644 --- a/src/main/java/org/olat/modules/forms/model/xml/Rubric.java +++ b/src/main/java/org/olat/modules/forms/model/xml/Rubric.java @@ -50,6 +50,7 @@ public class Rubric extends AbstractElement { private Double upperBoundNeutral; private Double lowerBoundSufficient; private Double upperBoundSufficient; + private boolean startGoodRating; @Override public String getType() { @@ -185,6 +186,14 @@ public class Rubric extends AbstractElement { this.upperBoundSufficient = upperBoundSufficient; } + public boolean isStartGoodRating() { + return startGoodRating; + } + + public void setStartGoodRating(boolean startGoodRating) { + this.startGoodRating = startGoodRating; + } + @Override public boolean equals(Object obj) { if(this == obj) { diff --git a/src/main/java/org/olat/modules/forms/ui/RubricEditorController.java b/src/main/java/org/olat/modules/forms/ui/RubricEditorController.java index 2f2e87754dd3535bd88d7c80d4a25a38eeb1da5f..7467fe5d33bcb7aa59e14d497da676f2ad0def87 100644 --- a/src/main/java/org/olat/modules/forms/ui/RubricEditorController.java +++ b/src/main/java/org/olat/modules/forms/ui/RubricEditorController.java @@ -19,6 +19,8 @@ */ package org.olat.modules.forms.ui; +import static org.olat.core.gui.translator.TranslatorHelper.translateAll; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -58,6 +60,12 @@ import org.olat.modules.forms.model.xml.StepLabel; */ public class RubricEditorController extends FormBasicController implements PageElementEditorController { + private static final String GOOD_RATING_END_KEY = "rubric.good.rating.end"; + private static final String GOOD_RATING_START_KEY = "rubric.good.rating.start"; + private final String[] GOOD_RATING_KEYS = new String[] { + GOOD_RATING_END_KEY, GOOD_RATING_START_KEY + }; + private static AtomicInteger count = new AtomicInteger(); private final Rubric rubric; private boolean editMode = false; @@ -83,6 +91,7 @@ public class RubricEditorController extends FormBasicController implements PageE private TextElement upperBoundNeutralEl; private TextElement lowerBoundSufficientEl; private TextElement upperBoundSufficientEl; + private SingleSelection goodRatingEl; private FormLink addSliderButton; private FormLayoutContainer settingsLayout; @@ -222,6 +231,13 @@ public class RubricEditorController extends FormBasicController implements PageE sufficientCont); upperBoundSufficientEl.setDomReplacementWrapperRequired(false); upperBoundSufficientEl.setDisplaySize(4); + + goodRatingEl = uifactory.addDropdownSingleselect("rubric.good.rating" + count.incrementAndGet(), "rubric.good.rating", + settingsLayout, GOOD_RATING_KEYS, translateAll(getTranslator(), GOOD_RATING_KEYS), null); + if (rubric != null) { + String goodRatingKey = rubric.isStartGoodRating()? GOOD_RATING_START_KEY: GOOD_RATING_END_KEY; + goodRatingEl.select(goodRatingKey, true); + } updateTypeSettings(); updateSteps(); @@ -592,6 +608,11 @@ public class RubricEditorController extends FormBasicController implements PageE rubric.setUpperBoundSufficient(null); } + boolean startGoodRating = goodRatingEl.isOneSelected() && GOOD_RATING_END_KEY.equals(goodRatingEl.getSelectedKey()) + ? true + : false; + rubric.setStartGoodRating(startGoodRating); + rubricCtrl.updateForm(); fireEvent(ureq, new ChangePartEvent(rubric)); diff --git a/src/main/java/org/olat/modules/forms/ui/_content/rubric_editor.html b/src/main/java/org/olat/modules/forms/ui/_content/rubric_editor.html index b7b42ec7a7d16753ba1b3333101578d65274bbea..8170d71b34c9e2e889f35910eb9ca1ba8818824e 100644 --- a/src/main/java/org/olat/modules/forms/ui/_content/rubric_editor.html +++ b/src/main/java/org/olat/modules/forms/ui/_content/rubric_editor.html @@ -5,7 +5,7 @@ #if($r.isNotEmpty($stepLabels)) <div class="row"> <div class="form-horizontal"> - <label class="control-label col-sm-3">$r.translate("rubic.column.label")</label> + <label class="control-label col-sm-3">$r.translate("rubric.column.label")</label> </div> <div class="col-sm-6"><div class="form-inline"> #foreach($stepLabel in $stepLabels) diff --git a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_de.properties index d7c944b76e1c533576bb9f9039aff05d0def382e..504ae68ff81c447ab0c51569ee8d308cb11f7f5f 100644 --- a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_de.properties @@ -94,7 +94,10 @@ reports.session.forms=Frageb\u00F6gen reports.session.selection=Einzelne Frageb\u00F6gen reports.table.overview=\u00DCbersicht reports.table.report=Tabellen -rubic.column.label=Spaltenbeschriftung +rubric.column.label=Spaltenbeschriftung +rubric.good.rating.end=Rechts +rubric.good.rating.start=Links +rubric.good.rating=Positive Bewertung rubric.insufficient=Ungen\u00FCgend rubric.insufficient.explanation=Ungen\u00FCgende Beurteilung (Wert zwischen {0} und {1}) rubric.lower.bound=von diff --git a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_en.properties index 28e06cc4bb079e3945748187f39ea137a2ff226b..f10d8fbb5f68fef78964cb8c25ad31303096fa30 100644 --- a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_en.properties @@ -94,7 +94,10 @@ reports.session.forms=Questionnaires reports.session.selection=Individual questionnaires reports.table.overview=Overview reports.table.report=Tables -rubic.column.label=Column label +rubric.column.label=Column label +rubric.good.rating.end=Right +rubric.good.rating.start=Left +rubric.good.rating=Positive rating rubric.insufficient=Insufficient rubric.insufficient.explanation=Good rating (Value between {0} and {1}) rubric.lower.bound=from diff --git a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_fr.properties index 27cdd4a1273d81a615a0c3ef76a5eb0ed174eebb..cf2c14d87cf6dbf53182706e31f11bec05bc7ea1 100644 --- a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_fr.properties @@ -91,7 +91,7 @@ reports.session.forms=Questionnaires reports.session.selection=Questionnaires individuels reports.table.overview=Aper\u00E7u reports.table.report=Tableaux -rubic.column.label=Etiquette de colonne +rubric.column.label=Etiquette de colonne rubric.insufficient=Insuffisant rubric.insufficient.explanation=Evaluation insuffisante (valuer entre {0} et {1}) rubric.lower.bound=de diff --git a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties index 7c28598f8c6278578bb38df7e33548b8d5ed8356..78c02e570b034e724ca320316a87213dc81464eb 100644 --- a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties @@ -91,7 +91,7 @@ reports.session.forms=Question\u00E1rios reports.session.selection=Question\u00E1rios individuais reports.table.overview=Vis\u00E3o global reports.table.report=Tabelas -rubic.column.label=R\u00F3tulo da coluna +rubric.column.label=R\u00F3tulo da coluna rubric.insufficient=Insuficiente rubric.insufficient.explanation=Boa classifica\u00E7\u00E3o (valor entre {0} e {1}) rubric.lower.bound=de diff --git a/src/main/java/org/olat/modules/quality/analysis/GroupedStatistic.java b/src/main/java/org/olat/modules/quality/analysis/GroupedStatistic.java index 50748d428ea96f03672abb17a44d1f8069be23a5..6dd792eb24fb6e58903fc350484acce87097424d 100644 --- a/src/main/java/org/olat/modules/quality/analysis/GroupedStatistic.java +++ b/src/main/java/org/olat/modules/quality/analysis/GroupedStatistic.java @@ -29,8 +29,10 @@ import org.olat.modules.forms.RubricRating; */ public interface GroupedStatistic extends RawGroupedStatistic { + public boolean isRawAvgMaxGood(); + public Double getAvg(); public RubricRating getRating(); - + } diff --git a/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java b/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java index 7e83878eded87a23ac6c1cee111556d259a2a05f..94b249df81a9f3b8b3565a75596a6110c62d98ce 100644 --- a/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java +++ b/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java @@ -90,10 +90,11 @@ public class StatisticsCalculator { GroupedStatistic getGroupedStatistic(RawGroupedStatistic rawStatistic, Rubric rubric) { log.debug("Raw grouped statistic: " + rawStatistic.toString()); Double rawAvg = rawStatistic.getRawAvg(); + boolean rawAvgMaxGood = !rubric.isStartGoodRating(); Double scaledAvg = getScaledAvg(rubric, rawAvg); RubricRating rating = evaluationFormManager.getRubricRating(rubric, scaledAvg); GroupedStatistic statistic = new GroupedStatisticImpl(rawStatistic.getIdentifier(), rawStatistic.getMultiKey(), - rawStatistic.getTemporalKey(), rawStatistic.getCount(), rawAvg, scaledAvg, rating); + rawStatistic.getTemporalKey(), rawStatistic.getCount(), rawAvg, rawAvgMaxGood, scaledAvg, rating); log.debug("Grouped statistic: " + statistic.toString()); return statistic; } @@ -134,7 +135,7 @@ public class StatisticsCalculator { for (TemporalKey temporalKey: multiTrendSeries.getTemporalKeys()) { GroupedStatistic currentStatistic = statistics.getStatistic(identifier, temporalKey); if (currentStatistic != null) { - DIRECTION direction = getTrendDirection(lastStatistic, currentStatistic); + DIRECTION direction = getTrendDirection(lastStatistic, currentStatistic, currentStatistic.isRawAvgMaxGood()); Trend trend = new TrendImpl(currentStatistic, direction); multiTrendSeries.put(identifier, temporalKey, trend); lastStatistic = currentStatistic; @@ -144,25 +145,26 @@ public class StatisticsCalculator { return multiTrendSeries; } - DIRECTION getTrendDirection(GroupedStatistic prev, GroupedStatistic current) { + DIRECTION getTrendDirection(GroupedStatistic prev, GroupedStatistic current, boolean rawAvgMaxGood) { // First in a series if (prev == null) return DIRECTION.EQUAL; // Should not happen Double prevAvg = prev.getRawAvg(); Double currentAvg = current.getRawAvg(); - return getTrendDirection(prevAvg, currentAvg); + return getTrendDirection(prevAvg, currentAvg, rawAvgMaxGood); } - DIRECTION getTrendDirection(Double prevAvg, Double currentAvg) { + DIRECTION getTrendDirection(Double prevAvg, Double currentAvg, boolean rawAvgMaxGood) { if (prevAvg == null || currentAvg == null) return null; + double diffRange = 0.05; double diff = currentAvg.doubleValue() - prevAvg.doubleValue(); DIRECTION direction = DIRECTION.EQUAL; - if (diff > 0.05) { - direction = DIRECTION.UP; - } else if (diff < -0.05) { - direction = DIRECTION.DOWN; + if (diff > diffRange) { + direction = rawAvgMaxGood? DIRECTION.UP: DIRECTION.DOWN; + } else if (diff < -diffRange) { + direction = rawAvgMaxGood? DIRECTION.DOWN: DIRECTION.UP; } return direction; } diff --git a/src/main/java/org/olat/modules/quality/analysis/model/GroupedStatisticImpl.java b/src/main/java/org/olat/modules/quality/analysis/model/GroupedStatisticImpl.java index e6bc04df067aa7b7f117cf567f21968d5a5aa0f4..8d75bd5bf7fa78af0902e08f902506cf6f010e73 100644 --- a/src/main/java/org/olat/modules/quality/analysis/model/GroupedStatisticImpl.java +++ b/src/main/java/org/olat/modules/quality/analysis/model/GroupedStatisticImpl.java @@ -37,17 +37,19 @@ public class GroupedStatisticImpl implements GroupedStatistic { private final TemporalKey temporalKey; private final Long count; private final Double rawAvg; + private final boolean rawAvgMaxGood; private final Double avg; private final RubricRating rating; public GroupedStatisticImpl(String identitfier, MultiKey multiKey, TemporalKey temporalKey, Long count, - Double rawAvg, Double avg, RubricRating rating) { + Double rawAvg, boolean rawMaxGood, Double avg, RubricRating rating) { this.identitfier = identitfier; this.multiKey = multiKey; this.temporalKey = temporalKey; this.count = count; this.rawAvg = rawAvg; this.avg = avg; + this.rawAvgMaxGood = rawMaxGood; this.rating = rating; } @@ -76,6 +78,11 @@ public class GroupedStatisticImpl implements GroupedStatistic { return rawAvg; } + @Override + public boolean isRawAvgMaxGood() { + return rawAvgMaxGood; + } + @Override public Double getAvg() { return avg; diff --git a/src/main/java/org/olat/modules/quality/analysis/model/TrendImpl.java b/src/main/java/org/olat/modules/quality/analysis/model/TrendImpl.java index ce7de78a5d4333550aac8266c6ef761538f3a4e9..31a319d48a4e8c753683694229a74cb6229e1316 100644 --- a/src/main/java/org/olat/modules/quality/analysis/model/TrendImpl.java +++ b/src/main/java/org/olat/modules/quality/analysis/model/TrendImpl.java @@ -71,6 +71,11 @@ public class TrendImpl implements Trend { return groupedStatistic.getRawAvg(); } + @Override + public boolean isRawAvgMaxGood() { + return groupedStatistic.isRawAvgMaxGood(); + } + @Override public Double getAvg() { return groupedStatistic.getAvg(); diff --git a/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java b/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java index 95735a4a0707fae9cdac7b04943f0ad3e728b143..d70e882460251691dedb2032e8a6ff4e64f5a371 100644 --- a/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java +++ b/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java @@ -88,21 +88,42 @@ public class StatisticsCalculatorTest extends OlatTestCase { @Test public void shouldCalculateTrendDirectionUp() { - DIRECTION direction = sut.getTrendDirection(1.0, 2.0); + DIRECTION direction = sut.getTrendDirection(1.0, 2.0, true); assertThat(direction).isEqualTo(DIRECTION.UP); } @Test public void shouldCalculateTrendDirectionDown() { - DIRECTION direction = sut.getTrendDirection(2.0, 1.0); + DIRECTION direction = sut.getTrendDirection(2.0, 1.0, true); assertThat(direction).isEqualTo(DIRECTION.DOWN); } @Test public void shouldCalculateTrendDirectionEqual() { - DIRECTION direction = sut.getTrendDirection(1.0, 1.01); + DIRECTION direction = sut.getTrendDirection(1.0, 1.01, true); + + assertThat(direction).isEqualTo(DIRECTION.EQUAL); + } + + @Test + public void shouldCalculateTrendDirectionDownWithRawMaxBad() { + DIRECTION direction = sut.getTrendDirection(1.0, 2.0, false); + + assertThat(direction).isEqualTo(DIRECTION.DOWN); + } + + @Test + public void shouldCalculateTrendDirectionUpWithRawMaxBad() { + DIRECTION direction = sut.getTrendDirection(2.0, 1.0, false); + + assertThat(direction).isEqualTo(DIRECTION.UP); + } + + @Test + public void shouldCalculateTrendDirectionEqualWithRawMaxBad() { + DIRECTION direction = sut.getTrendDirection(1.0, 1.01, false); assertThat(direction).isEqualTo(DIRECTION.EQUAL); } @@ -113,17 +134,17 @@ public class StatisticsCalculatorTest extends OlatTestCase { TemporalKey tk2000 = TemporalKey.of(2000); TemporalKey tk2005 = TemporalKey.of(2005); GroupedStatistics<GroupedStatistic> statistics = new GroupedStatistics<>(); - GroupedStatistic gs0 = new GroupedStatisticImpl(identifier1, MultiKey.none(), tk2000, 1l, 1.0, null, null); + GroupedStatistic gs0 = new GroupedStatisticImpl(identifier1, MultiKey.none(), tk2000, 1l, 1.0, true, null, null); statistics.putStatistic(gs0); - GroupedStatistic gs1 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2001), 1l, 1.0, null, null); + GroupedStatistic gs1 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2001), 1l, 1.0, true, null, null); statistics.putStatistic(gs1); - GroupedStatistic gs2 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2002), 1l, 2.0, null, null); + GroupedStatistic gs2 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2002), 1l, 2.0, true, null, null); statistics.putStatistic(gs2); - GroupedStatistic gs3 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2003), 1l, 2.01, null, null); + GroupedStatistic gs3 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2003), 1l, 2.01, true, null, null); statistics.putStatistic(gs3); - GroupedStatistic gs4 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2004), 1l, 1.0, null, null); + GroupedStatistic gs4 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2004), 1l, 1.0, true, null, null); statistics.putStatistic(gs4); - GroupedStatistic gs5 = new GroupedStatisticImpl(identifier1, MultiKey.none(), tk2005, 1l, 1.0, null, null); + GroupedStatistic gs5 = new GroupedStatisticImpl(identifier1, MultiKey.none(), tk2005, 1l, 1.0, true, null, null); statistics.putStatistic(gs5); MultiTrendSeries<String> multiTrendSeries = sut.getTrends(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR); @@ -147,9 +168,9 @@ public class StatisticsCalculatorTest extends OlatTestCase { public void shouldClaculateTrendGaps() { String identifier1 = "i1"; GroupedStatistics<GroupedStatistic> statistics = new GroupedStatistics<>(); - GroupedStatistic gs0 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2000), 1l, 1.0, null, null); + GroupedStatistic gs0 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2000), 1l, 1.0, true, null, null); statistics.putStatistic(gs0); - GroupedStatistic gs3 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2003), 1l, 2.01, null, null); + GroupedStatistic gs3 = new GroupedStatisticImpl(identifier1, MultiKey.none(), TemporalKey.of(2003), 1l, 2.01, true, null, null); statistics.putStatistic(gs3); MultiTrendSeries<String> multiTrendSeries = sut.getTrends(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR);