Skip to content
Snippets Groups Projects
Commit e4e89268 authored by srosse's avatar srosse
Browse files

OO-3770: implements an overview of a QTI 2.1 test configuration

parent 53109bab
No related branches found
No related tags found
No related merge requests found
Showing
with 1168 additions and 3 deletions
......@@ -30,6 +30,9 @@ import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
......@@ -51,6 +54,7 @@ import org.olat.ims.qti21.model.xml.interactions.UploadAssessmentItemBuilder;
import org.olat.ims.qti21.ui.AssessmentItemDisplayController;
import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent;
import org.olat.ims.qti21.ui.editor.events.DetachFromPoolEvent;
import org.olat.ims.qti21.ui.editor.events.SelectEvent.SelectionTarget;
import org.olat.ims.qti21.ui.editor.interactions.ChoiceScoreController;
import org.olat.ims.qti21.ui.editor.interactions.DrawingEditorController;
import org.olat.ims.qti21.ui.editor.interactions.EssayEditorController;
......@@ -83,7 +87,7 @@ import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentItemEditorController extends BasicController {
public class AssessmentItemEditorController extends BasicController implements Activateable2 {
private final AssessmentItemRef itemRef;
private final ResolvedAssessmentItem resolvedAssessmentItem;
......@@ -504,6 +508,29 @@ public class AssessmentItemEditorController extends BasicController {
return hottextItemBuilder;
}
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
if(entries == null || entries.isEmpty()) return;
String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
if(SelectionTarget.description.name().equalsIgnoreCase(type) || SelectionTarget.expert.name().equalsIgnoreCase(type)) {
activate(ureq, itemEditor);
} else if(SelectionTarget.description.name().equalsIgnoreCase(type) || SelectionTarget.score.name().equalsIgnoreCase(type)) {
activate(ureq, scoreEditor);
} else if(SelectionTarget.feedback.name().equalsIgnoreCase(type)) {
activate(ureq, feedbackEditor);
}
}
private void activate(UserRequest ureq, Controller ctrl) {
if(ctrl == null) return;
int index = tabbedPane.indexOfTab(ctrl.getInitialComponent());
if(index >= 0) {
tabbedPane.setSelectedPane(ureq, index);
}
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
if(tabbedPane == source) {
......
......@@ -20,6 +20,7 @@
package org.olat.ims.qti21.ui.editor;
import java.io.File;
import java.util.List;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
......@@ -29,10 +30,14 @@ import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.ims.qti21.ui.AssessmentTestDisplayController;
import org.olat.ims.qti21.ui.editor.events.AssessmentSectionEvent;
import org.olat.ims.qti21.ui.editor.events.SelectEvent.SelectionTarget;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
......@@ -42,7 +47,7 @@ import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentSectionEditorController extends BasicController {
public class AssessmentSectionEditorController extends BasicController implements Activateable2 {
private final TabbedPane tabbedPane;
private final VelocityContainer mainVC;
......@@ -95,6 +100,18 @@ public class AssessmentSectionEditorController extends BasicController {
//
}
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
if(entries == null || entries.isEmpty()) return;
String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
if(SelectionTarget.description.name().equalsIgnoreCase(type) || SelectionTarget.score.name().equalsIgnoreCase(type)) {
tabbedPane.setSelectedPane(ureq, tabbedPane.indexOfTab(optionsCtrl.getInitialComponent()));
} else if(SelectionTarget.expert.name().equalsIgnoreCase(type)) {
tabbedPane.setSelectedPane(ureq, tabbedPane.indexOfTab(expertOptionsCtrl.getInitialComponent()));
}
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
//
......
......@@ -59,6 +59,7 @@ import org.olat.core.gui.control.VetoableCloseController;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.MainLayoutBasicController;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.gui.control.generic.messages.MessageController;
import org.olat.core.gui.control.generic.messages.MessageUIFactory;
import org.olat.core.gui.control.generic.modal.DialogBoxController;
......@@ -69,12 +70,16 @@ import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
import org.olat.core.gui.control.generic.wizard.StepsRunContext;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.helpers.Settings;
import org.olat.core.id.context.BusinessControlFactory;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.util.Formatter;
import org.olat.core.util.Util;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult;
import org.olat.core.util.resource.OresHelper;
import org.olat.core.util.tree.TreeHelper;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.fileresource.FileResourceManager;
import org.olat.ims.qti21.AssessmentTestHelper;
......@@ -113,6 +118,9 @@ import org.olat.ims.qti21.ui.editor.events.AssessmentSectionEvent;
import org.olat.ims.qti21.ui.editor.events.AssessmentTestEvent;
import org.olat.ims.qti21.ui.editor.events.AssessmentTestPartEvent;
import org.olat.ims.qti21.ui.editor.events.DetachFromPoolEvent;
import org.olat.ims.qti21.ui.editor.events.SelectEvent;
import org.olat.ims.qti21.ui.editor.events.SelectEvent.SelectionTarget;
import org.olat.ims.qti21.ui.editor.overview.AssessmentTestOverviewConfigurationController;
import org.olat.imscp.xml.manifest.FileType;
import org.olat.imscp.xml.manifest.ResourceType;
import org.olat.modules.qpool.QuestionItemFull;
......@@ -131,6 +139,7 @@ import uk.ac.ed.ph.jqtiplus.node.test.AbstractPart;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
import uk.ac.ed.ph.jqtiplus.node.test.ControlObject;
import uk.ac.ed.ph.jqtiplus.node.test.SectionPart;
import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
......@@ -159,6 +168,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
newEssayLink, newUploadLink, newDrawingLink;
private Link importFromPoolLink, importFromTableLink, exportToPoolLink, exportToDocxLink;
private Link reloadInCacheLink, deleteLink, copyLink;
private Link configurationOverviewLink;
private final TooledStackedPanel toolbar;
private VelocityContainer mainVC;
......@@ -168,6 +178,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
private DialogBoxController confirmDeleteCtrl;
private StepsMainRunController importTableWizard;
private LayoutMain3ColsController columnLayoutCtr;
private AssessmentTestOverviewConfigurationController overviewConfigCtrl;
private File unzippedDirRoot;
private VFSContainer unzippedContRoot;
......@@ -350,6 +361,9 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
copyLink.setDomReplacementWrapperRequired(false);
changeItemTools.addComponent(copyLink);
configurationOverviewLink = LinkFactory.createToolLink("configuration.overview", translate("configuration.overview"), this, "o_icon_description");
configurationOverviewLink.setDomReplacementWrapperRequired(false);
// main layout
mainVC = createVelocityContainer("assessment_test_composer");
columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, mainVC, "at" + testEntry.getKey());
......@@ -411,6 +425,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
toolbar.addTool(exportItemTools, Align.left);
toolbar.addTool(addItemTools, Align.left);
toolbar.addTool(changeItemTools, Align.left);
toolbar.addTool(configurationOverviewLink, Align.right);
}
@Override
......@@ -474,6 +489,14 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
doDelete(ureq, (TreeNode)confirmDeleteCtrl.getUserObject());
}
cleanUp();
} else if(overviewConfigCtrl == source) {
if(event instanceof SelectEvent) {
SelectEvent se = (SelectEvent)event;
if(doSelect(ureq, se.getControlObject(), se.getTarget())) {
cleanUp();
}
}
} else if(cmc == source) {
cleanUp();
}
......@@ -481,9 +504,11 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
}
private void cleanUp() {
removeAsListenerAndDispose(overviewConfigCtrl);
removeAsListenerAndDispose(confirmDeleteCtrl);
removeAsListenerAndDispose(selectQItemCtrl);
removeAsListenerAndDispose(cmc);
overviewConfigCtrl = null;
confirmDeleteCtrl = null;
selectQItemCtrl = null;
cmc = null;
......@@ -549,7 +574,25 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
doCopy(ureq);
} else if(reloadInCacheLink == source) {
doForceReloadFiles(ureq);
} else if(configurationOverviewLink == source) {
doConfigurationOverview(ureq);
}
}
private boolean doSelect(UserRequest ureq, ControlObject<?> uobject, SelectionTarget target) {
TreeNode selectedNode = TreeHelper.findNodeByUserObject(uobject, menuTree.getTreeModel().getRootNode());
if(selectedNode != null) {
toolbar.popUpToController(this);
partEditorFactory(ureq, selectedNode);
if(currentEditorCtrl instanceof Activateable2) {
List<ContextEntry> entries = BusinessControlFactory.getInstance()
.createCEListFromString(OresHelper.createOLATResourceableType(target.name()));
((Activateable2)currentEditorCtrl).activate(ureq, entries, null);
}
return currentEditorCtrl != null;
}
return false;
}
private void doSelectQItem(UserRequest ureq) {
......@@ -1304,6 +1347,15 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
assessmentChanged(ureq);
}
private void doConfigurationOverview(UserRequest ureq) {
removeAsListenerAndDispose(overviewConfigCtrl);
overviewConfigCtrl = new AssessmentTestOverviewConfigurationController(ureq, getWindowControl(), toolbar,
testEntry, resolvedAssessmentTest);
listenTo(overviewConfigCtrl);
toolbar.pushController(translate("configuration.overview"), overviewConfigCtrl);
}
private void doConfirmDelete(UserRequest ureq) {
if(confirmDeleteCtrl != null) return;
......
......@@ -20,6 +20,7 @@
package org.olat.ims.qti21.ui.editor;
import java.io.File;
import java.util.List;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
......@@ -29,11 +30,15 @@ import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.ims.qti21.model.xml.AssessmentTestBuilder;
import org.olat.ims.qti21.ui.AssessmentTestDisplayController;
import org.olat.ims.qti21.ui.editor.events.AssessmentTestEvent;
import org.olat.ims.qti21.ui.editor.events.SelectEvent.SelectionTarget;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
......@@ -44,7 +49,7 @@ import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentTestEditorController extends BasicController {
public class AssessmentTestEditorController extends BasicController implements Activateable2 {
private final TabbedPane tabbedPane;
private final VelocityContainer mainVC;
......@@ -113,6 +118,29 @@ public class AssessmentTestEditorController extends BasicController {
}
}
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
if(entries == null || entries.isEmpty()) return;
String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
if(SelectionTarget.description.name().equalsIgnoreCase(type) || SelectionTarget.score.name().equalsIgnoreCase(type)) {
activate(ureq, optionsCtrl);
} else if(SelectionTarget.expert.name().equalsIgnoreCase(type) && testPartOptionsCtrl != null) {
activate(ureq, testPartOptionsCtrl);
} else if(SelectionTarget.feedback.name().equalsIgnoreCase(type) && testPartOptionsCtrl != null) {
activate(ureq, testPartOptionsCtrl);
}
}
private void activate(UserRequest ureq, Controller ctrl) {
if(ctrl == null) return;
int index = tabbedPane.indexOfTab(ctrl.getInitialComponent());
if(index >= 0) {
tabbedPane.setSelectedPane(ureq, index);
}
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
//
......
......@@ -15,6 +15,10 @@ add.match.column=Kolonne hinzuf\u00FCgen
add.match.row=Zeile hinzuf\u00FCgen
answers=Antworten
change.elements=Elemente \u00E4ndern
configuration.overview=\u00DCbersicht Testkonfiguration
configuration.option.yes=Ja
configuration.option.no=Nein
configuration.option.inherited=Vererbt
convert=Konvertieren
convert.alien=Konvertieren
convert.to=Umwandeln in\:
......@@ -139,7 +143,9 @@ form.imd.wrong.kprim=Falsch
form.kprim=Kprim
form.match=Match
form.metadata=Metadaten
form.metadata.creationDate=Erstellt
form.metadata.description=Beschreibung
form.metadata.initialAuthor=Erstellt durch
form.metadata.title=Titel
form.pool=Fragenpool
form.score=Punkte
......@@ -228,6 +234,16 @@ new.upload=Datei hochladen
preview=Vorschau
preview.solution=Vorschau L\u00F6sung
rights.owners=$org.olat.modules.qpool.ui\:rights.owners
table.header.attempts=L\u00F6sungsversuche
table.header.comment=Kommentar erlauben
table.header.feedback=Feedback
table.header.identifier=Frage ID
table.header.points=Punkte
table.header.review=R\u00FCckblick erlauben
table.header.skipping=\u00DCberspring erlauben
table.header.solution=L\u00F6sung anzeigen
table.header.title=Titel
table.header.type=Fragetyp
time.limit.max=Zeitbeschr\u00E4nkung
title.add=$org.olat.ims.qti.editor\:title.add
tools.change.copy=$org.olat.ims.qti.editor\:tools.change.copy
......
......@@ -15,6 +15,10 @@ add.match.column=Add column
add.match.row=Add row
answers=Answers
change.elements=Edition
configuration.overview=Test configuration overview
configuration.option.yes=Yes
configuration.option.no=No
configuration.option.inherited=Inherited
convert=Convert
convert.alien=Convert
convert.to=Convert to\:
......@@ -139,7 +143,9 @@ form.imd.wrong.kprim=False
form.kprim=Kprim
form.match=Match
form.metadata=Metadata
form.metadata.creationDate=Created
form.metadata.description=Description
form.metadata.initialAuthor=Creator
form.metadata.title=Title
form.pool=Question bank
form.score=Score
......@@ -228,6 +234,16 @@ new.upload=Upload file
preview=Preview
preview.solution=Preview solution
rights.owners=$org.olat.modules.qpool.ui\:rights.owners
table.header.attempts=Attempts
table.header.comment=Allow comment
table.header.identifier=Question ID
table.header.feedback=Feedback
table.header.points=Points
table.header.review=Allow review
table.header.skipping=Allow skipping
table.header.solution=Show solution
table.header.title=Title
table.header.type=Type
time.limit.max=Time limit
title.add=$org.olat.ims.qti.editor\:title.add
tools.change.copy=$org.olat.ims.qti.editor\:tools.change.copy
......
/**
* <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.ims.qti21.ui.editor.events;
import org.olat.core.gui.control.Event;
import uk.ac.ed.ph.jqtiplus.node.test.ControlObject;
/**
*
* Initial date: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class SelectEvent extends Event {
private static final long serialVersionUID = 1554430878603467523L;
public static final String SELECT = "select-control-object";
private final SelectionTarget target;
private final ControlObject<?> controlObject;
public SelectEvent(ControlObject<?> controlObject, SelectionTarget target) {
super(SELECT);
this.target = target;
this.controlObject = controlObject;
}
public SelectionTarget getTarget() {
return target;
}
public ControlObject<?> getControlObject() {
return controlObject;
}
public enum SelectionTarget {
description,
expert,
score,
feedback
}
}
/**
* <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.ims.qti21.ui.editor.overview;
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.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
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;
import org.olat.modules.assessment.ui.ScoreCellRenderer;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
/**
*
* Initial date: 16 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentSectionScoreCellRenderer implements FlexiCellRenderer {
private final ScoreCellRenderer scoreRenderer;
private final StaticFlexiCellRenderer actionRenderer;
public AssessmentSectionScoreCellRenderer(String action) {
scoreRenderer = new ScoreCellRenderer();
actionRenderer = new StaticFlexiCellRenderer(action, scoreRenderer);
}
@Override
public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
URLBuilder ubu, Translator translator) {
ControlObjectRow object = (ControlObjectRow)source.getFlexiTableElement().getTableDataModel().getObject(row);
if(object.getControlObject() instanceof AssessmentSection) {
scoreRenderer.render(renderer, target, cellValue, row, source, ubu, translator);
} else {
actionRenderer.render(renderer, target, cellValue, row, source, ubu, translator);
}
}
}
/**
* <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.ims.qti21.ui.editor.overview;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.DoubleAdder;
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.DateChooser;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
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.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
import org.olat.core.gui.components.stack.TooledStackedPanel;
import org.olat.core.gui.control.Controller;
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.render.URLBuilder;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.course.assessment.AssessmentHelper;
import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
import org.olat.ims.qti21.ui.assessment.components.QuestionTypeFlexiCellRenderer;
import org.olat.ims.qti21.ui.editor.AssessmentTestComposerController;
import org.olat.ims.qti21.ui.editor.events.SelectEvent;
import org.olat.ims.qti21.ui.editor.events.SelectEvent.SelectionTarget;
import org.olat.ims.qti21.ui.editor.overview.AssessmentTestOverviewDataModel.PartCols;
import org.olat.repository.RepositoryEntry;
import org.olat.user.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
import uk.ac.ed.ph.jqtiplus.node.test.SectionPart;
import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
import uk.ac.ed.ph.jqtiplus.node.test.TimeLimits;
import uk.ac.ed.ph.jqtiplus.provision.BadResourceException;
import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest;
/**
*
* Initial date: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentTestOverviewConfigurationController extends FormBasicController {
private FlexiTableElement tableEl;
private AssessmentTestOverviewDataModel tableModel;
private final TooledStackedPanel toolbar;
private final RepositoryEntry testEntry;
private final ResolvedAssessmentTest resolvedAssessmentTest;
@Autowired
private UserManager userManager;
public AssessmentTestOverviewConfigurationController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbar,
RepositoryEntry testEntry, ResolvedAssessmentTest resolvedAssessmentTest) {
super(ureq, wControl, "overview", Util.createPackageTranslator(AssessmentTestComposerController.class, ureq.getLocale()));
this.testEntry = testEntry;
this.resolvedAssessmentTest = resolvedAssessmentTest;
this.toolbar = toolbar;
initForm(ureq);
initialPanel.setCssClass("o_edit_mode");
loadModel();
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
initInfosForm(formLayout);
initTableForm(formLayout, ureq);
}
private void initInfosForm(FormItemContainer formLayout) {
FormLayoutContainer infosLayout = FormLayoutContainer.createDefaultFormLayout("test.infos", getTranslator());
formLayout.add("infos", infosLayout);
infosLayout.setRootForm(mainForm);
AssessmentTest assessmentTest = resolvedAssessmentTest.getRootNodeLookup().extractIfSuccessful();
String title = assessmentTest.getTitle();
TextElement titleEl = uifactory.addTextElement("title", "form.metadata.title", 255, title, infosLayout);
titleEl.setEnabled(false);
String initalAuthor = testEntry.getInitialAuthor() == null ? "-" : testEntry.getInitialAuthor();
if(testEntry.getInitialAuthor() != null) {
initalAuthor = userManager.getUserDisplayName(initalAuthor);
}
TextElement creatorEl = uifactory.addTextElement("initialAuthor", "form.metadata.initialAuthor", 255, StringHelper.escapeHtml(initalAuthor), infosLayout);
creatorEl.setEnabled(false);
DateChooser creationEl = uifactory.addDateChooser("form.metadata.creationDate", testEntry.getCreationDate(), infosLayout);
creationEl.setEnabled(false);
Double maxScore = QtiNodesExtractor.extractMaxScore(assessmentTest);
String maxScoreStr = AssessmentHelper.getRoundedScore(maxScore);
TextElement maxScoreEl = uifactory.addTextElement("max.score", "max.score", 255, maxScoreStr, infosLayout);
maxScoreEl.setEnabled(false);
Double cutValue = QtiNodesExtractor.extractCutValue(assessmentTest);
String cutValueStr = AssessmentHelper.getRoundedScore(cutValue);
TextElement cutValueEl = uifactory.addTextElement("cut.value", "cut.value", 255, cutValueStr, infosLayout);
cutValueEl.setEnabled(false);
TimeLimits timeLimits = assessmentTest.getTimeLimits();
long maxInSeconds = -1;
String timeMaxHour = "";
String timeMaxMinute = "";
if(timeLimits != null && timeLimits.getMaximum() != null && timeLimits.getMaximum().longValue() > 0) {
maxInSeconds = timeLimits.getMaximum().longValue();
timeMaxHour = Long.toString(maxInSeconds / 3600);
timeMaxMinute = Long.toString((maxInSeconds % 3600) / 60);
}
if(StringHelper.containsNonWhitespace(timeMaxHour) || StringHelper.containsNonWhitespace(timeMaxMinute)) {
String page = velocity_root + "/max_time_limit.html";
FormLayoutContainer maxTimeCont = FormLayoutContainer.createCustomFormLayout("time.limit.cont", getTranslator(), page);
infosLayout.add(maxTimeCont);
maxTimeCont.setLabel("time.limit.max", null);
timeMaxHour = timeMaxHour.equals("0") ? "" : timeMaxHour;
TextElement maxTimeHourEl = uifactory.addTextElement("time.limit.hour", "time.limit.max", 4, timeMaxHour, maxTimeCont);
maxTimeHourEl.setDomReplacementWrapperRequired(false);
maxTimeHourEl.setDisplaySize(4);
maxTimeHourEl.setEnabled(false);
TextElement maxTimeMinuteEl = uifactory.addTextElement("time.limit.minute", "time.limit.max", 4, timeMaxMinute, maxTimeCont);
maxTimeMinuteEl.setDomReplacementWrapperRequired(false);
maxTimeMinuteEl.setDisplaySize(4);
maxTimeMinuteEl.setEnabled(false);
}
}
private void initTableForm(FormItemContainer formLayout, UserRequest ureq) {
FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
DefaultFlexiColumnModel titleCol = new DefaultFlexiColumnModel(PartCols.title,
SelectionTarget.description.name(), new HierarchicalPartCellRenderer());
titleCol.setAlwaysVisible(true);
tableColumnModel.addFlexiColumnModel(titleCol);
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PartCols.maxScore,
new AssessmentSectionScoreCellRenderer(SelectionTarget.score.name())));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PartCols.attempts,
SelectionTarget.expert.name(), new MaxAttemptsCellRenderer(getTranslator())));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PartCols.skipping,
new TestAndSectionCellRenderer(SelectionTarget.expert.name(), new OptionCellRenderer(getTranslator()))));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PartCols.comment,
new TestAndSectionCellRenderer(SelectionTarget.expert.name(), new OptionCellRenderer(getTranslator()))));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PartCols.review,
new TestAndSectionCellRenderer(SelectionTarget.expert.name(), new OptionCellRenderer(getTranslator()))));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PartCols.solution,
new TestAndSectionCellRenderer(SelectionTarget.expert.name(), new OptionCellRenderer(getTranslator()))));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, PartCols.type, new QuestionTypeFlexiCellRenderer(getTranslator())));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, PartCols.identifier));
tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, PartCols.feedback, SelectionTarget.feedback.name()));
tableModel = new AssessmentTestOverviewDataModel(tableColumnModel);
tableEl = uifactory.addTableElement(getWindowControl(), "overview", tableModel, 32000, false, getTranslator(), formLayout);
tableEl.setElementCssClass("o_sel_qti_configuration_overview");
tableEl.setExportEnabled(true);
tableEl.setAndLoadPersistedPreferences(ureq, "assessment-test-config-overview");
}
@Override
protected void doDispose() {
toolbar.setCssClass("");
}
private void loadModel() {
List<ControlObjectRow> rows = new ArrayList<>();
AssessmentTest test = resolvedAssessmentTest.getTestLookup().getRootNodeHolder().getRootNode();
rows.add(ControlObjectRow.valueOf(test));
List<TestPart> parts = test.getTestParts();
if(parts.size() == 1) {
List<AssessmentSection> sections = parts.get(0).getAssessmentSections();
for(AssessmentSection section:sections) {
loadModel(section, rows);
}
} else {
for(int i=0; i<parts.size(); i++) {
loadModel(parts.get(i), (i+1), rows);
}
}
tableModel.setObjects(rows);
tableEl.reset(true, true, true);
}
private void loadModel(TestPart part, int pos, List<ControlObjectRow> rows) {
rows.add(ControlObjectRow.valueOf(part, pos));
List<AssessmentSection> sections = part.getAssessmentSections();
for(AssessmentSection section:sections) {
loadModel(section, rows);
}
}
private Double loadModel(AssessmentSection section, List<ControlObjectRow> rows) {
ControlObjectRow sectionRow = ControlObjectRow.valueOf(section);
rows.add(sectionRow);
boolean someMaxScore = false;
DoubleAdder atomicMaxScore = new DoubleAdder();
for(SectionPart part: section.getSectionParts()) {
Double maxScore = null;
if(part instanceof AssessmentItemRef) {
maxScore = loadModel((AssessmentItemRef)part, rows);
} else if(part instanceof AssessmentSection) {
maxScore = loadModel((AssessmentSection) part, rows);
}
if(maxScore != null) {
someMaxScore = true;
atomicMaxScore.add(maxScore.doubleValue());
}
}
if(someMaxScore) {
sectionRow.setMaxScore(Double.valueOf(atomicMaxScore.sum()));
}
return sectionRow.getMaxScore();
}
private Double loadModel(AssessmentItemRef itemRef, List<ControlObjectRow> rows) {
Double maxScore = null;
ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef);
if(resolvedAssessmentItem == null || resolvedAssessmentItem.getItemLookup() == null
|| resolvedAssessmentItem.getItemLookup().getRootNodeHolder() == null) {
rows.add(ControlObjectRow.errorOf(itemRef));
} else {
BadResourceException ex = resolvedAssessmentItem.getItemLookup().getBadResourceException();
if(ex != null) {
rows.add(ControlObjectRow.errorOf(itemRef));
} else {
AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
ControlObjectRow row = ControlObjectRow.valueOf(itemRef, assessmentItem);
maxScore = row.getMaxScore();
rows.add(row);
}
}
return maxScore;
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(tableEl == source) {
if(event instanceof SelectionEvent) {
SelectionEvent se = (SelectionEvent)event;
if(StringHelper.containsNonWhitespace(se.getCommand())) {
SelectionTarget target = SelectionTarget.valueOf(se.getCommand());
ControlObjectRow row = tableModel.getObject(se.getIndex());
fireEvent(ureq, new SelectEvent(row.getControlObject(), target));
}
}
}
super.formInnerEvent(ureq, source, event);
}
@Override
protected void formOK(UserRequest ureq) {
//
}
private static class TestAndSectionCellRenderer implements FlexiCellRenderer {
private final FlexiCellRenderer delegate;
private final StaticFlexiCellRenderer actionRenderer;
public TestAndSectionCellRenderer(String action, FlexiCellRenderer delegate) {
this.delegate = delegate;
actionRenderer = new StaticFlexiCellRenderer(action, delegate);
}
@Override
public void render(Renderer renderer, StringOutput target, Object cellValue, int row,
FlexiTableComponent source, URLBuilder ubu, Translator translator) {
ControlObjectRow object = (ControlObjectRow)source.getFlexiTableElement().getTableDataModel().getObject(row);
if(object.getControlObject() instanceof AssessmentItemRef) {
delegate.render(renderer, target, cellValue, row, source, ubu, translator);
} else {
actionRenderer.render(renderer, target, cellValue, row, source, ubu, translator);
}
}
}
}
/**
* <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.ims.qti21.ui.editor.overview;
import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
/**
*
* Initial date: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentTestOverviewDataModel extends DefaultFlexiTableDataModel<ControlObjectRow> {
public AssessmentTestOverviewDataModel(FlexiTableColumnModel columnModel) {
super(columnModel);
}
@Override
public Object getValueAt(int row, int col) {
ControlObjectRow partRow = getObject(row);
switch(PartCols.values()[col]) {
case title: return partRow;
case maxScore: return partRow.getMaxScore();
case attempts: return partRow.getAttemptOption();
case skipping: return partRow.getSkipping();
case comment: return partRow.getComment();
case review: return partRow.getReview();
case solution: return partRow.getSolution();
case type: return partRow.getType();
case identifier: return partRow.getIdentifier();
case feedback: return partRow.getFeedbacks();
default: return "ERROR";
}
}
@Override
public AssessmentTestOverviewDataModel createCopyWithEmptyList() {
return new AssessmentTestOverviewDataModel(getTableColumnModel());
}
public enum PartCols implements FlexiSortableColumnDef {
title("table.header.title"),
maxScore("table.header.points"),
attempts("table.header.attempts"),
skipping("table.header.skipping"),
comment("table.header.comment"),
review("table.header.review"),
solution("table.header.solution"),
type("table.header.type"),
identifier("table.header.identifier"),
feedback("table.header.feedback");
private final String i18nKey;
private PartCols(String i18nKey) {
this.i18nKey = i18nKey;
}
@Override
public String i18nHeaderKey() {
return i18nKey;
}
@Override
public boolean sortable() {
return false;
}
@Override
public String sortKey() {
return name();
}
}
}
/**
* <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.ims.qti21.ui.editor.overview;
import java.util.List;
import org.olat.ims.qti21.model.QTI21QuestionType;
import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
import uk.ac.ed.ph.jqtiplus.node.test.AbstractPart;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
import uk.ac.ed.ph.jqtiplus.node.test.ControlObject;
import uk.ac.ed.ph.jqtiplus.node.test.ItemSessionControl;
import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
/**
*
* Initial date: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class ControlObjectRow {
private final String title;
private final String iconCssClass;
private final ControlObject<?> part;
private Double maxScore;
private Boolean feedbacks;
private QTI21QuestionType type;
private OptionEnum review;
private OptionEnum comment;
private OptionEnum skipping;
private OptionEnum solution;
private MaxAttemptOption attemptOption;
public ControlObjectRow(String title, ControlObject<?> part, String iconCssClass) {
this.part = part;
this.title = title;
this.iconCssClass = iconCssClass;
}
public static ControlObjectRow valueOf(AssessmentTest assessmentTest) {
ControlObjectRow row = new ControlObjectRow(assessmentTest.getTitle(), assessmentTest, "o_qtiassessment_icon");
row.maxScore = QtiNodesExtractor.extractMaxScore(assessmentTest);
boolean hasFeedbacks = !assessmentTest.getTestFeedbacks().isEmpty();
row.feedbacks = Boolean.valueOf(hasFeedbacks);
List<TestPart> parts = assessmentTest.getTestParts();
if(parts.size() == 1) {
TestPart part = parts.get(0);
configuration(row, part);
}
return row;
}
public static ControlObjectRow valueOf(TestPart part, int pos) {
ControlObjectRow row = new ControlObjectRow(pos + ". Test part", part, "o_icon-lg o_qtiassessment_icon");
configuration(row, part);
return row;
}
public static ControlObjectRow valueOf(AssessmentSection section) {
ControlObjectRow row = new ControlObjectRow(section.getTitle(), section, "o_mi_qtisection");
configuration(row, section);
return row;
}
public static ControlObjectRow errorOf(AssessmentItemRef itemRef) {
return new ControlObjectRow("ERROR", itemRef, "o_icon_error");
}
public static ControlObjectRow valueOf(AssessmentItemRef itemRef, AssessmentItem assessmentItem) {
String itemCssClass;
QTI21QuestionType type = QTI21QuestionType.getType(assessmentItem);
if(type != null) {
itemCssClass = type.getCssClass();
} else {
itemCssClass = "o_mi_qtiunkown";
}
ControlObjectRow row = new ControlObjectRow(assessmentItem.getTitle(), itemRef, itemCssClass);
row.maxScore = QtiNodesExtractor.extractMaxScore(assessmentItem);
row.type = type;
boolean hasFeedbacks = !assessmentItem.getModalFeedbacks().isEmpty();
row.feedbacks = Boolean.valueOf(hasFeedbacks);
configuration(row, itemRef);
return row;
}
private static void configuration(ControlObjectRow row, AbstractPart part) {
attempts(row, part);
skipping(row, part);
comment(row, part);
review(row, part);
solution(row, part);
}
private static void attempts(ControlObjectRow row, AbstractPart part) {
Integer maxAttempts = null;
ItemSessionControl itemSessionControl = part.getItemSessionControl();
if(itemSessionControl != null) {
maxAttempts = itemSessionControl.getMaxAttempts();
}
if(maxAttempts != null) {
OptionEnum option = (maxAttempts.intValue() == 0 ? OptionEnum.no : OptionEnum.yes);
row.attemptOption = MaxAttemptOption.valueOf(option, maxAttempts);
} else {
OptionEnum option = (part instanceof TestPart) ? OptionEnum.no : OptionEnum.inherited;
row.attemptOption = MaxAttemptOption.valueOf(option, Integer.valueOf(1));
}
}
private static void skipping(ControlObjectRow row, AbstractPart part) {
ItemSessionControl itemSessionControl = part.getItemSessionControl();
if(itemSessionControl != null && itemSessionControl.getAllowSkipping() != null) {
row.skipping = itemSessionControl.getAllowSkipping().booleanValue() ? OptionEnum.yes : OptionEnum.no;
} else {
row.skipping = (part instanceof TestPart) ? OptionEnum.yes : OptionEnum.inherited;
}
}
private static void comment(ControlObjectRow row, AbstractPart part) {
ItemSessionControl itemSessionControl = part.getItemSessionControl();
if(itemSessionControl != null && itemSessionControl.getAllowComment() != null) {
row.comment = itemSessionControl.getAllowComment().booleanValue() ? OptionEnum.yes : OptionEnum.no;
} else {
row.comment = (part instanceof TestPart) ? OptionEnum.yes : OptionEnum.inherited;
}
}
private static void review(ControlObjectRow row, AbstractPart part) {
ItemSessionControl itemSessionControl = part.getItemSessionControl();
if(itemSessionControl != null && itemSessionControl.getAllowReview() != null) {
row.review = itemSessionControl.getAllowReview().booleanValue() ? OptionEnum.yes : OptionEnum.no;
} else {
row.review = (part instanceof TestPart) ? OptionEnum.no : OptionEnum.inherited;
}
}
private static void solution(ControlObjectRow row, AbstractPart part) {
ItemSessionControl itemSessionControl = part.getItemSessionControl();
if(itemSessionControl != null && itemSessionControl.getShowSolution() != null) {
row.solution = itemSessionControl.getShowSolution().booleanValue() ? OptionEnum.yes : OptionEnum.no;
} else {
row.solution = (part instanceof TestPart) ? OptionEnum.no : OptionEnum.inherited;
}
}
public String getTitle() {
return title;
}
public String getIdentifier() {
return part.getIdentifier().toString();
}
public ControlObject<?> getControlObject() {
return part;
}
public String getIconCssClass() {
return iconCssClass;
}
public Double getMaxScore() {
return maxScore;
}
public void setMaxScore(Double maxScore) {
this.maxScore = maxScore;
}
public QTI21QuestionType getType() {
return type;
}
public Boolean getFeedbacks() {
return feedbacks;
}
public OptionEnum getSkipping() {
return skipping;
}
public OptionEnum getComment() {
return comment;
}
public OptionEnum getReview() {
return review;
}
public OptionEnum getSolution() {
return solution;
}
public MaxAttemptOption getAttemptOption() {
return attemptOption;
}
public int getDepth() {
int depth = 0;
for(ControlObject<?> parent=part.getParent(); parent != null; parent = parent.getParent()) {
depth++;
}
return depth;
}
}
/**
* <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.ims.qti21.ui.editor.overview;
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: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class HierarchicalPartCellRenderer implements FlexiCellRenderer {
@Override
public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
URLBuilder ubu, Translator translator) {
if(cellValue instanceof ControlObjectRow) {
ControlObjectRow controlObject = (ControlObjectRow)cellValue;
int depth = controlObject.getDepth();
target.append("<div class='o_table_flexi_l").append(depth).append("'><span><i class='o_icon ").append(controlObject.getIconCssClass()).append("'> </i> ")
.append(controlObject.getTitle()).append("</span></div>");
} else if(cellValue instanceof String) {
target.append((String)cellValue);
}
}
}
/**
* <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.ims.qti21.ui.editor.overview;
/**
*
* Initial date: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class MaxAttemptOption {
private final OptionEnum option;
private final Integer maxAttempts;
private MaxAttemptOption(OptionEnum option, Integer maxAttempts) {
this.option = option;
this.maxAttempts = maxAttempts;
}
public static MaxAttemptOption valueOf(OptionEnum option, Integer maxAttempts) {
return new MaxAttemptOption(option, maxAttempts);
}
public OptionEnum getOption() {
return option;
}
public Integer getMaxAttempts() {
return maxAttempts;
}
}
/**
* <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.ims.qti21.ui.editor.overview;
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: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class MaxAttemptsCellRenderer extends OptionCellRenderer {
public MaxAttemptsCellRenderer(Translator translator) {
super(translator);
}
@Override
public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
URLBuilder ubu, Translator trans) {
if(cellValue instanceof MaxAttemptOption) {
MaxAttemptOption attempts = (MaxAttemptOption)cellValue;
OptionEnum option = attempts.getOption();
if(option == OptionEnum.yes) {
target.append(attempts.getMaxAttempts());
} else {
super.render(renderer, target, option, row, source, ubu, trans);
}
}
}
}
/**
* <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.ims.qti21.ui.editor.overview;
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: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class OptionCellRenderer implements FlexiCellRenderer {
private final Translator translator;
public OptionCellRenderer(Translator translator) {
this.translator = translator;
}
@Override
public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
URLBuilder ubu, Translator trans) {
if(cellValue instanceof OptionEnum) {
OptionEnum option = (OptionEnum)cellValue;
target.append(translator.translate("configuration.option.".concat(option.name())));
}
}
}
/**
* <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.ims.qti21.ui.editor.overview;
/**
*
* Initial date: 15 janv. 2019<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public enum OptionEnum {
yes,
no,
inherited
}
<div class="form-inline">$r.render("time.limit.hour") $r.translate("hour.short") $r.render("time.limit.minute") $r.translate("minute.short")</div>
$r.render("infos")
$r.render("overview")
\ No newline at end of file
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