diff --git a/src/main/java/org/olat/modules/forms/EvaluationFormManager.java b/src/main/java/org/olat/modules/forms/EvaluationFormManager.java index b29bac8fd691e11c94ac4084b52f0f300f9cc72f..7040f63670449bcce9347318935438aa2f8c7330 100644 --- a/src/main/java/org/olat/modules/forms/EvaluationFormManager.java +++ b/src/main/java/org/olat/modules/forms/EvaluationFormManager.java @@ -34,6 +34,8 @@ import org.olat.modules.forms.model.jpa.EvaluationFormResponses; import org.olat.modules.forms.model.xml.AbstractElement; import org.olat.modules.forms.model.xml.Form; import org.olat.modules.forms.model.xml.Rubric; +import org.olat.modules.forms.ui.model.CountRatioResult; +import org.olat.modules.forms.ui.model.CountResult; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; @@ -235,5 +237,7 @@ public interface EvaluationFormManager { public RubricStatistic getRubricStatistic(Rubric rubric, SlidersStatistic slidersStatistic); public RubricRating getRubricRating(Rubric rubric, Double value); + + public List<CountRatioResult> calculateRatio(List<CountResult> countResults); } diff --git a/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java b/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java index 9c7dbfeef06770e82ec51927d57b980a77b7e3a9..3b37dc2ab2ba1f124d983fd33f469786d3867f66 100644 --- a/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java +++ b/src/main/java/org/olat/modules/forms/manager/EvaluationFormManagerImpl.java @@ -76,6 +76,8 @@ import org.olat.modules.forms.model.xml.Form; import org.olat.modules.forms.model.xml.FormXStream; import org.olat.modules.forms.model.xml.Rubric; import org.olat.modules.forms.model.xml.Slider; +import org.olat.modules.forms.ui.model.CountRatioResult; +import org.olat.modules.forms.ui.model.CountResult; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; import org.springframework.beans.factory.annotation.Autowired; @@ -580,4 +582,19 @@ public class EvaluationFormManagerImpl implements EvaluationFormManager { public RubricRating getRubricRating(Rubric rubric, Double value) { return RubricRatingEvaluator.rate(rubric, value); } + + @Override + public List<CountRatioResult> calculateRatio(List<CountResult> countResults) { + if (countResults == null || countResults.isEmpty()) return new ArrayList<>(0); + + long sum = countResults.stream().mapToLong(CountResult::getCount).sum(); + if (sum == 0) return new ArrayList<>(0); + + List<CountRatioResult> ratios = new ArrayList<>(countResults.size()); + for (CountResult countResult : countResults) { + double ratio = (double)countResult.getCount() / sum; + ratios.add(new CountRatioResult(countResult, ratio)); + } + return ratios; + } } diff --git a/src/main/java/org/olat/modules/forms/ui/CountDataModel.java b/src/main/java/org/olat/modules/forms/ui/CountDataModel.java index a81a9c8de0ab0a46232fc33a23f3955b01313f8a..1069ac244079dc6df1b3aaa59cf772647a846dca 100644 --- a/src/main/java/org/olat/modules/forms/ui/CountDataModel.java +++ b/src/main/java/org/olat/modules/forms/ui/CountDataModel.java @@ -27,7 +27,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSorta import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; -import org.olat.modules.forms.ui.model.CountResult; +import org.olat.modules.forms.ui.model.CountRatioResult; /** * @@ -35,8 +35,8 @@ import org.olat.modules.forms.ui.model.CountResult; * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ -public class CountDataModel extends DefaultFlexiTableDataModel<CountResult> -implements SortableFlexiTableDataModel<CountResult> { +public class CountDataModel extends DefaultFlexiTableDataModel<CountRatioResult> +implements SortableFlexiTableDataModel<CountRatioResult> { public CountDataModel(FlexiTableColumnModel columnsModel) { super(columnsModel); @@ -44,33 +44,35 @@ implements SortableFlexiTableDataModel<CountResult> { @Override public void sort(SortKey orderBy) { - List<CountResult> rows = new SortableFlexiTableModelDelegate<>(orderBy, this, null).sort(); + List<CountRatioResult> rows = new SortableFlexiTableModelDelegate<>(orderBy, this, null).sort(); super.setObjects(rows); } @Override public Object getValueAt(int row, int col) { - CountResult countResult = getObject(row); + CountRatioResult countResult = getObject(row); return getValueAt(countResult, col); } @Override - public Object getValueAt(CountResult row, int col) { + public Object getValueAt(CountRatioResult row, int col) { switch(CountReportCols.values()[col]) { case name: return row.getName(); case count: return row.getCount(); + case percent: return row.getRatio(); default: return null; } } @Override - public DefaultFlexiTableDataModel<CountResult> createCopyWithEmptyList() { + public DefaultFlexiTableDataModel<CountRatioResult> createCopyWithEmptyList() { return new CountDataModel(getTableColumnModel()); } public enum CountReportCols implements FlexiSortableColumnDef { name("report.count.name.title"), - count("report.count.count.title"); + count("report.count.count.title"), + percent("report.count.percent.title"); private final String i18nKey; diff --git a/src/main/java/org/olat/modules/forms/ui/CountTableController.java b/src/main/java/org/olat/modules/forms/ui/CountTableController.java index 7b2a4db62f6fd42664c9c00a02bc0493d88a9de3..41f1689a49e43dfdf7188c29f73d9497ccfecb23 100644 --- a/src/main/java/org/olat/modules/forms/ui/CountTableController.java +++ b/src/main/java/org/olat/modules/forms/ui/CountTableController.java @@ -19,18 +19,25 @@ */ package org.olat.modules.forms.ui; +import java.util.List; + import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.CodeHelper; +import org.olat.modules.forms.EvaluationFormManager; import org.olat.modules.forms.ui.CountDataModel.CountReportCols; +import org.olat.modules.forms.ui.component.PercentCellRenderer; import org.olat.modules.forms.ui.model.CountDataSource; +import org.olat.modules.forms.ui.model.CountRatioResult; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -41,6 +48,9 @@ import org.olat.modules.forms.ui.model.CountDataSource; public class CountTableController extends FormBasicController { private final CountDataSource dataSource; + + @Autowired + private EvaluationFormManager evaluationFormManager; public CountTableController(UserRequest ureq, WindowControl wControl, CountDataSource dataSource) { super(ureq, wControl, LAYOUT_HORIZONTAL); @@ -52,10 +62,19 @@ public class CountTableController extends FormBasicController { protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CountReportCols.name)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CountReportCols.count)); + DefaultFlexiColumnModel countModel = new DefaultFlexiColumnModel(CountReportCols.count); + countModel.setAlignment(FlexiColumnModel.ALIGNMENT_RIGHT); + countModel.setHeaderAlignment(FlexiColumnModel.ALIGNMENT_RIGHT); + columnsModel.addFlexiColumnModel(countModel); + DefaultFlexiColumnModel percentModel = new DefaultFlexiColumnModel(CountReportCols.percent, new PercentCellRenderer()); + percentModel.setAlignment(FlexiColumnModel.ALIGNMENT_RIGHT); + percentModel.setHeaderAlignment(FlexiColumnModel.ALIGNMENT_RIGHT); + columnsModel.addFlexiColumnModel(percentModel); CountDataModel dataModel = new CountDataModel(columnsModel); - dataModel.setObjects(dataSource.getResponses()); + + List<CountRatioResult> calculateRatio = evaluationFormManager.calculateRatio(dataSource.getResponses()); + dataModel.setObjects(calculateRatio); FlexiTableElement tableEl = uifactory.addTableElement(getWindowControl(), "counts" + CodeHelper.getRAMUniqueID(), dataModel, getTranslator(), formLayout); tableEl.setNumOfRowsEnabled(false); 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 a2e7c705d9738e4f0d5a95d2950c6c397f9cae5f..d90b57e39b8a3f99bcb1eb78ef8f2eabb33160da 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 @@ -67,6 +67,7 @@ no.response=Keine Antwort m\u00F6glich report.anonymous.user=Anonym report.count.count.title=Anzahl report.count.name.title=Wert +report.count.percent.title=% report.excel.legend=Legende report.excel.text=Text report.export=Export Excel 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 ad67fe4624ccfe05510937b81d9f306cb3ff6a8a..1d2d4e033e439acbf21185fab5f09b07fb6b14f0 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 @@ -66,6 +66,7 @@ no.response=No answer report.anonymous.user=Anonymous report.count.count.title=Count report.count.name.title=Value +report.count.percent.title=% report.excel.legend=Legend report.excel.text=Text report.export=Export Excel diff --git a/src/main/java/org/olat/modules/forms/ui/component/PercentCellRenderer.java b/src/main/java/org/olat/modules/forms/ui/component/PercentCellRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..e0f11c7dc873454d0823754660e9189651d1323d --- /dev/null +++ b/src/main/java/org/olat/modules/forms/ui/component/PercentCellRenderer.java @@ -0,0 +1,46 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.forms.ui.component; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; + +/** + * + * Initial date: 05.02.2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class PercentCellRenderer implements FlexiCellRenderer { + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator translator) { + if(cellValue instanceof Double) { + double percent = ((Double)cellValue).doubleValue() * 100.0d; + long rounded = Math.round(percent); + target.append(rounded).append("%"); + } + } +} diff --git a/src/main/java/org/olat/modules/forms/ui/model/CountRatioResult.java b/src/main/java/org/olat/modules/forms/ui/model/CountRatioResult.java new file mode 100644 index 0000000000000000000000000000000000000000..861ccbd7ebb5f19b8d70f4d63998f102f9724ab3 --- /dev/null +++ b/src/main/java/org/olat/modules/forms/ui/model/CountRatioResult.java @@ -0,0 +1,41 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.forms.ui.model; + +/** + * + * Initial date: 5 Feb 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class CountRatioResult extends CountResult { + + private final Double ratio; + + public CountRatioResult(CountResult countResult, Double ratio) { + super(countResult.getName(), countResult.getCount()); + this.ratio = ratio; + } + + public Double getRatio() { + return ratio; + } + +} diff --git a/src/test/java/org/olat/modules/forms/manager/EvaluationFormMangerImplTest.java b/src/test/java/org/olat/modules/forms/manager/EvaluationFormMangerImplTest.java index 5e00f9ad5bd2dce38bbc80728824b6bab7d5ee04..02dc7a6ea87d6cd0d302c27e83de97dfa122929d 100644 --- a/src/test/java/org/olat/modules/forms/manager/EvaluationFormMangerImplTest.java +++ b/src/test/java/org/olat/modules/forms/manager/EvaluationFormMangerImplTest.java @@ -27,6 +27,11 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; @@ -39,6 +44,8 @@ import org.olat.modules.forms.EvaluationFormSessionStatus; import org.olat.modules.forms.EvaluationFormSurvey; import org.olat.modules.forms.RubricRating; import org.olat.modules.forms.model.xml.Rubric; +import org.olat.modules.forms.ui.model.CountRatioResult; +import org.olat.modules.forms.ui.model.CountResult; import org.olat.repository.RepositoryEntry; /** @@ -284,6 +291,25 @@ public class EvaluationFormMangerImplTest { assertThat(rating).isEqualTo(expectedRating); } + + @Test + public void shouldCalculateRatioList() { + List<CountResult> countResults = new ArrayList<>(); + countResults.add(new CountResult("1", 5)); + countResults.add(new CountResult("2", 5)); + countResults.add(new CountResult("3", 10)); + countResults.add(new CountResult("4", 0)); + + List<CountRatioResult> ratios = sut.calculateRatio(countResults); + + Map<String, Double> percentMap = ratios.stream() + .collect(Collectors.toMap(CountRatioResult::getName, CountRatioResult::getRatio)); + assertThat(percentMap.get("1")).isEqualTo(0.25); + assertThat(percentMap.get("2")).isEqualTo(0.25); + assertThat(percentMap.get("3")).isEqualTo(0.5); + assertThat(percentMap.get("4")).isEqualTo(0); + } + }