Skip to content
Snippets Groups Projects
Commit 0b05d42f authored by uhensler's avatar uhensler
Browse files

OO-3819: Option to set the positive rating end of a rubric

parent 6ff33b6c
No related branches found
No related tags found
No related merge requests found
Showing
with 100 additions and 27 deletions
...@@ -50,6 +50,7 @@ public class Rubric extends AbstractElement { ...@@ -50,6 +50,7 @@ public class Rubric extends AbstractElement {
private Double upperBoundNeutral; private Double upperBoundNeutral;
private Double lowerBoundSufficient; private Double lowerBoundSufficient;
private Double upperBoundSufficient; private Double upperBoundSufficient;
private boolean startGoodRating;
@Override @Override
public String getType() { public String getType() {
...@@ -185,6 +186,14 @@ public class Rubric extends AbstractElement { ...@@ -185,6 +186,14 @@ public class Rubric extends AbstractElement {
this.upperBoundSufficient = upperBoundSufficient; this.upperBoundSufficient = upperBoundSufficient;
} }
public boolean isStartGoodRating() {
return startGoodRating;
}
public void setStartGoodRating(boolean startGoodRating) {
this.startGoodRating = startGoodRating;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(this == obj) { if(this == obj) {
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
*/ */
package org.olat.modules.forms.ui; package org.olat.modules.forms.ui;
import static org.olat.core.gui.translator.TranslatorHelper.translateAll;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -58,6 +60,12 @@ import org.olat.modules.forms.model.xml.StepLabel; ...@@ -58,6 +60,12 @@ import org.olat.modules.forms.model.xml.StepLabel;
*/ */
public class RubricEditorController extends FormBasicController implements PageElementEditorController { 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 static AtomicInteger count = new AtomicInteger();
private final Rubric rubric; private final Rubric rubric;
private boolean editMode = false; private boolean editMode = false;
...@@ -83,6 +91,7 @@ public class RubricEditorController extends FormBasicController implements PageE ...@@ -83,6 +91,7 @@ public class RubricEditorController extends FormBasicController implements PageE
private TextElement upperBoundNeutralEl; private TextElement upperBoundNeutralEl;
private TextElement lowerBoundSufficientEl; private TextElement lowerBoundSufficientEl;
private TextElement upperBoundSufficientEl; private TextElement upperBoundSufficientEl;
private SingleSelection goodRatingEl;
private FormLink addSliderButton; private FormLink addSliderButton;
private FormLayoutContainer settingsLayout; private FormLayoutContainer settingsLayout;
...@@ -222,6 +231,13 @@ public class RubricEditorController extends FormBasicController implements PageE ...@@ -222,6 +231,13 @@ public class RubricEditorController extends FormBasicController implements PageE
sufficientCont); sufficientCont);
upperBoundSufficientEl.setDomReplacementWrapperRequired(false); upperBoundSufficientEl.setDomReplacementWrapperRequired(false);
upperBoundSufficientEl.setDisplaySize(4); 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(); updateTypeSettings();
updateSteps(); updateSteps();
...@@ -592,6 +608,11 @@ public class RubricEditorController extends FormBasicController implements PageE ...@@ -592,6 +608,11 @@ public class RubricEditorController extends FormBasicController implements PageE
rubric.setUpperBoundSufficient(null); rubric.setUpperBoundSufficient(null);
} }
boolean startGoodRating = goodRatingEl.isOneSelected() && GOOD_RATING_END_KEY.equals(goodRatingEl.getSelectedKey())
? true
: false;
rubric.setStartGoodRating(startGoodRating);
rubricCtrl.updateForm(); rubricCtrl.updateForm();
fireEvent(ureq, new ChangePartEvent(rubric)); fireEvent(ureq, new ChangePartEvent(rubric));
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#if($r.isNotEmpty($stepLabels)) #if($r.isNotEmpty($stepLabels))
<div class="row"> <div class="row">
<div class="form-horizontal"> <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>
<div class="col-sm-6"><div class="form-inline"> <div class="col-sm-6"><div class="form-inline">
#foreach($stepLabel in $stepLabels) #foreach($stepLabel in $stepLabels)
......
...@@ -94,7 +94,10 @@ reports.session.forms=Frageb\u00F6gen ...@@ -94,7 +94,10 @@ reports.session.forms=Frageb\u00F6gen
reports.session.selection=Einzelne Frageb\u00F6gen reports.session.selection=Einzelne Frageb\u00F6gen
reports.table.overview=\u00DCbersicht reports.table.overview=\u00DCbersicht
reports.table.report=Tabellen 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=Ungen\u00FCgend
rubric.insufficient.explanation=Ungen\u00FCgende Beurteilung (Wert zwischen {0} und {1}) rubric.insufficient.explanation=Ungen\u00FCgende Beurteilung (Wert zwischen {0} und {1})
rubric.lower.bound=von rubric.lower.bound=von
......
...@@ -94,7 +94,10 @@ reports.session.forms=Questionnaires ...@@ -94,7 +94,10 @@ reports.session.forms=Questionnaires
reports.session.selection=Individual questionnaires reports.session.selection=Individual questionnaires
reports.table.overview=Overview reports.table.overview=Overview
reports.table.report=Tables 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=Insufficient
rubric.insufficient.explanation=Good rating (Value between {0} and {1}) rubric.insufficient.explanation=Good rating (Value between {0} and {1})
rubric.lower.bound=from rubric.lower.bound=from
......
...@@ -91,7 +91,7 @@ reports.session.forms=Questionnaires ...@@ -91,7 +91,7 @@ reports.session.forms=Questionnaires
reports.session.selection=Questionnaires individuels reports.session.selection=Questionnaires individuels
reports.table.overview=Aper\u00E7u reports.table.overview=Aper\u00E7u
reports.table.report=Tableaux reports.table.report=Tableaux
rubic.column.label=Etiquette de colonne rubric.column.label=Etiquette de colonne
rubric.insufficient=Insuffisant rubric.insufficient=Insuffisant
rubric.insufficient.explanation=Evaluation insuffisante (valuer entre {0} et {1}) rubric.insufficient.explanation=Evaluation insuffisante (valuer entre {0} et {1})
rubric.lower.bound=de rubric.lower.bound=de
......
...@@ -91,7 +91,7 @@ reports.session.forms=Question\u00E1rios ...@@ -91,7 +91,7 @@ reports.session.forms=Question\u00E1rios
reports.session.selection=Question\u00E1rios individuais reports.session.selection=Question\u00E1rios individuais
reports.table.overview=Vis\u00E3o global reports.table.overview=Vis\u00E3o global
reports.table.report=Tabelas reports.table.report=Tabelas
rubic.column.label=R\u00F3tulo da coluna rubric.column.label=R\u00F3tulo da coluna
rubric.insufficient=Insuficiente rubric.insufficient=Insuficiente
rubric.insufficient.explanation=Boa classifica\u00E7\u00E3o (valor entre {0} e {1}) rubric.insufficient.explanation=Boa classifica\u00E7\u00E3o (valor entre {0} e {1})
rubric.lower.bound=de rubric.lower.bound=de
......
...@@ -29,8 +29,10 @@ import org.olat.modules.forms.RubricRating; ...@@ -29,8 +29,10 @@ import org.olat.modules.forms.RubricRating;
*/ */
public interface GroupedStatistic extends RawGroupedStatistic { public interface GroupedStatistic extends RawGroupedStatistic {
public boolean isRawAvgMaxGood();
public Double getAvg(); public Double getAvg();
public RubricRating getRating(); public RubricRating getRating();
} }
...@@ -90,10 +90,11 @@ public class StatisticsCalculator { ...@@ -90,10 +90,11 @@ public class StatisticsCalculator {
GroupedStatistic getGroupedStatistic(RawGroupedStatistic rawStatistic, Rubric rubric) { GroupedStatistic getGroupedStatistic(RawGroupedStatistic rawStatistic, Rubric rubric) {
log.debug("Raw grouped statistic: " + rawStatistic.toString()); log.debug("Raw grouped statistic: " + rawStatistic.toString());
Double rawAvg = rawStatistic.getRawAvg(); Double rawAvg = rawStatistic.getRawAvg();
boolean rawAvgMaxGood = !rubric.isStartGoodRating();
Double scaledAvg = getScaledAvg(rubric, rawAvg); Double scaledAvg = getScaledAvg(rubric, rawAvg);
RubricRating rating = evaluationFormManager.getRubricRating(rubric, scaledAvg); RubricRating rating = evaluationFormManager.getRubricRating(rubric, scaledAvg);
GroupedStatistic statistic = new GroupedStatisticImpl(rawStatistic.getIdentifier(), rawStatistic.getMultiKey(), 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()); log.debug("Grouped statistic: " + statistic.toString());
return statistic; return statistic;
} }
...@@ -134,7 +135,7 @@ public class StatisticsCalculator { ...@@ -134,7 +135,7 @@ public class StatisticsCalculator {
for (TemporalKey temporalKey: multiTrendSeries.getTemporalKeys()) { for (TemporalKey temporalKey: multiTrendSeries.getTemporalKeys()) {
GroupedStatistic currentStatistic = statistics.getStatistic(identifier, temporalKey); GroupedStatistic currentStatistic = statistics.getStatistic(identifier, temporalKey);
if (currentStatistic != null) { if (currentStatistic != null) {
DIRECTION direction = getTrendDirection(lastStatistic, currentStatistic); DIRECTION direction = getTrendDirection(lastStatistic, currentStatistic, currentStatistic.isRawAvgMaxGood());
Trend trend = new TrendImpl(currentStatistic, direction); Trend trend = new TrendImpl(currentStatistic, direction);
multiTrendSeries.put(identifier, temporalKey, trend); multiTrendSeries.put(identifier, temporalKey, trend);
lastStatistic = currentStatistic; lastStatistic = currentStatistic;
...@@ -144,25 +145,26 @@ public class StatisticsCalculator { ...@@ -144,25 +145,26 @@ public class StatisticsCalculator {
return multiTrendSeries; return multiTrendSeries;
} }
DIRECTION getTrendDirection(GroupedStatistic prev, GroupedStatistic current) { DIRECTION getTrendDirection(GroupedStatistic prev, GroupedStatistic current, boolean rawAvgMaxGood) {
// First in a series // First in a series
if (prev == null) return DIRECTION.EQUAL; if (prev == null) return DIRECTION.EQUAL;
// Should not happen // Should not happen
Double prevAvg = prev.getRawAvg(); Double prevAvg = prev.getRawAvg();
Double currentAvg = current.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; if (prevAvg == null || currentAvg == null) return null;
double diffRange = 0.05;
double diff = currentAvg.doubleValue() - prevAvg.doubleValue(); double diff = currentAvg.doubleValue() - prevAvg.doubleValue();
DIRECTION direction = DIRECTION.EQUAL; DIRECTION direction = DIRECTION.EQUAL;
if (diff > 0.05) { if (diff > diffRange) {
direction = DIRECTION.UP; direction = rawAvgMaxGood? DIRECTION.UP: DIRECTION.DOWN;
} else if (diff < -0.05) { } else if (diff < -diffRange) {
direction = DIRECTION.DOWN; direction = rawAvgMaxGood? DIRECTION.DOWN: DIRECTION.UP;
} }
return direction; return direction;
} }
......
...@@ -37,17 +37,19 @@ public class GroupedStatisticImpl implements GroupedStatistic { ...@@ -37,17 +37,19 @@ public class GroupedStatisticImpl implements GroupedStatistic {
private final TemporalKey temporalKey; private final TemporalKey temporalKey;
private final Long count; private final Long count;
private final Double rawAvg; private final Double rawAvg;
private final boolean rawAvgMaxGood;
private final Double avg; private final Double avg;
private final RubricRating rating; private final RubricRating rating;
public GroupedStatisticImpl(String identitfier, MultiKey multiKey, TemporalKey temporalKey, Long count, 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.identitfier = identitfier;
this.multiKey = multiKey; this.multiKey = multiKey;
this.temporalKey = temporalKey; this.temporalKey = temporalKey;
this.count = count; this.count = count;
this.rawAvg = rawAvg; this.rawAvg = rawAvg;
this.avg = avg; this.avg = avg;
this.rawAvgMaxGood = rawMaxGood;
this.rating = rating; this.rating = rating;
} }
...@@ -76,6 +78,11 @@ public class GroupedStatisticImpl implements GroupedStatistic { ...@@ -76,6 +78,11 @@ public class GroupedStatisticImpl implements GroupedStatistic {
return rawAvg; return rawAvg;
} }
@Override
public boolean isRawAvgMaxGood() {
return rawAvgMaxGood;
}
@Override @Override
public Double getAvg() { public Double getAvg() {
return avg; return avg;
......
...@@ -71,6 +71,11 @@ public class TrendImpl implements Trend { ...@@ -71,6 +71,11 @@ public class TrendImpl implements Trend {
return groupedStatistic.getRawAvg(); return groupedStatistic.getRawAvg();
} }
@Override
public boolean isRawAvgMaxGood() {
return groupedStatistic.isRawAvgMaxGood();
}
@Override @Override
public Double getAvg() { public Double getAvg() {
return groupedStatistic.getAvg(); return groupedStatistic.getAvg();
......
...@@ -88,21 +88,42 @@ public class StatisticsCalculatorTest extends OlatTestCase { ...@@ -88,21 +88,42 @@ public class StatisticsCalculatorTest extends OlatTestCase {
@Test @Test
public void shouldCalculateTrendDirectionUp() { 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); assertThat(direction).isEqualTo(DIRECTION.UP);
} }
@Test @Test
public void shouldCalculateTrendDirectionDown() { 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); assertThat(direction).isEqualTo(DIRECTION.DOWN);
} }
@Test @Test
public void shouldCalculateTrendDirectionEqual() { 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); assertThat(direction).isEqualTo(DIRECTION.EQUAL);
} }
...@@ -113,17 +134,17 @@ public class StatisticsCalculatorTest extends OlatTestCase { ...@@ -113,17 +134,17 @@ public class StatisticsCalculatorTest extends OlatTestCase {
TemporalKey tk2000 = TemporalKey.of(2000); TemporalKey tk2000 = TemporalKey.of(2000);
TemporalKey tk2005 = TemporalKey.of(2005); TemporalKey tk2005 = TemporalKey.of(2005);
GroupedStatistics<GroupedStatistic> statistics = new GroupedStatistics<>(); 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); 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); 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); 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); 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); 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); statistics.putStatistic(gs5);
MultiTrendSeries<String> multiTrendSeries = sut.getTrends(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR); MultiTrendSeries<String> multiTrendSeries = sut.getTrends(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR);
...@@ -147,9 +168,9 @@ public class StatisticsCalculatorTest extends OlatTestCase { ...@@ -147,9 +168,9 @@ public class StatisticsCalculatorTest extends OlatTestCase {
public void shouldClaculateTrendGaps() { public void shouldClaculateTrendGaps() {
String identifier1 = "i1"; String identifier1 = "i1";
GroupedStatistics<GroupedStatistic> statistics = new GroupedStatistics<>(); 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); 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); statistics.putStatistic(gs3);
MultiTrendSeries<String> multiTrendSeries = sut.getTrends(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR); MultiTrendSeries<String> multiTrendSeries = sut.getTrends(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment