From 4f612384f3b5b7467add8718883453bfa405cbc0 Mon Sep 17 00:00:00 2001 From: fkiefer <none@none> Date: Tue, 23 Aug 2016 16:39:08 +0200 Subject: [PATCH] OO-2133 new package org.olat.course.highscore --- .../org/olat/course/_spring/courseContext.xml | 2 +- .../highscore/manager/HighScoreManager.java | 75 +++++ .../highscore/ui/HighScoreController.java | 287 ++++++++++++++++++ .../highscore/ui/HighScoreEditController.java | 215 +++++++++++++ .../ui/HighScoreFlexiTableModel.java | 58 ++++ .../highscore/ui/HighScoreRunController.java | 215 +++++++++++++ .../highscore/ui/HighScoreTableEntry.java | 71 +++++ .../highscore/ui/_content/highscore.html | 183 +++++++++++ .../ui/_content/histogram_score.html | 16 + .../ui/_i18n/LocalStrings_de.properties | 19 ++ .../ui/_i18n/LocalStrings_en.properties | 19 ++ .../nodes/ms/MSCourseNodeEditController.java | 26 +- .../nodes/ms/MSCourseNodeRunController.java | 11 +- .../olat/course/nodes/ms/_content/run.html | 3 + 14 files changed, 1197 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/olat/course/highscore/manager/HighScoreManager.java create mode 100644 src/main/java/org/olat/course/highscore/ui/HighScoreController.java create mode 100644 src/main/java/org/olat/course/highscore/ui/HighScoreEditController.java create mode 100644 src/main/java/org/olat/course/highscore/ui/HighScoreFlexiTableModel.java create mode 100644 src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java create mode 100644 src/main/java/org/olat/course/highscore/ui/HighScoreTableEntry.java create mode 100644 src/main/java/org/olat/course/highscore/ui/_content/highscore.html create mode 100644 src/main/java/org/olat/course/highscore/ui/_content/histogram_score.html create mode 100644 src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_de.properties create mode 100644 src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties diff --git a/src/main/java/org/olat/course/_spring/courseContext.xml b/src/main/java/org/olat/course/_spring/courseContext.xml index aea0913520a..461f7ff2d47 100644 --- a/src/main/java/org/olat/course/_spring/courseContext.xml +++ b/src/main/java/org/olat/course/_spring/courseContext.xml @@ -8,7 +8,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - <context:component-scan base-package="org.olat.course.certificate.manager,org.olat.course.reminder" /> + <context:component-scan base-package="org.olat.course.certificate.manager,org.olat.course.reminder,org.olat.course.highscore" /> <import resource="classpath:/org/olat/course/assessment/_spring/assessmentContext.xml"/> <import resource="classpath:/org/olat/course/certificate/_spring/certificateContext.xml"/> diff --git a/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java b/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java new file mode 100644 index 00000000000..2921bc4ef7d --- /dev/null +++ b/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java @@ -0,0 +1,75 @@ +package org.olat.course.highscore.manager; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.olat.core.id.Identity; +import org.olat.course.highscore.ui.HighScoreTableEntry; +import org.olat.modules.assessment.AssessmentEntry; +import org.olat.user.UserManager; +import org.springframework.stereotype.Service; + +import edu.emory.mathcs.backport.java.util.Collections; + +@Service +public class HighScoreManager { + + + public double[] sortRankByScore (List<AssessmentEntry> assessEntries, + List<HighScoreTableEntry> allMembers, List<HighScoreTableEntry> ownIdMembers, + List<List<HighScoreTableEntry>> allPodium, List<Integer> ownIdIndices, + int tableSize, Identity ownIdentity, UserManager userManager){ + + for (AssessmentEntry assessmentEntry : assessEntries) { + allMembers.add(new HighScoreTableEntry((assessmentEntry.getScore().floatValue()), + userManager.getUserDisplayName(assessmentEntry.getIdentity()), + assessmentEntry.getIdentity())); + } + assessEntries.clear(); + //2 step comparator, sorts by score then own Identity comes first + Collections.sort(allMembers, new Comparator<HighScoreTableEntry>() { + public int compare(HighScoreTableEntry a, HighScoreTableEntry b){ + int answer = Float.compare(b.getScore(), a.getScore()); + if (answer == 0){ + if (a.getIdentity().equals(ownIdentity))return -1; + else if (b.getIdentity().equals(ownIdentity))return 1; + else return 0; + } else { + return answer; + } + } + }); + + float buffer = -1; + int index = 0, rank = 1; + double[] allScores = new double[allMembers.size()]; + for (int j = 0; j < allMembers.size(); j++) { + if (allMembers.get(j).getScore() < buffer){ + index++; + rank = j + 1; + } + //first three position are put in separate lists, + if (index < 3){ + allPodium.get(index).add(allMembers.get(j)); + } + // finding position rank for own id + if (allMembers.get(j).getIdentity().equals(ownIdentity)){ + ownIdIndices.add(j); + } + //setting rank for each member + allMembers.get(j).setRank(rank); + buffer = allMembers.get(j).getScore(); + //adding scores for histogram + allScores[j] = buffer; + } + //only getting member with own id for 2nd table + ownIdMembers.addAll(allMembers.stream() + .skip(tableSize) + .filter(a -> a.getIdentity().equals(ownIdentity)) + .collect(Collectors.toList())); + + return allScores; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/highscore/ui/HighScoreController.java b/src/main/java/org/olat/course/highscore/ui/HighScoreController.java new file mode 100644 index 00000000000..20d722924fd --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/HighScoreController.java @@ -0,0 +1,287 @@ +/** +* OLAT - Online Learning and Training<br> +* http://www.olat.org +* <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 +* <p> +* http://www.apache.org/licenses/LICENSE-2.0 +* <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> +* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> +* University of Zurich, Switzerland. +* <hr> +* <a href="http://www.openolat.org"> +* OpenOLAT - Online Learning and Training</a><br> +* This file has been modified by the OpenOLAT community. Changes are licensed +* under the Apache 2.0 license as the original file. +*/ +package org.olat.course.highscore.ui; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.chart.BarChartComponent; +import org.olat.core.gui.components.chart.BarSeries; +import org.olat.core.gui.components.table.BaseTableDataModelWithoutFilter; +import org.olat.core.gui.components.table.CustomCellRenderer; +import org.olat.core.gui.components.table.DefaultColumnDescriptor; +import org.olat.core.gui.components.table.TableController; +import org.olat.core.gui.components.table.TableGuiConfiguration; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.DefaultController; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.util.Util; +import org.olat.course.groupsandrights.CourseGroupManager; +import org.olat.course.nodes.AssessableCourseNode; +import org.olat.course.nodes.CourseNode; +import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.assessment.AssessmentEntry; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; +import org.olat.repository.RepositoryService; +import org.olat.resource.OLATResource; +import org.olat.user.DisplayPortraitController; +import org.springframework.beans.factory.annotation.Autowired; + +import edu.emory.mathcs.backport.java.util.Arrays; + +public class HighScoreController extends DefaultController{ + + private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(HighScoreController.class); + + private final VelocityContainer myContent; + + protected HighScoreController(UserRequest ureq, WindowControl wControl) { + super(wControl); + Translator fallbackTrans = Util.createPackageTranslator(CourseNode.class, ureq.getLocale()); + + myContent = new VelocityContainer("highscore", VELOCITY_ROOT + "/highscore.html", fallbackTrans, this); + + } + +// Identity markedIdentity = ureq.getIdentity(); +// boolean revealIdentities = false; +// HighScoreController highScoreCtr = new HighScoreController(ureq, wControl, msCourseNode, markedIdentity, revealIdentities); +// myContent.put("highScore", highScoreCtr.getInitialComponent()); + + public HighScoreController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, + AssessableCourseNode courseNode, Identity markedIdentity, boolean revealIdentities) { + super(wControl); + Translator fallbackTrans = Util.createPackageTranslator(CourseNode.class, ureq.getLocale()); + Translator trans = Util.createPackageTranslator(HighScoreController.class, ureq.getLocale(), fallbackTrans); + + String s = VELOCITY_ROOT; + + myContent = new VelocityContainer("highscore", VELOCITY_ROOT + "/highscore.html", trans, this); + +// DisplayPortraitController portrait = new DisplayPortraitController(ureq, wControl, markedIdentity, false, true); +// Component compi = portrait.getInitialComponent(); +// myContent.put("portrait", compi); + + RepositoryEntry entry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); + List<Identity> participants = cgm.getParticipants(); + List<Identity> coaches = cgm.getCoaches(); + //cgm.getParticipantsFromAreas(); + List<Identity> participantz = cgm.getParticipantsFromBusinessGroups(); + List<AssessmentEntry> assessEntries = userCourseEnv.getCourseEnvironment().getAssessmentManager().getAssessmentEntries(courseNode); + + List<HighScoreTableEntry> members = new ArrayList<>(); + List<HighScoreTableEntry> members2 = new ArrayList<>(); + Identity ownIdentity = ureq.getIdentity(); + + for (AssessmentEntry assessmentEntry : assessEntries) { + members.add(new HighScoreTableEntry((int)(assessmentEntry.getScore().floatValue() * 10), + assessmentEntry.getIdentity().getName(), assessmentEntry.getIdentity())); + } + +// for (Identity identity : participants) { +// if (participants.indexOf(identity) < 5) { +// members.add(new TableEntry((int)(Math.random()*100), identity.getName(), identity)); +//// } else if (participants.indexOf(identity) > 2 && ownIdentity.getKey().equals(identity.getKey())){ +//// members2.add(new TableEntry((int)(Math.random()*100), identity.getName(), identity)); +// } +// } + + members = members.stream() + .sorted((a,b) -> Float.compare(b.getScore(),a.getScore())) + .collect(Collectors.toList()); + + members2 = members.stream() + .skip(2) + .filter(a -> a.getIdentity().equals(ownIdentity)) + .collect(Collectors.toList()); + + final List<HighScoreTableEntry> members3 = members; + int[] indices = IntStream.range(0, members.size()) + .filter(i -> members3.get(i).getIdentity().equals(ownIdentity)) + .toArray(); + + members = members.stream() + .limit(4) + .collect(Collectors.toList()); + + + String[] localizer = { "first", "second", "third" }; + for (int i = 0; i < localizer.length; i++) { + myContent.contextPut(localizer[i], (members.size() > i) ? members.get(i).getName() : ""); + myContent.contextPut("score" + (i + 1), (members.size() > i) ? members.get(i).getScore() : ""); + if (members.size() > i) { + DisplayPortraitController portrait = new DisplayPortraitController(ureq, wControl, + members.get(i).getIdentity(), false, true); + Component compi = portrait.getInitialComponent(); + myContent.put("portrait" + (i + 1), compi); + } + } +// myContent.contextPut("first", (members.size()>0)?members.get(0).getName():""); +// myContent.contextPut("second", (members.size()>1)?members.get(1).getName():""); +// myContent.contextPut("third", (members.size()>2)?members.get(2).getName():""); +// BarChartComponent barchart = new BarChartComponent("barchart"); +// barchart.addSeries(new BarSeries()); + + BarChartComponent chartCmp = new BarChartComponent("stat"); + List<String> labels = Arrays.asList(new String[]{"eins","zwei","drei","vier"}); + List<Integer> values = Arrays.asList(new Integer[]{12,55,33,24}); + BarSeries serie = new BarSeries(); + for(int i=0; i<labels.size(); i++) { + double value = values.get(i).doubleValue(); + String category = labels.get(i); + serie.add(value, category); + } + chartCmp.addSeries(serie); + + myContent.put("barchart", chartCmp); + + TableGuiConfiguration tgc = new TableGuiConfiguration(); + tgc.setPreferencesOffered(true, "TableGuiDemoPrefs"); + TableController table = new TableController(tgc, ureq, getWindowControl(), trans); + + TableGuiConfiguration tgc2 = new TableGuiConfiguration(); + tgc2.setPreferencesOffered(true, "TableGuiDemoPrefs"); + TableController table2 = new TableController(tgc2, ureq, getWindowControl(), trans); + + TableController[] tables = {table,table2}; + for (int i = 0; i < tables.length; i++) { + for (int j = 0; j < 3; j++) { + tables[i].addColumnDescriptor( + new DefaultColumnDescriptor("highscore.table.header" + (j+1), j, null, ureq.getLocale())); + } + } + + +// table.addColumnDescriptor(new DefaultColumnDescriptor("highscore.table.header1", 0, null, ureq.getLocale())); +// table.addColumnDescriptor(new DefaultColumnDescriptor("highscore.table.header2", 1, null, ureq.getLocale())); +// table.addColumnDescriptor(new DefaultColumnDescriptor("highscore.table.header3", 2, null, ureq.getLocale())); +// table.addColumnDescriptor(new DefaultColumnDescriptor("guidemo.table.header4", 3, null, ureq.getLocale())); +// table.addColumnDescriptor(new DefaultColumnDescriptor("guidemo.table.header5", 4, null, ureq.getLocale())); +// table.addColumnDescriptor(new CustomRenderColumnDescriptor("guidemo.table.header6", 5, null, ureq.getLocale(), +// CustomRenderColumnDescriptor.ALIGNMENT_CENTER, new ImageCellRenderer())); + + table.setTableDataModel(new SampleTableModel(members,0)); + myContent.put("table", table.getInitialComponent()); + + if(!members2.isEmpty()){ + table2.setTableDataModel(new SampleTableModel(members2,indices[0])); + myContent.put("table2", table2.getInitialComponent()); + } + setInitialComponent(myContent); + + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // TODO Auto-generated method stub + + } + + @Override + protected void doDispose() { + // TODO Auto-generated method stub + + } + +} +class SampleTableModel extends BaseTableDataModelWithoutFilter<java.util.List<Object>> { + @Autowired + private RepositoryManager repositoryManager; + + private int COLUMN_COUNT = 3; + private List<List<Object>> entries; + + + public SampleTableModel(List<HighScoreTableEntry> members, int rank) { + + RepositoryManager rm = RepositoryManager.getInstance(); + RepositoryService rs = CoreSpringFactory.getImpl(RepositoryService.class); + + RepositoryEntry entry = rm.lookupRepositoryEntry(34570267L); + + List<OLATResource> resourcesForReservations = new ArrayList<>(); + if(entry != null) { + resourcesForReservations.add(entry.getOlatResource()); + } + +// List<ResourceReservation> reservations = acService.getReservations(resourcesForReservations); + +// List<TableEntry> members = new ArrayList<TableEntry>(); +// members.add(new TableEntry(22,"Fabian Kiefer")); +// members.add(new TableEntry(11,"Flad Käfer")); +// members.add(new TableEntry(17,"Stefanie Müller")); +// members.add(new TableEntry(35,"Heinrich Kiefer")); +// members.add(new TableEntry(17,"Frentix Uzzer")); + + + + + int iEntries = members.size() <= 10 ? members.size() : 10; + this.entries = new ArrayList<List<Object>>(iEntries); + for (int i=0; i < iEntries; i++) { + List<Object> row = new ArrayList<Object>(3); + row.add(rank != 0 ? rank+1 : Integer.toString(i+1)); + row.add(Float.toString(members.get(i).getScore())); + row.add(members.get(i).getName()); +// row.add(""); + entries.add(row); + } + } + + public int getColumnCount() { + return COLUMN_COUNT; + } + + public int getRowCount() { + return entries.size(); + } + + public Object getValueAt(int row, int col) { + List<Object> entry = entries.get(row); + return entry.get(col); + } +} +class ImageCellRenderer implements CustomCellRenderer { + + public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) { + sb.append("<img src=\""); + Renderer.renderStaticURI(sb, "images/openolat/openolat_logo_16.png"); + sb.append("\" alt=\"An image within a table...\" />"); + } + +} diff --git a/src/main/java/org/olat/course/highscore/ui/HighScoreEditController.java b/src/main/java/org/olat/course/highscore/ui/HighScoreEditController.java new file mode 100644 index 00000000000..bc0da630439 --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/HighScoreEditController.java @@ -0,0 +1,215 @@ +package org.olat.course.highscore.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.SelectionElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.course.nodes.CourseNode; +import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.ModuleConfiguration; + +public class HighScoreEditController extends FormBasicController { + + private final static String[] yesOrNoKeys = new String[] { "highscore.all", "highscore.bestonly" }; + + /** configuration: boolean has a podium */ + public static final String CONFIG_KEY_HIGHSCORE= "allowHighscore"; + /** configuration: boolean has a podium */ + public static final String CONFIG_KEY_PODIUM = "podium"; + /** configuration: boolean has a histogram */ + public static final String CONFIG_KEY_HISTOGRAM = "histogram"; + /** configuration: boolean has a listing */ + public static final String CONFIG_KEY_LISTING = "listing"; + /** configuration: boolean bestonly or all */ + public static final String CONFIG_KEY_BESTONLY = "bestOnly"; + /** configuration: integer size of table */ + public static final String CONFIG_KEY_NUMUSER = "numUser"; + /** configuration: boolean anonymize */ + public static final String CONFIG_KEY_ANONYMIZE = "anonymize"; + + private SingleSelection horizontalRadioButtons; + private SelectionElement allowHighScore; + private SelectionElement showPodium; + private SelectionElement showHistogram; + private SelectionElement showListing; + private SelectionElement displayAnonymous; + private TextElement numTableRows; + private CourseNode msNode; + private ModuleConfiguration config; + + public HighScoreEditController(UserRequest ureq, WindowControl wControl, CourseNode msNode, UserCourseEnvironment euce) { + super(ureq, wControl, FormBasicController.LAYOUT_DEFAULT); + this.msNode = msNode; + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + + allowHighScore = uifactory.addCheckboxesHorizontal("highscore.show", formLayout, new String[] { "xx" }, + new String[] { null }); + allowHighScore.addActionListener(FormEvent.ONCLICK); + allowHighScore.select("xx", true); + + uifactory.addSpacerElement("spacer", formLayout, false); + + showPodium = uifactory.addCheckboxesHorizontal("highscore.podium", formLayout, new String[] { "xx" }, + new String[] { null }); + showHistogram = uifactory.addCheckboxesHorizontal("highscore.histogram", formLayout, new String[] { "xx" }, + new String[] { null }); + showListing = uifactory.addCheckboxesHorizontal("highscore.listing", formLayout, new String[] { "xx" }, + new String[] { null }); + showListing.addActionListener(FormEvent.ONCLICK); + + // Translate the keys to the yes and no option values + final String[] yesOrNoOptions = new String[yesOrNoKeys.length]; + for (int i = 0; i < yesOrNoKeys.length; i++) { + yesOrNoOptions[i] = translate(yesOrNoKeys[i]); + } + horizontalRadioButtons = uifactory.addRadiosHorizontal("highscore.void", formLayout, yesOrNoKeys, + yesOrNoOptions); + // A default value is needed for show/hide rules + horizontalRadioButtons.select(yesOrNoKeys[1], true); + horizontalRadioButtons.addActionListener(FormEvent.ONCLICK);//why + + numTableRows = uifactory.addTextElement("textField", "highscore.tablesize", 4, "10", formLayout); + numTableRows.setMandatory(true); + numTableRows.setNotEmptyCheck("highscore.emptycheck"); + + displayAnonymous = uifactory.addCheckboxesHorizontal("highscore.anonymize", formLayout, new String[] { "xx" }, new String[] { null }); + + // Create submit and cancel buttons + final FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttonLayout", + getTranslator()); + formLayout.add(buttonLayout); + uifactory.addFormSubmitButton("submit", buttonLayout); + uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl()); + + setFromConfig(); + } + + @Override + protected void formInnerEvent (UserRequest ureq, FormItem source, FormEvent event) { + if (source == allowHighScore){ + activateForm(false); + } else if (source == showListing){ + activateListing(); + } else if (source == horizontalRadioButtons){ + activateTopUsers(); + } + } + + private void setFromConfig() { + config = msNode.getModuleConfiguration(); + boolean allowhighscore = config.getBooleanSafe(CONFIG_KEY_HIGHSCORE); + allowHighScore.select("xx", allowhighscore); + showPodium.select("xx", config.getBooleanSafe(CONFIG_KEY_PODIUM)); + showHistogram.select("xx", config.getBooleanSafe(CONFIG_KEY_HISTOGRAM)); + boolean listing = config.getBooleanSafe(CONFIG_KEY_LISTING); + showListing.select("xx", listing); + int showAll = (int) config.get(CONFIG_KEY_BESTONLY); + horizontalRadioButtons.select(yesOrNoKeys[showAll], true); + if (showAll == 0 || !listing) { + numTableRows.setVisible(false); + } + displayAnonymous.setVisible(listing); + horizontalRadioButtons.setVisible(listing); + numTableRows.setValue(config.get(CONFIG_KEY_NUMUSER).toString()); + activateForm(true); + } + + private void activateForm (boolean init){ + boolean formactive = allowHighScore.isSelected(0); + SelectionElement[] checkboxes = {showPodium,showHistogram,showListing,displayAnonymous}; + for (int i = 0; i < checkboxes.length; i++) { + checkboxes[i].setEnabled(formactive); + if (!init) { + checkboxes[i].select("xx", i != 3 ? formactive : false); + } + } + if (!init) { + displayAnonymous.setVisible(formactive); + horizontalRadioButtons.setVisible(formactive); + horizontalRadioButtons.select(yesOrNoKeys[1], true); + numTableRows.setVisible(formactive); + } + } + + private void activateListing() { + boolean listingactive = showListing.isSelected(0); + displayAnonymous.setVisible(listingactive); + horizontalRadioButtons.setVisible(listingactive); + horizontalRadioButtons.select(yesOrNoKeys[1], true); + numTableRows.setVisible(listingactive); + } + + private void activateTopUsers() { + int all = horizontalRadioButtons.getSelected(); + numTableRows.setVisible(all != 0); + } + + public void updateModuleConfiguration(ModuleConfiguration moduleConfiguration) { + moduleConfiguration.set(CONFIG_KEY_HIGHSCORE, allowHighScore.isSelected(0)); + moduleConfiguration.set(CONFIG_KEY_PODIUM, showPodium.isSelected(0)); + moduleConfiguration.set(CONFIG_KEY_HISTOGRAM, showHistogram.isSelected(0)); + moduleConfiguration.set(CONFIG_KEY_LISTING, showListing.isSelected(0)); + if (showListing.isSelected(0)) { + moduleConfiguration.set(CONFIG_KEY_ANONYMIZE, displayAnonymous.isSelected(0)); + moduleConfiguration.set(CONFIG_KEY_BESTONLY, horizontalRadioButtons.getSelected()); + moduleConfiguration.set(CONFIG_KEY_NUMUSER, convertToInteger(numTableRows.getValue())); + } + } + + public static int convertToInteger(String str) { + if (str == null) { + return 10; + } + int length = str.length(); + if (length == 0) { + return 10; + } + int i = 0; + if (str.charAt(0) == '-') { + if (length == 1) { + return 10; + } + i = 1; + } + for (; i < length; i++) { + char c = str.charAt(i); + if (c < '0' || c > '9') { + return 10; + } + } + return Integer.valueOf(str); + } + + + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, Event.DONE_EVENT); + } + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } + + @Override + protected void doDispose() { + // TODO Auto-generated method stub + + } + + + +} diff --git a/src/main/java/org/olat/course/highscore/ui/HighScoreFlexiTableModel.java b/src/main/java/org/olat/course/highscore/ui/HighScoreFlexiTableModel.java new file mode 100644 index 00000000000..e505ade2ad5 --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/HighScoreFlexiTableModel.java @@ -0,0 +1,58 @@ +package org.olat.course.highscore.ui; + +import java.util.List; + +import org.olat.core.gui.components.table.TableDataModel; + +public class HighScoreFlexiTableModel implements TableDataModel<HighScoreTableEntry> { + + private final int COLUMN_COUNT = 3; + private final int ROW_COUNT; + private final List<HighScoreTableEntry> entries; + + public HighScoreFlexiTableModel(List<HighScoreTableEntry> entries) { + this.ROW_COUNT = entries.size(); + this.entries = entries; + } + + @Override + public int getColumnCount() { + return COLUMN_COUNT; + } + + @Override + public int getRowCount() { + return ROW_COUNT; + } + + @Override + public Object getValueAt(int row, int col) { + HighScoreTableEntry entry = entries.get(row); + switch(col) { + case 0: return entry.getRank(); + case 1: return entry.getScore(); + case 2: return entry.getName(); + default: return entry; + } + } + + @Override + public HighScoreTableEntry getObject(int row) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setObjects(List objects) { + // TODO Auto-generated method stub + + } + + @Override + public Object createCopyWithEmptyList() { + // TODO Auto-generated method stub + return null; + } + + +} diff --git a/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java b/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java new file mode 100644 index 00000000000..b09f5609a9a --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java @@ -0,0 +1,215 @@ +/** +* OLAT - Online Learning and Training<br> +* http://www.olat.org +* <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 +* <p> +* http://www.apache.org/licenses/LICENSE-2.0 +* <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> +* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> +* University of Zurich, Switzerland. +* <hr> +* <a href="http://www.openolat.org"> +* OpenOLAT - Online Learning and Training</a><br> +* This file has been modified by the OpenOLAT community. Changes are licensed +* under the Apache 2.0 license as the original file. +*/ +package org.olat.course.highscore.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.chart.BarSeries; +import org.olat.core.gui.components.chart.StatisticsComponent; +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.FormLayoutContainer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableCssDelegate; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelImpl; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.course.highscore.manager.HighScoreManager; +import org.olat.course.nodes.CourseNode; +import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.AssessmentEntry; +import org.olat.user.DisplayPortraitController; +import org.olat.user.UserAvatarMapper; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; + + +public class HighScoreRunController extends FormBasicController{ + + private FlexiTableDataModel<HighScoreTableEntry> tableDataModel, tableDataModel2; + private List<HighScoreTableEntry> allMembers, ownIdMembers; + private List<List<HighScoreTableEntry>> allPodium; + private List<Integer> ownIdIndices; + private int tableSize; + private Identity ownIdentity; + private boolean viewTable, viewHistogram, viewPodium, viewHighscore; + private double[] allScores; + + @Autowired + private HighScoreManager highScoreManager; + @Autowired + private UserManager userManager; + + + public HighScoreRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, + CourseNode courseNode) { + super(ureq, wControl, "highscore"); + + List<AssessmentEntry> assessEntries = userCourseEnv.getCourseEnvironment() + .getAssessmentManager().getAssessmentEntries(courseNode); + + ModuleConfiguration config = courseNode.getModuleConfiguration(); + //TODO initialize + viewHighscore = config.getBooleanSafe(HighScoreEditController.CONFIG_KEY_HIGHSCORE); + if (!viewHighscore)return; + viewTable = config.getBooleanSafe(HighScoreEditController.CONFIG_KEY_LISTING); + viewHistogram = config.getBooleanSafe(HighScoreEditController.CONFIG_KEY_HISTOGRAM); + viewPodium = config.getBooleanSafe(HighScoreEditController.CONFIG_KEY_PODIUM); + int bestOnly = (int) config.get(HighScoreEditController.CONFIG_KEY_BESTONLY); + tableSize = bestOnly != 0 ? (int) config.get(HighScoreEditController.CONFIG_KEY_NUMUSER) : assessEntries.size(); + ownIdentity = ureq.getIdentity(); + initLists(); + + allScores = highScoreManager.sortRankByScore(assessEntries, allMembers, ownIdMembers, + allPodium, ownIdIndices, tableSize, ownIdentity, userManager); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + + VelocityContainer mainVC = ((FormLayoutContainer) formLayout).getFormItemComponent(); + mainVC.put("loadd3js", new StatisticsComponent("d3loader")); + + if (viewHistogram) { + VelocityContainer scoreHistogramVC = createVelocityContainer("histogram_score"); + scoreHistogramVC.contextPut("datas", BarSeries.datasToString(allScores)); + scoreHistogramVC.contextPut("cutValue", + ownIdIndices.size() > 0 ? allMembers.get(ownIdIndices.get(0)).getScore() : ""); + + UserAvatarMapper mapper = new UserAvatarMapper(false); + String mapperPath = registerMapper(ureq, mapper); + String identityMapperPath = mapper.createPathFor(mapperPath, ownIdentity); + scoreHistogramVC.contextPut("mapperUrl", identityMapperPath); + + mainVC.put("scoreHistogram", scoreHistogramVC); + } + if (viewPodium) { + String[] localizer = { "first", "second", "third" }; + for (int i = 0; i < localizer.length; i++) { + StringBuilder sb = new StringBuilder(); + for (HighScoreTableEntry te : allPodium.get(i)) { + sb.append(te.getName()); + sb.append("</br>"); + } + mainVC.contextPut(localizer[i], allPodium.get(i).size() > 0 ? sb.toString() : "") ; + mainVC.contextPut("score" + (i + 1), allPodium.get(i).size() > 0 ? + allPodium.get(i).get(0).getScore() : ""); + if (tableSize > i) { + DisplayPortraitController portrait = new DisplayPortraitController(ureq, getWindowControl(), + allPodium.get(i).get(0).getIdentity(), i == 0, true); + Component compi = portrait.getInitialComponent(); + mainVC.put("portrait" + (i + 1), compi); + } + } + } + if (viewTable) { + FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + tableColumnModel.addFlexiColumnModel( + new DefaultFlexiColumnModel("highscore.table.header1", HighScoreTableEntry.RANK)); + tableColumnModel.addFlexiColumnModel( + new DefaultFlexiColumnModel("highscore.table.header2", HighScoreTableEntry.SCORE)); + tableColumnModel.addFlexiColumnModel( + new DefaultFlexiColumnModel("highscore.table.header3", HighScoreTableEntry.NAME)); + + //trim to tableSize + allMembers.subList(tableSize, allMembers.size()).clear(); + + tableDataModel = new FlexiTableDataModelImpl<HighScoreTableEntry>( + new HighScoreFlexiTableModel(allMembers), tableColumnModel); + FlexiTableElement topTenTable = uifactory.addTableElement( + getWindowControl(), "table", tableDataModel, getTranslator(), formLayout); + topTenTable.setNumOfRowsEnabled(false); + topTenTable.setCustomizeColumns(false); + topTenTable.setCssDelegate(new MarkedMemberCssDelegate(false)); + + + if (!ownIdMembers.isEmpty()) { + tableDataModel2 = new FlexiTableDataModelImpl<HighScoreTableEntry>( + new HighScoreFlexiTableModel(ownIdMembers), + tableColumnModel); + FlexiTableElement tableElement = uifactory.addTableElement( + getWindowControl(), "table2", tableDataModel2, getTranslator(), formLayout); + tableElement.setNumOfRowsEnabled(false); + tableElement.setCustomizeColumns(false); + tableElement.setCssDelegate(new MarkedMemberCssDelegate(true)); + } + } + + } + + private void initLists(){ + ownIdIndices = new ArrayList<>(); + allMembers = new ArrayList<>(); + ownIdMembers = new ArrayList<>(); + allPodium = new ArrayList<>(); + allPodium.add(new ArrayList<>()); + allPodium.add(new ArrayList<>()); + allPodium.add(new ArrayList<>()); + } + + @Override + protected void formOK(UserRequest ureq) { + // TODO Auto-generated method stub + + } + + @Override + protected void doDispose() { + // TODO Auto-generated method stub + + } + + private class MarkedMemberCssDelegate extends DefaultFlexiTableCssDelegate { + private boolean mark; + public MarkedMemberCssDelegate(boolean mark) { + this.mark = mark; + } + @Override + public String getRowCssClass(FlexiTableRendererType type, int pos) { + return ownIdIndices.get(0) < tableSize && pos == ownIdIndices.get(0) || mark ? "o_row_selected" : null; + } + } + + public boolean isViewHighscore() { + return viewHighscore; + } + + + +} + diff --git a/src/main/java/org/olat/course/highscore/ui/HighScoreTableEntry.java b/src/main/java/org/olat/course/highscore/ui/HighScoreTableEntry.java new file mode 100644 index 00000000000..9c57275d50e --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/HighScoreTableEntry.java @@ -0,0 +1,71 @@ +/** +* OLAT - Online Learning and Training<br> +* http://www.olat.org +* <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 +* <p> +* http://www.apache.org/licenses/LICENSE-2.0 +* <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> +* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> +* University of Zurich, Switzerland. +* <hr> +* <a href="http://www.openolat.org"> +* OpenOLAT - Online Learning and Training</a><br> +* This file has been modified by the OpenOLAT community. Changes are licensed +* under the Apache 2.0 license as the original file. +*/ +package org.olat.course.highscore.ui; + +import org.olat.core.id.Identity; + +public class HighScoreTableEntry { + + public static int RANK = 0; + public static int SCORE = 1; + public static int NAME = 2; + + private float score; + private String name; + private Identity identity; + private int rank; + + public HighScoreTableEntry(float score, String name, Identity identity){ + this.score = score; + this.name = name; + this.identity = identity; + } + + public float getScore (){ + return score; + } + public String getName(){ + return name; + } + public Identity getIdentity() { + return identity; + } + public int getRank() { + return rank; + } + public void setScore(float score) { + this.score = score; + } + public void setName(String name) { + this.name = name; + } + public void setIdentity(Identity identity) { + this.identity = identity; + } + public void setRank(int rank) { + this.rank = rank; + } + +} diff --git a/src/main/java/org/olat/course/highscore/ui/_content/highscore.html b/src/main/java/org/olat/course/highscore/ui/_content/highscore.html new file mode 100644 index 00000000000..3e398ff8b68 --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/_content/highscore.html @@ -0,0 +1,183 @@ +<style> +.line { + fill: none; + stroke: steelblue; + stroke-width: 2px; +} + + +.o_podium { + position: relative; + vertical-align: bottom; + height: 300px; + margin-bottom: 50px; +} + +.o_step { + width: 30%; + position: absolute; + bottom: 0; +} +.o_step:before { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + text-align: center; +} + +.o_step .o_name { + position: absolute; + top: 100%; + width: 100%; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 1em; +} + +.o_step .o_score { + width: 100%; + text-align: center; + position: absolute; + top: -20px; +} + +.o_first { + height: 150px; + background-color: gold; + left: 30%; +} +.o_first:before { + content: "1"; + font-size: 700%; +} + +.o_second { + height: 100px; + background-color: silver; + left: 0; +} +.o_second:before { + content: "2"; + font-size: 500%; +} + +.o_third { + height: 80px; + background-color: #965A38; + left: 60%; +} + +.o_third:before { + content: "3"; + font-size: 300%; +} + +.o_step .o_portrait { + position: absolute; + width: 100%; + text-align: center; +} +.o_step.o_first .o_portrait { + top: -125px; +} +.o_step.o_second .o_portrait { + top: -70px; +} +.o_step.o_second .o_portrait .o_portrait_avatar_small, +.o_step.o_second .o_portrait .o_portrait_dummy_small, +.o_step.o_second .o_portrait .o_portrait_dummy_female_small, +.o_step.o_second .o_portrait .o_portrait_dummy_male_small, +.o_step.o_second .o_portrait .o_portrait_anonymous_small { + width: 50px; + height: 50px; +} + +.o_step.o_third .o_portrait { + top: -50px; +} + +.o_histogram { + position: relative; + bottom: -40px; + margin-bottom: 40px; +} +.o_histogram .d3chart { + width: 100%; + padding-top: 50px; + height: 300px; +} + +.o_histogram .d3chart .axis path, +.o_histogram .d3chart .axis line { + stroke: #888; +} +.o_histogram .d3chart text { + fill: #888; +} + +/* Align both tables the same way */ +.o_listing table th:nth-of-type(1), +.o_listing table th:nth-of-type(2) { + width: 5em; +} + +</style> + + +<div class="panel panel-default o_comment"> + <div class="panel-heading" data-toggle="collapse" + data-target="#collapseComment"> + <h4 class="panel-title"> + <i id="collapseCommentToggler" + class="o_icon o_icon-fw o_icon_close_togglebox"> </i> + $r.translate("highscore.title") + </h4> + </div> + <div id="collapseComment" class="panel-collapse collapse in"> + <div class="panel-body"> + <div class="container-fluid"> + <div class="row clearfix"> + #if ($first) + <div class="col-sm-6 o_podium"> + <div class="o_step o_first"> + #if ($r.available("portrait1")) $r.render("portrait1") #end + <div class="o_name">$first</div> + <div class="o_score">$score1 $r.translate("graph.axis.points")</div> + </div> + + <div class="o_step o_second"> + #if ($r.available("portrait2")) $r.render("portrait2") #end + <div class="o_name">$second</div> + <div class="o_score">$score2 $r.translate("graph.axis.points")</div> + </div> + + <div class="o_step o_third"> + #if ($r.available("portrait3")) $r.render("portrait3") #end + <div class="o_name">$third</div> + <div class="o_score">$score3 $r.translate("graph.axis.points")</div> + </div> + + </div> + #end + + #if ($r.available("scoreHistogram")) + <div class="col-sm-6 o_histogram"> + $r.render("scoreHistogram") + </div> + #end + + </div> + </div> + #if ($r.available("table")) + <div class="o_listing"> + <h4>$r.translate("highscore.title")</h4> + $r.render("table") + #if ($r.available("table2")) $r.render("table2") #end + </div> + #end + </div> + </div> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/course/highscore/ui/_content/histogram_score.html b/src/main/java/org/olat/course/highscore/ui/_content/histogram_score.html new file mode 100644 index 00000000000..5291b3bf04c --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/_content/histogram_score.html @@ -0,0 +1,16 @@ +<div id='histogram_$r.getCId()' class='d3chart'> + +<script type='text/javascript'> +/* <![CDATA[ */ +jQuery(function () { + jQuery('#histogram_$r.getCId()').qtiStatistics('highScore', { + values: [$datas], + cut: #if($cutValue) $cutValue #else null #end, + mapperUrl: '$mapperUrl', + xBottomLegend: '$r.translate("graph.axis.points")', + yLeftLegend: '$r.translate("graph.axis.percent")', + yRightLegend: '$r.translate("graph.axis.absolute")' + }); +}); +/* ]]> */</script> +</div> diff --git a/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_de.properties new file mode 100644 index 00000000000..c328827ee01 --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_de.properties @@ -0,0 +1,19 @@ +#Mon Aug 15 11:26:04 CET 2016 +highscore.table.header1=Rang +highscore.table.header2=Punkte +highscore.table.header3=Name +graph.axis.points=Punkte +graph.axis.percent=Prozent +graph.axis.absolute=Absolut +highscore.title=Highscore +pane.tab.highscore=HighScore +highscore.podium=Siegertreppchen +highscore.histogram=Histogramm +highscore.listing=Auflistung +highscore.show=Highscore anzeigen +highscore.all=alle +highscore.bestonly=beste Benutzer anzeigen +highscore.void= +highscore.tablesize=Anzahl bester Benutzer +highscore.anonymize=Anonymisieren +highscore.emptycheck=Dieses Textfeld darf nicht leer sein! \ No newline at end of file diff --git a/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties new file mode 100644 index 00000000000..6abeaa64b4f --- /dev/null +++ b/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties @@ -0,0 +1,19 @@ +#Mon Aug 15 11:26:04 CET 2016 +highscore.table.header1=Rank +highscore.table.header2=Score +highscore.table.header3=Name +graph.axis.points=Points +graph.axis.percent=Percent +graph.axis.absolute=Absolute +highscore.title=Highscore +pane.tab.highscore=HighScore +highscore.podium=Podium +highscore.histogram=Histogram +highscore.listing=Listing +highscore.show=Show Highscore +highscore.all=all +highscore.bestonly=show top users +highscore.void= +highscore.tablesize=Number of top users +highscore.anonymize=Anonymize +highscore.emptycheck=This Textfield must not be empty! \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java index ac28cc7a9f0..07a82d213a8 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java @@ -36,12 +36,14 @@ import org.olat.core.gui.control.ControllerEventListener; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultController; +import org.olat.core.util.Util; import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.condition.Condition; import org.olat.course.condition.ConditionEditController; import org.olat.course.editor.NodeEditController; +import org.olat.course.highscore.ui.HighScoreEditController; import org.olat.course.nodes.MSCourseNode; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.tree.CourseEditorTreeModel; @@ -53,12 +55,14 @@ import org.olat.course.tree.CourseEditorTreeModel; public class MSCourseNodeEditController extends ActivateableTabbableDefaultController implements ControllerEventListener { public static final String PANE_TAB_CONFIGURATION = "pane.tab.configuration"; - private static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility"; + private static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility"; + public static final String PANE_TAB_HIGHSCORE = "pane.tab.highscore"; private static final String[] paneKeys = { PANE_TAB_CONFIGURATION, PANE_TAB_ACCESSIBILITY }; private MSCourseNode msNode; private VelocityContainer configurationVC; private MSEditFormController modConfigController; + private HighScoreEditController highScoreNodeConfigController; private ConditionEditController accessibilityCondContr; private TabbedPane myTabbedPane; @@ -75,6 +79,8 @@ public class MSCourseNodeEditController extends ActivateableTabbableDefaultContr */ public MSCourseNodeEditController(UserRequest ureq, WindowControl wControl, MSCourseNode msNode, ICourse course, UserCourseEnvironment euce) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(HighScoreEditController.class, getLocale(), getTranslator())); + this.msNode = msNode; configurationVC = createVelocityContainer("edit"); @@ -93,6 +99,9 @@ public class MSCourseNodeEditController extends ActivateableTabbableDefaultContr listenTo(modConfigController); configurationVC.put("mseditform", modConfigController.getInitialComponent()); + highScoreNodeConfigController = new HighScoreEditController(ureq, wControl, msNode, euce); + listenTo(highScoreNodeConfigController); + // if there is already user data available, make for read only //TODO:chg:a concurrency issues? hasLogEntries = auditManager.hasUserNodeLogs(msNode); @@ -146,8 +155,20 @@ public class MSCourseNodeEditController extends ActivateableTabbableDefaultContr modConfigController.updateModuleConfiguration(msNode.getModuleConfiguration()); fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); } + updateHighscoreTab(); + + } else if (source == highScoreNodeConfigController){ + if (event == Event.DONE_EVENT) { + highScoreNodeConfigController.updateModuleConfiguration(msNode.getModuleConfiguration()); + fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); + } } } + + private void updateHighscoreTab() { + Boolean sf = msNode.getModuleConfiguration().getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD,false); + myTabbedPane.setEnabled(4, sf); + } /** * @see org.olat.core.gui.control.generic.tabbable.TabbableDefaultController#addTabs(org.olat.core.gui.components.TabbedPane) @@ -156,6 +177,9 @@ public class MSCourseNodeEditController extends ActivateableTabbableDefaultContr myTabbedPane = tabbedPane; tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), accessibilityCondContr.getWrappedDefaultAccessConditionVC(translate("condition.accessibility.title"))); tabbedPane.addTab(translate(PANE_TAB_CONFIGURATION), configurationVC); + tabbedPane.addTab(translate(PANE_TAB_HIGHSCORE) , highScoreNodeConfigController.getInitialComponent()); + updateHighscoreTab(); + } /** diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java index 48ba90a8ada..6a78ff32be4 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java @@ -37,6 +37,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.auditing.UserNodeAuditManager; +import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.ObjectivesHelper; @@ -74,7 +75,15 @@ public class MSCourseNodeRunController extends DefaultController { Translator trans = Util.createPackageTranslator(MSCourseNodeRunController.class, ureq.getLocale(), fallbackTrans); myContent = new VelocityContainer("olatmsrun", VELOCITY_ROOT + "/run.html", trans, this); - + + if (msCourseNode.getModuleConfiguration().getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD,false)){ + HighScoreRunController highScoreCtr = new HighScoreRunController(ureq, wControl, userCourseEnv, msCourseNode); + if (highScoreCtr.isViewHighscore()) { + Component compi = highScoreCtr.getInitialComponent(); + myContent.put("highScore", compi); + } + } + ModuleConfiguration config = msCourseNode.getModuleConfiguration(); myContent.contextPut("displayNodeInfo", Boolean.valueOf(displayNodeInfo)); if (displayNodeInfo) { diff --git a/src/main/java/org/olat/course/nodes/ms/_content/run.html b/src/main/java/org/olat/course/nodes/ms/_content/run.html index 20bab52534a..2f4139e7741 100644 --- a/src/main/java/org/olat/course/nodes/ms/_content/run.html +++ b/src/main/java/org/olat/course/nodes/ms/_content/run.html @@ -99,6 +99,9 @@ </script> #end +#if ($r.available("highScore")) + $r.render("highScore") +#end #if($log) <div class="o_box"> -- GitLab