diff --git a/src/main/java/org/olat/ims/qti21/QTI21Service.java b/src/main/java/org/olat/ims/qti21/QTI21Service.java index 05d33efa148bd21b4419fbd9d3525423290c7261..b7de4fd41a358b4fe8ca04d2b9f999db3fd1e6f3 100644 --- a/src/main/java/org/olat/ims/qti21/QTI21Service.java +++ b/src/main/java/org/olat/ims/qti21/QTI21Service.java @@ -35,6 +35,7 @@ import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; +import uk.ac.ed.ph.jqtiplus.node.AssessmentObject; import uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult; import uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder; import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; @@ -85,6 +86,8 @@ public interface QTI21Service { public boolean updateAssesmentObject(File resourceFile, ResolvedAssessmentObject<?> resolvedAssessmentObject); + public boolean persistAssessmentObject(File resourceFile, AssessmentObject assessmentObject); + public UserTestSession createTestSession(Identity identity, AssessmentEntry assessmentEntry, RepositoryEntry entry, String subIdent, RepositoryEntry testEntry, diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java index 8bf959fddfafe0610a8b2a3c1a9529569e6ace32..b1f28fe33f573111ff0e93aa1700cfdd56b3768c 100644 --- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java +++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java @@ -208,7 +208,8 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa throw new OLATRuntimeException("Unexpected branch " + assessmentObjectType, null); } - ResolvedAssessmentObject<?> cachedResult = assessmentTestsAndItemsCache.putIfAbsent(resourceDirectory, result); + File resourceFile = new File(assessmentObjectSystemId); + ResolvedAssessmentObject<?> cachedResult = assessmentTestsAndItemsCache.putIfAbsent(resourceFile, result); if(cachedResult != null) { result = cachedResult; } @@ -229,6 +230,11 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa return false; } + return persistAssessmentObject(resourceFile, assessmentObject); + } + + @Override + public boolean persistAssessmentObject(File resourceFile, AssessmentObject assessmentObject) { try(FileOutputStream out = new FileOutputStream(resourceFile)) { qtiSerializer().serializeJqtiObject(assessmentObject, out); //TODO qti diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentBuilderHelper.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentBuilderHelper.java index a385c2adef2b8862b0ebbf39363ceb89ef23ce70..7384c0fabfac275d2aecd665a973ea3f385de327 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentBuilderHelper.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentBuilderHelper.java @@ -19,29 +19,13 @@ */ package org.olat.ims.qti21.model.xml; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.List; +import org.xml.sax.SAXParseException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.stream.StreamResult; - -import org.olat.core.gui.render.StringOutput; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.xml.sax.SAXException; - -import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; -import uk.ac.ed.ph.jqtiplus.exception.QtiModelException; -import uk.ac.ed.ph.jqtiplus.node.LoadingContext; -import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; -import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; -import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic; -import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; +import uk.ac.ed.ph.jqtiplus.provision.BadResourceException; +import uk.ac.ed.ph.jqtiplus.reading.QtiModelBuildingError; +import uk.ac.ed.ph.jqtiplus.reading.QtiXmlInterpretationException; +import uk.ac.ed.ph.jqtiplus.reading.QtiXmlInterpretationException.InterpretationFailureReason; +import uk.ac.ed.ph.jqtiplus.xmlutils.XmlParseResult; /** * @@ -50,74 +34,54 @@ import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; * */ public class AssessmentBuilderHelper { - - private static final OLog log = Tracing.createLoggerFor(AssessmentBuilderHelper.class); - - private final QtiSerializer qtiSerializer; - - public AssessmentBuilderHelper() { - JqtiExtensionManager jqtiExtensionManager = new JqtiExtensionManager(); - qtiSerializer = new QtiSerializer(jqtiExtensionManager); - } - - public AssessmentBuilderHelper(QtiSerializer qtiSerializer) { - this.qtiSerializer = qtiSerializer; - } - - public String toString(List<FlowStatic> statics) { - StringOutput sb = new StringOutput(); - if(statics != null && statics.size() > 0) { - for(FlowStatic flowStatic:statics) { - qtiSerializer.serializeJqtiObject(flowStatic, new StreamResult(sb)); - } - } - return sb.toString(); - } - - public List<Block> parseHtml(String html) { - //tinymce bad habits - if(html.startsWith("<p> ")) { - html = html.replace("<p> ", "<p>"); - } - Document document = htmlToDOM("<html>" + html + "</html>"); - LoadingContext context = new HTMLLoadingContext(); - - ItemBody helper = new ItemBody(null); - helper.load(document.getDocumentElement(), context); - return helper.getBlocks(); - } - - /** - * This method use the standard XML parser. It's not really - * good but QTIWorks want DOM Level 2 elements. - * - * @param content - * @return - */ - private Document htmlToDOM(String content) { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(new ByteArrayInputStream(content.getBytes())); - return doc; - } catch (ParserConfigurationException | SAXException | IOException e) { - log.error("", e); - return null; - } - } - - private static final class HTMLLoadingContext implements LoadingContext { - @Override - public JqtiExtensionManager getJqtiExtensionManager() { - return null; - } - - @Override - public void modelBuildingError(QtiModelException exception, Node badNode) { - // - } + public static void extractMessage(BadResourceException e, StringBuilder out) { + + if(e instanceof QtiXmlInterpretationException) { + QtiXmlInterpretationException qe = (QtiXmlInterpretationException)e; + if(qe.getQtiModelBuildingErrors() != null) { + for(QtiModelBuildingError error :qe.getQtiModelBuildingErrors()) { + String localName = error.getElementLocalName(); + String msg = error.getException().getMessage(); + int lineNumber = error.getElementLocation().getLineNumber(); + out.append(lineNumber + " :: " + localName + " :: " + msg + "\n"); + } + } + + if(qe.getInterpretationFailureReason() != null) { + InterpretationFailureReason reason = qe.getInterpretationFailureReason(); + out.append("Failure: " + reason + "\n"); + } + + if(qe.getXmlParseResult() != null) { + XmlParseResult result = qe.getXmlParseResult(); + if(result.getWarnings() != null) { + for(SAXParseException saxex : result.getWarnings()) { + int lineNumber = saxex.getLineNumber(); + int columnNumber = saxex.getColumnNumber(); + String msg = saxex.getMessage(); + out.append("Error: " + lineNumber + ":" + columnNumber + " :: " + msg + "\n"); + } + } + + if(result.getErrors() != null) { + for(SAXParseException saxex : result.getErrors()) { + int lineNumber = saxex.getLineNumber(); + int columnNumber = saxex.getColumnNumber(); + String msg = saxex.getMessage(); + out.append("Error: " + lineNumber + ":" + columnNumber + " :: " + msg + "\n"); + } + } + + if(result.getFatalErrors() != null) { + for(SAXParseException saxex : result.getFatalErrors()) { + int lineNumber = saxex.getLineNumber(); + int columnNumber = saxex.getColumnNumber(); + String msg = saxex.getMessage(); + out.append("Fatal: " + lineNumber + ":" + columnNumber + " :: " + msg + "\n"); + } + } + } + } } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..0022d6d93aa5fd1742da3923bea8fd677f42bfeb --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java @@ -0,0 +1,127 @@ +/** + * <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.model.xml; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.stream.StreamResult; + +import org.cyberneko.html.parsers.SAXParser; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; +import uk.ac.ed.ph.jqtiplus.exception.QtiModelException; +import uk.ac.ed.ph.jqtiplus.node.AbstractNode; +import uk.ac.ed.ph.jqtiplus.node.LoadingContext; +import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic; +import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; +import uk.ac.ed.ph.jqtiplus.xmlutils.SimpleDomBuilderHandler; + +/** + * Do the ugly job to convert the Tiny MCE HTML code to the object model + * of QTI Works + * + * Initial date: 10.12.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AssessmentHtmlBuilder { + + private static final OLog log = Tracing.createLoggerFor(AssessmentHtmlBuilder.class); + + private final QtiSerializer qtiSerializer; + + public AssessmentHtmlBuilder() { + JqtiExtensionManager jqtiExtensionManager = new JqtiExtensionManager(); + qtiSerializer = new QtiSerializer(jqtiExtensionManager); + } + + public AssessmentHtmlBuilder(QtiSerializer qtiSerializer) { + this.qtiSerializer = qtiSerializer; + } + + public String toString(List<FlowStatic> statics) { + StringOutput sb = new StringOutput(); + if(statics != null && statics.size() > 0) { + for(FlowStatic flowStatic:statics) { + qtiSerializer.serializeJqtiObject(flowStatic, new StreamResult(sb)); + } + } + return sb.toString(); + } + + public void appendHtml(AbstractNode parent, String htmlFragment) { + //tinymce bad habits + if(htmlFragment.startsWith("<p> ")) { + htmlFragment = htmlFragment.replace("<p> ", "<p>"); + } + //wrap around <html> to have a root element + Document document = filter("<html>" + htmlFragment + "</html>"); + parent.getNodeGroups().load(document.getDocumentElement(), new HTMLLoadingContext()); + } + + private Document filter(String content) { + try { + SAXParser parser = new SAXParser(); + parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower"); + parser.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment", true); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.newDocument(); + SimpleDomBuilderHandler contentHandler = new SimpleDomBuilderHandler(document); + parser.setContentHandler(contentHandler); + parser.parse(new InputSource(new ByteArrayInputStream(content.getBytes()))); + return document; + } catch (SAXException e) { + log.error("", e); + return null; + } catch (IOException e) { + log.error("", e); + return null; + } catch (Exception e) { + log.error("", e); + return null; + } + } + + private static final class HTMLLoadingContext implements LoadingContext { + + @Override + public JqtiExtensionManager getJqtiExtensionManager() { + return null; + } + + @Override + public void modelBuildingError(QtiModelException exception, Node badNode) { + // + } + } +} diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java index c206f27fd8028e174b9bd45957fe5a1abd245ce7..47e2fd8c832179ed6dca16e3330318122d2a83d2 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java @@ -50,6 +50,7 @@ public abstract class AssessmentItemBuilder { protected final AssessmentItem assessmentItem; protected final QtiSerializer qtiSerializer; + protected final AssessmentHtmlBuilder htmlHelper; protected final AssessmentBuilderHelper builderHelper; private ScoreBuilder minScoreBuilder; @@ -62,10 +63,15 @@ public abstract class AssessmentItemBuilder { public AssessmentItemBuilder(AssessmentItem assessmentItem, QtiSerializer qtiSerializer) { this.assessmentItem = assessmentItem; this.qtiSerializer = qtiSerializer; - builderHelper = new AssessmentBuilderHelper(qtiSerializer); + builderHelper = new AssessmentBuilderHelper(); + htmlHelper = new AssessmentHtmlBuilder(qtiSerializer); extract(); } + public AssessmentItem getAssessmentItem() { + return assessmentItem; + } + protected void extract() { extractMinScore(); extractMaxScore(); @@ -164,6 +170,10 @@ public abstract class AssessmentItemBuilder { public AssessmentBuilderHelper getHelper() { return builderHelper; } + + public AssessmentHtmlBuilder getHtmlHelper() { + return htmlHelper; + } public final void build() { List<OutcomeDeclaration> outcomeDeclarations = assessmentItem.getOutcomeDeclarations(); diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java index 8d3113436dd23b8204a5c88bdab40181a8196975..28d89805ddc3bd86858bccca3f3a94c0ed95c18f 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java @@ -39,8 +39,6 @@ import uk.ac.ed.ph.jqtiplus.group.item.response.processing.ResponseProcessingGro import uk.ac.ed.ph.jqtiplus.group.outcome.declaration.OutcomeDeclarationGroup; import uk.ac.ed.ph.jqtiplus.node.QtiNode; import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; -import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; -import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic; import uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun; import uk.ac.ed.ph.jqtiplus.node.content.xhtml.text.P; import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue; @@ -363,12 +361,14 @@ public class AssessmentItemFactory { modalFeedback.setVisibilityMode(VisibilityMode.parseVisibilityMode("show")); modalFeedback.getAttributes().getStringAttribute(ModalFeedback.ATTR_TITLE_NAME).setValue(title); - List<Block> blocks = new AssessmentBuilderHelper().parseHtml(text); + new AssessmentHtmlBuilder().appendHtml(modalFeedback, text); + + /*List<Block> blocks = new AssessmentHTMLBuilder().parseHtml(text); for(Block block:blocks) { if(block instanceof FlowStatic) { modalFeedback.getFlowStatics().add((FlowStatic)block); } - } + }*/ return modalFeedback; } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestPackage.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestPackage.java deleted file mode 100644 index 6f9b7cfedc4074318c379b0d11b4c1b75abfefdc..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestPackage.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * <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.model.xml; - -/** - * - * Initial date: 04.06.2015<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class AssessmentTestPackage { - -} diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ManifestPackage.java b/src/main/java/org/olat/ims/qti21/model/xml/ManifestPackage.java index 1d7578708c6b02176e222f7fca08c3760038a847..9105243de03c459eec6db5c4347b10b07b13e4dc 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/ManifestPackage.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/ManifestPackage.java @@ -19,12 +19,17 @@ */ package org.olat.ims.qti21.model.xml; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.util.UUID; import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; @@ -132,4 +137,31 @@ public class ManifestPackage { log.error("", e); } } + + public static void write(ManifestType manifest, File manifestFile) { + try(OutputStream out = new FileOutputStream(manifestFile)) { + JAXBContext context = JAXBContext.newInstance("org.olat.imscp.xml.manifest"); + Marshaller marshaller = context.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/qtiv2p1_imscpv1p2_v1p0.xsd"); + + marshaller.marshal(objectFactory.createManifest(manifest), out); + } catch (JAXBException | IOException e) { + log.error("", e); + } + } + + public static ManifestType read(File manifestFile) { + try { + JAXBContext context = JAXBContext.newInstance("org.olat.imscp.xml.manifest"); + Unmarshaller marshaller = context.createUnmarshaller(); + //marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + //marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/qtiv2p1_imscpv1p2_v1p0.xsd"); + + return (ManifestType)((JAXBElement<?>)marshaller.unmarshal(manifestFile)).getValue(); + } catch (JAXBException e) { + log.error("", e); + return null; + } + } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java index 7c5eb63f61203eb1b93b6c303428a49bec066b0b..8a5189d86972ac3ba7057fa84d9484a2a6271422 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java @@ -55,7 +55,7 @@ public class ModalFeedbackBuilder { this.assessmentItem = assessmentItem; this.modalFeedback = modalFeedback; if(modalFeedback != null) { - text = new AssessmentBuilderHelper().toString(modalFeedback.getFlowStatics()); + text = new AssessmentHtmlBuilder().toString(modalFeedback.getFlowStatics()); StringAttribute titleAttr = modalFeedback.getAttributes().getStringAttribute(ModalFeedback.ATTR_TITLE_NAME); title = titleAttr == null ? null : titleAttr.getComputedValue(); identifier = modalFeedback.getIdentifier(); diff --git a/src/main/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilder.java index 57381148a5a06607c095ed6b2b6a699e29c9ecad..6fa954af0670dc4a2ef79826427af492c0bc2bd1 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilder.java @@ -103,9 +103,12 @@ public class SingleChoiceAssessmentItemBuilder extends ChoiceAssessmentItemBuild List<Block> blocks = assessmentItem.getItemBody().getBlocks(); blocks.clear(); + /* //add question - List<Block> questionBlocks = getHelper().parseHtml(question); + List<Block> questionBlocks = getHtmlHelper().parseHtml(question); blocks.addAll(questionBlocks); + */ + getHtmlHelper().appendHtml(assessmentItem.getItemBody(), question); //add interaction ChoiceInteraction singleChoiceInteraction = AssessmentItemFactory diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/EditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemBuilderController.java similarity index 93% rename from src/main/java/org/olat/ims/qti21/ui/editor/EditorController.java rename to src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemBuilderController.java index 0f761f189ecff1cc130a6207dc98d9c37126d2ca..c9e32921016ad575d905730928fe17b6f422bf45 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/EditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemBuilderController.java @@ -22,7 +22,7 @@ package org.olat.ims.qti21.ui.editor; import org.olat.core.gui.control.Controller; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; -public interface EditorController extends Controller { +public interface AssessmentItemBuilderController extends Controller { public void updateFromBuilder(); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java index 1104d95de6ea174d29e02565cccb92913ce42488..d675c9895bf8b2051142e0e40d3f52c17a7db24a 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java @@ -36,6 +36,7 @@ import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.SingleChoiceAssessmentItemBuilder; import org.olat.ims.qti21.ui.AssessmentItemDisplayController; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentService; import org.olat.repository.RepositoryEntry; @@ -55,12 +56,13 @@ import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; */ public class AssessmentItemEditorController extends BasicController { + private final AssessmentItemRef itemRef; private final ResolvedAssessmentItem resolvedAssessmentItem; private final TabbedPane tabbedPane; private final VelocityContainer mainVC; - private EditorController itemEditor, scoreEditor, feedbackEditor; + private AssessmentItemBuilderController itemEditor, scoreEditor, feedbackEditor; private AssessmentItemDisplayController displayCtrl; @Autowired @@ -71,6 +73,7 @@ public class AssessmentItemEditorController extends BasicController { public AssessmentItemEditorController(UserRequest ureq, WindowControl wControl, RepositoryEntry testEntry, ResolvedAssessmentItem resolvedAssessmentItem, AssessmentItemRef itemRef, File unzippedDirectory) { super(ureq, wControl); + this.itemRef = itemRef; this.resolvedAssessmentItem = resolvedAssessmentItem; mainVC = createVelocityContainer("assessment_item_editor"); @@ -89,6 +92,10 @@ public class AssessmentItemEditorController extends BasicController { putInitialPanel(mainVC); } + public String getTitle() { + return resolvedAssessmentItem.getRootNodeLookup().getRootNodeHolder().getRootNode().getTitle(); + } + @Override protected void doDispose() { // @@ -151,15 +158,19 @@ public class AssessmentItemEditorController extends BasicController { @Override protected void event(UserRequest ureq, Controller source, Event event) { if(event instanceof AssessmentItemEvent) { - if(event == AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED) { - if(source instanceof EditorController) { - EditorController editorCtrl = (EditorController)source; - AssessmentItemBuilder builder = editorCtrl.getBuilder(); - if(builder != null) { - builder.build(); + if(event instanceof AssessmentItemEvent) { + AssessmentItemEvent aie = (AssessmentItemEvent)event; + if(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED.equals(aie.getCommand())) { + if(source instanceof AssessmentItemBuilderController) { + AssessmentItemBuilderController editorCtrl = (AssessmentItemBuilderController)source; + AssessmentItemBuilder builder = editorCtrl.getBuilder(); + if(builder != null) { + builder.build(); + } } + doSaveAssessmentItem(); + fireEvent(ureq, new AssessmentItemEvent(aie.getCommand(), aie.getAssessmentItem(), itemRef)); } - doSaveAssessmentItem(); } } super.event(ureq, source, event); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java index 9ed6831e2e1a76801b57b201a3c9eae55cb57315..97a75ffb1dfaed0553c7fd590b249946c6844b3a 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java @@ -26,6 +26,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; +import org.olat.ims.qti21.ui.editor.events.AssessmentSectionEvent; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection; @@ -62,6 +63,10 @@ public class AssessmentSectionEditorController extends ItemSessionControlControl formLayout.add(buttonsCont); uifactory.addFormSubmitButton("save", "save", buttonsCont); } + + public String getTitle() { + return titleEl.getValue(); + } @Override protected void doDispose() { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java index 464539964f351e3429a7a93d90862a539a5cfd5d..326d8a5fe7b2ca38184a0cbada4e8ea1b3c59596 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java @@ -21,10 +21,13 @@ package org.olat.ims.qti21.ui.editor; import java.io.File; import java.net.URI; +import java.net.URISyntaxException; +import java.util.UUID; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.panel.Panel; @@ -43,17 +46,26 @@ import org.olat.core.gui.control.controller.MainLayoutBasicController; import org.olat.core.util.Util; import org.olat.fileresource.FileResourceManager; import org.olat.ims.qti21.QTI21Service; +import org.olat.ims.qti21.model.xml.AssessmentItemFactory; +import org.olat.ims.qti21.model.xml.ManifestPackage; import org.olat.ims.qti21.ui.AssessmentTestDisplayController; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; +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.imscp.xml.manifest.ManifestType; import org.olat.repository.RepositoryEntry; import org.olat.repository.ui.RepositoryEntryRuntimeController.ToolbarAware; 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.TestPart; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest; +import uk.ac.ed.ph.jqtiplus.types.Identifier; /** * Assessment test editor and composer. @@ -68,6 +80,8 @@ public class AssessmentTestComposerController extends MainLayoutBasicController private final MenuTree menuTree; private final Link saveLink; + private final Dropdown addItemTools; + private final Link newSectionLink, newSingleChoiceLink; private final TooledStackedPanel toolbar; private final VelocityContainer mainVC; @@ -76,7 +90,8 @@ public class AssessmentTestComposerController extends MainLayoutBasicController private final File unzippedDirRoot; private final RepositoryEntry testEntry; - private final ResolvedAssessmentTest resolvedAssessmentTest; + private ManifestType manifest; + private ResolvedAssessmentTest resolvedAssessmentTest; private final boolean restrictedEdit; @@ -107,10 +122,25 @@ public class AssessmentTestComposerController extends MainLayoutBasicController resolvedAssessmentTest = qtiService.loadAndResolveAssessmentObject(unzippedDirRoot); menuTree.setTreeModel(new AssessmentTestEditorAndComposerTreeModel(resolvedAssessmentTest)); + manifest = ManifestPackage.read(new File(unzippedDirRoot, "imsmanifest.xml")); + //default buttons saveLink = LinkFactory.createToolLink("serialize", translate("serialize"), this, "o_icon_save"); saveLink.setDomReplacementWrapperRequired(false); + //add elements + addItemTools = new Dropdown("editTools", "new.elements", false, getTranslator()); + addItemTools.setIconCSS("o_icon o_icon-fw o_icon_add"); + toolbar.addTool(addItemTools, Align.left); + + newSectionLink = LinkFactory.createToolLink("new.section", translate("new.section"), this, "o_mi_qtisection"); + newSectionLink.setDomReplacementWrapperRequired(false); + addItemTools.addComponent(newSectionLink); + + newSingleChoiceLink = LinkFactory.createToolLink("new.sc", translate("new.sc"), this, "o_mi_qtisc"); + newSingleChoiceLink.setDomReplacementWrapperRequired(false); + addItemTools.addComponent(newSingleChoiceLink); + // main layout mainVC = createVelocityContainer("assessment_test_composer"); columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, mainVC, "at" + testEntry.getKey()); @@ -119,7 +149,11 @@ public class AssessmentTestComposerController extends MainLayoutBasicController putInitialPanel(columnLayoutCtr.getInitialComponent()); // init - partEditorFactory(ureq, menuTree.getTreeModel().getRootNode()); + TreeNode selectedNode = doOpenFirstItem(); + if(selectedNode == null) { + selectedNode = menuTree.getTreeModel().getRootNode(); + } + partEditorFactory(ureq, selectedNode); } @Override @@ -129,6 +163,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController @Override public void initToolbar() { + toolbar.addTool(addItemTools, Align.left); toolbar.addTool(saveLink, Align.left); } @@ -144,11 +179,21 @@ public class AssessmentTestComposerController extends MainLayoutBasicController if(ate == AssessmentTestEvent.ASSESSMENT_TEST_CHANGED_EVENT) { doSaveAssessmentTest(); } + } else if(event instanceof AssessmentTestPartEvent) { + AssessmentTestPartEvent atpe = (AssessmentTestPartEvent)event; + if(atpe == AssessmentTestPartEvent.ASSESSMENT_TEST_PART_CHANGED_EVENT) { + doSaveAssessmentTest(); + } } else if(event instanceof AssessmentSectionEvent) { AssessmentSectionEvent ase = (AssessmentSectionEvent)event; if(AssessmentSectionEvent.ASSESSMENT_SECTION_CHANGED.equals(ase.getCommand())) { doSaveAssessmentTest(); - doUpdate(ase.getSection()); + doUpdate(ase.getSection().getIdentifier(), ase.getSection().getTitle()); + } + } else if(event instanceof AssessmentItemEvent) { + AssessmentItemEvent aie = (AssessmentItemEvent)event; + if(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED.equals(aie.getCommand())) { + doUpdate(aie.getAssessmentItemRef().getIdentifier(), aie.getAssessmentItem().getTitle()); } } super.event(ureq, source, event); @@ -168,7 +213,90 @@ public class AssessmentTestComposerController extends MainLayoutBasicController } } else if(saveLink == source) { doSaveAssessmentTest(); + } else if(newSectionLink == source) { + + } else if(newSingleChoiceLink == source) { + doNewSingleChoice(ureq, menuTree.getSelectedNode()); + } + } + + private TreeNode doOpenFirstItem() { + TreeNode node = menuTree.getTreeModel().getRootNode(); + if(node.getChildCount() > 0) { + return doOpenFirstItem((TreeNode)node.getChildAt(0)); + } + return node; + } + + private TreeNode doOpenFirstItem(TreeNode node) { + if(node.getUserObject() instanceof AssessmentItemRef) { + menuTree.setSelectedNode(node); + menuTree.open(node); + return node; + } + if(node.getChildCount() > 0) { + return doOpenFirstItem((TreeNode)node.getChildAt(0)); } + return null; + } + + private void doNewSection(UserRequest ureq) { + + } + + /** + * The method create a simple single choice, save the assessment item + * and append it to the test, update the manifest file. + * + * @param ureq + * @param selectedNode + */ + private void doNewSingleChoice(UserRequest ureq, TreeNode selectedNode) { + try { + TreeNode sectionNode = getNearestSection(selectedNode); + AssessmentSection section = (AssessmentSection)sectionNode.getUserObject(); + + AssessmentItemRef itemRef = new AssessmentItemRef(section); + String itemId = "sc" + UUID.randomUUID(); + itemRef.setIdentifier(Identifier.parseString(itemId)); + File itemFile = new File(unzippedDirRoot, itemId + ".xml"); + itemRef.setHref(new URI(itemFile.getName())); + section.getSectionParts().add(itemRef); + + AssessmentItem assessmentItem = AssessmentItemFactory.createSingleChoice(); + qtiService.persistAssessmentObject(itemFile, assessmentItem); + + URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId(); + File testFile = new File(testUri); + qtiService.updateAssesmentObject(testFile, resolvedAssessmentTest); + + ManifestPackage.appendAssessmentItem(itemFile.getName(), manifest); + ManifestPackage.write(manifest, new File(unzippedDirRoot, "imsmanifest.xml")); + + resolvedAssessmentTest = qtiService.loadAndResolveAssessmentObject(unzippedDirRoot); + menuTree.setTreeModel(new AssessmentTestEditorAndComposerTreeModel(resolvedAssessmentTest)); + + TreeNode newItemNode = menuTree.getTreeModel().getNodeById(itemId); + menuTree.setSelectedNode(newItemNode); + menuTree.open(newItemNode); + + partEditorFactory(ureq, newItemNode); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + private TreeNode getNearestSection(TreeNode node) { + if(node.getUserObject() instanceof AssessmentSection) { + return node; + } + if(node.getUserObject() instanceof AssessmentItemRef) { + return (TreeNode)node.getParent(); + } + if(node.getUserObject() instanceof TestPart) { + return (TreeNode)node.getChildAt(0); + } + return null; } private void doSaveAssessmentTest() { @@ -177,13 +305,13 @@ public class AssessmentTestComposerController extends MainLayoutBasicController qtiService.updateAssesmentObject(testFile, resolvedAssessmentTest); } - private void doUpdate(AssessmentSection section) { + private void doUpdate(Identifier identifier, String newTitle) { TreeNode node = menuTree.getTreeModel() - .getNodeById(section.getIdentifier().toString()); + .getNodeById(identifier.toString()); if(node instanceof GenericTreeNode) { - GenericTreeNode sectionNode = (GenericTreeNode)node; - if(!section.getTitle().equals(sectionNode.getTitle())) { - sectionNode.setTitle(section.getTitle()); + GenericTreeNode itemNode = (GenericTreeNode)node; + if(!newTitle.equals(itemNode.getTitle())) { + itemNode.setTitle(newTitle); menuTree.setDirty(true); } } @@ -212,7 +340,13 @@ public class AssessmentTestComposerController extends MainLayoutBasicController } else if(uobject instanceof AssessmentItemRef) { AssessmentItemRef itemRef = (AssessmentItemRef)uobject; ResolvedAssessmentItem item = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef); - currentEditorCtrl = new AssessmentItemEditorController(ureq, getWindowControl(), testEntry, item, itemRef, unzippedDirRoot); + if(item.getItemLookup().getBadResourceException() != null) { + currentEditorCtrl = new BadResourceController(ureq, getWindowControl(), + item.getItemLookup().getBadResourceException(), unzippedDirRoot, itemRef.getHref()); + } else { + currentEditorCtrl = new AssessmentItemEditorController(ureq, getWindowControl(), testEntry, + item, itemRef, unzippedDirRoot); + } } if(currentEditorCtrl != null) { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorAndComposerTreeModel.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorAndComposerTreeModel.java index 26ffff0d3d6e0ad4bf3cfc70bfe3ef0e31456ab5..89ac6a33b81df94532414f41652c9fa3ae7f9e1a 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorAndComposerTreeModel.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorAndComposerTreeModel.java @@ -32,6 +32,7 @@ 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.provision.BadResourceException; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest; @@ -65,6 +66,10 @@ public class AssessmentTestEditorAndComposerTreeModel extends GenericTreeModel i } } + public TreeNode addItem(AssessmentItemRef itemRef, TreeNode section) { + return buildRecursively(itemRef, section); + } + private void buildRecursively(TestPart part, int pos, TreeNode parentNode) { GenericTreeNode partNode = new GenericTreeNode(part.getIdentifier().toString()); partNode.setTitle(pos + ". Test part"); @@ -94,17 +99,26 @@ public class AssessmentTestEditorAndComposerTreeModel extends GenericTreeModel i } } - - private void buildRecursively(AssessmentItemRef itemRef, TreeNode parentNode) { - GenericTreeNode sectionNode = new GenericTreeNode(itemRef.getIdentifier().toString()); + private TreeNode buildRecursively(AssessmentItemRef itemRef, TreeNode parentNode) { + GenericTreeNode itemNode = new GenericTreeNode(itemRef.getIdentifier().toString()); ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef); - AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode(); - sectionNode.setTitle(assessmentItem.getTitle()); - sectionNode.setIconCssClass("o_icon o_mi_qtisc"); - sectionNode.setUserObject(itemRef); - parentNode.addChild(sectionNode); + BadResourceException ex = resolvedAssessmentItem.getItemLookup().getBadResourceException(); + if(ex != null) { + itemNode.setTitle("ERROR"); + itemNode.setIconCssClass("o_icon o_icon_error"); + itemNode.setUserObject(itemRef); + parentNode.addChild(itemNode); + } else { + AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode(); + itemNode.setTitle(assessmentItem.getTitle()); + itemNode.setIconCssClass("o_icon o_mi_qtisc"); + itemNode.setUserObject(itemRef); + parentNode.addChild(itemNode); + } + + return itemNode; } @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorController.java index a370c0ece4416364f9a0fef9da0ca36a5eaef94d..ef5c165f4d46fb646e552edef31eafe69f90362c 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEditorController.java @@ -29,6 +29,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.ims.qti21.ui.AssessmentTestDisplayController; +import org.olat.ims.qti21.ui.editor.events.AssessmentTestEvent; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest; @@ -70,6 +71,9 @@ public class AssessmentTestEditorController extends FormBasicController { // } + public String getTitle() { + return titleEl.getValue(); + } @Override protected boolean validateFormLogic(UserRequest ureq) { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestPartEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestPartEditorController.java index 9756ae9aec0cda9bdb0ae61e1bdad7c8bd033fc5..521f20f0ffadb6ef44bcdf572548182a697b0bb5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestPartEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestPartEditorController.java @@ -24,6 +24,7 @@ import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; +import org.olat.ims.qti21.ui.editor.events.AssessmentTestEvent; import uk.ac.ed.ph.jqtiplus.node.test.TestPart; diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/BadResourceController.java b/src/main/java/org/olat/ims/qti21/ui/editor/BadResourceController.java new file mode 100644 index 0000000000000000000000000000000000000000..a2a402aa85d72a35abed502d35c80cb4b9b6ad03 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/BadResourceController.java @@ -0,0 +1,78 @@ +/** + * <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; + +import java.io.File; +import java.net.URI; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +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.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.ims.qti21.model.xml.AssessmentBuilderHelper; + +import uk.ac.ed.ph.jqtiplus.provision.BadResourceException; + +/** + * + * Initial date: 10.12.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BadResourceController extends FormBasicController { + + private final URI resourceURI; + private final File unzippedDirectory; + private final BadResourceException resourceException; + + public BadResourceController(UserRequest ureq, WindowControl wControl, + BadResourceException resourceException, File unzippedDirectory, URI resourceURI) { + super(ureq, wControl, "bad_resource"); + this.resourceException = resourceException; + this.resourceURI = resourceURI; + this.unzippedDirectory = unzippedDirectory; + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + + StringBuilder out = new StringBuilder(); + AssessmentBuilderHelper.extractMessage(resourceException, out); + layoutCont.contextPut("message", out.toString()); + layoutCont.contextPut("directory", unzippedDirectory.toString()); + layoutCont.contextPut("uri", resourceURI.toASCIIString()); + } + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java index 5673318c3af825627b6c3499914d90a5c7d069fb..41b213737a9e8feac9c16200c454560843e74e99 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java @@ -33,6 +33,7 @@ import org.olat.core.util.filter.FilterFactory; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder; import org.olat.ims.qti21.model.xml.SingleChoiceAssessmentItemBuilder; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; /** * @@ -40,7 +41,7 @@ import org.olat.ims.qti21.model.xml.SingleChoiceAssessmentItemBuilder; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class FeedbackEditorController extends FormBasicController implements EditorController { +public class FeedbackEditorController extends FormBasicController implements AssessmentItemBuilderController { private TextElement feedbackCorrectTitleEl, feedbackIncorrectTitleEl; private RichTextElement feedbackCorrectTextEl, feedbackIncorrectTextEl; @@ -115,7 +116,7 @@ public class FeedbackEditorController extends FormBasicController implements Edi incorrectBuilder.setText(incorrectText); } - fireEvent(ureq, AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED); + fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem())); } @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceEditorController.java index c35cdadc940afc84f83ed0a129fc0948cc190ecf..605da726b83a8f732717427909ac1a2b86c33721 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceEditorController.java @@ -41,9 +41,8 @@ import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.AssessmentItemFactory; import org.olat.ims.qti21.model.xml.SingleChoiceAssessmentItemBuilder; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; -import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; -import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic; import uk.ac.ed.ph.jqtiplus.node.content.xhtml.text.P; import uk.ac.ed.ph.jqtiplus.node.item.interaction.ChoiceInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleChoice; @@ -55,7 +54,7 @@ import uk.ac.ed.ph.jqtiplus.types.Identifier; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class SingleChoiceEditorController extends FormBasicController implements EditorController { +public class SingleChoiceEditorController extends FormBasicController implements AssessmentItemBuilderController { private TextElement titleEl; private RichTextElement textEl; @@ -141,7 +140,7 @@ public class SingleChoiceEditorController extends FormBasicController implements } private void wrapAnswer(UserRequest ureq, SimpleChoice choice) { - String choiceContent = itemBuilder.getHelper().toString(choice.getFlowStatics()); + String choiceContent = itemBuilder.getHtmlHelper().toString(choice.getFlowStatics()); String choiceId = "answer" + count++; RichTextElement choiceEl = uifactory.addRichTextElementForStringData(choiceId, "form.imd.answer", choiceContent, 8, -1, true, null, null, answersCont, ureq.getUserSession(), getWindowControl()); @@ -213,19 +212,22 @@ public class SingleChoiceEditorController extends FormBasicController implements choiceWrapper.setCorrect(correctAnswerIdentifier.equals(choiceWrapper.getIdentifier())); //text String answer = choiceWrapper.getAnswer().getValue(); - List<Block> blocks = itemBuilder.getHelper().parseHtml(answer); + itemBuilder.getHtmlHelper().appendHtml(choice, answer); + + + /*List<Block> blocks = itemBuilder.getHtmlHelper().parseHtml(answer); choice.getFlowStatics().clear(); for(Block block:blocks) { if(block instanceof FlowStatic) { choice.getFlowStatics().add((FlowStatic)block); } - } + }*/ choiceList.add(choice); } itemBuilder.setSimpleChoices(choiceList); - fireEvent(ureq, AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED); + fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem())); } @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceScoreController.java b/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceScoreController.java index 9c47e8a1582dc7000758476f8e34fdb4891f558e..59030be5b4f4cf3c85631dedbbcdb57cfe57bee5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceScoreController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/SingleChoiceScoreController.java @@ -29,6 +29,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.ScoreBuilder; import org.olat.ims.qti21.model.xml.SingleChoiceAssessmentItemBuilder; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; /** * @@ -36,7 +37,7 @@ import org.olat.ims.qti21.model.xml.SingleChoiceAssessmentItemBuilder; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class SingleChoiceScoreController extends FormBasicController implements EditorController { +public class SingleChoiceScoreController extends FormBasicController implements AssessmentItemBuilderController { private TextElement minScoreEl; private TextElement maxScoreEl; @@ -81,6 +82,8 @@ public class SingleChoiceScoreController extends FormBasicController implements Double maxScore = Double.parseDouble(maxScoreValue); itemBuilder.setMaxScore(maxScore); itemBuilder.setMinScore(new Double(0d)); + + fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem())); } @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java index 9184c7a241e0905cb1d9d5b523ab80a18dd223a4..7cae5dd8c4a8d4a61a75331a2b60d8d92c78e291 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java @@ -32,7 +32,7 @@ import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class UnkownItemEditorController extends FormBasicController implements EditorController { +public class UnkownItemEditorController extends FormBasicController implements AssessmentItemBuilderController { public UnkownItemEditorController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_content/bad_resource.html b/src/main/java/org/olat/ims/qti21/ui/editor/_content/bad_resource.html new file mode 100644 index 0000000000000000000000000000000000000000..fd8683f69585f8aa0c3081e22df1a9761cba5262 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_content/bad_resource.html @@ -0,0 +1,5 @@ +<div class="alert alert-danger"> + <p>Directory: $directory</p> + <p>File: $uri</p> + <p>$message</p> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties index f38be912ca9aa039e8a94ee58c28d87bc7117c4d..701301da5b97a44e8a220eb88a0874d8aa526730 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties @@ -11,4 +11,7 @@ form.imd.incorrect.title=Incorrect title form.imd.correct.text=Correct feedback form.imd.incorrect.text=Incorrect feedback min.score=Min. score -max.score=Max. score \ No newline at end of file +max.score=Max. score +new.elements=New elements +new.sc=Single choice +new.section=Section \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemPackage.java b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java similarity index 51% rename from src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemPackage.java rename to src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java index 4c648b2b4bf7e97a9f6712cee3adc1607a16166e..deb26732646c0543245633ea7dff78ad729d33f2 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemPackage.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java @@ -17,23 +17,44 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.ims.qti21.model.xml; +package org.olat.ims.qti21.ui.editor.events; -import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import org.olat.core.gui.control.Event; + +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef; /** * - * Initial date: 04.06.2015<br> + * Initial date: 03.07.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class AssessmentItemPackage { +public class AssessmentItemEvent extends Event { - public ResolvedAssessmentItem createSingleChoice() { - - ResolvedAssessmentItem item = new ResolvedAssessmentItem(null, null); - return item; - + private static final long serialVersionUID = -1768118856227595311L; + + public static final String ASSESSMENT_ITEM_CHANGED = "assessment-item-changed"; + + private AssessmentItem item; + private AssessmentItemRef itemRef; + + public AssessmentItemEvent(String cmd, AssessmentItem item) { + super(cmd); + this.item = item; + } + + public AssessmentItemEvent(String cmd, AssessmentItem item, AssessmentItemRef itemRef) { + super(cmd); + this.item = item; + this.itemRef = itemRef; } + public AssessmentItem getAssessmentItem() { + return item; + } + + public AssessmentItemRef getAssessmentItemRef() { + return itemRef; + } } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEvent.java b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentSectionEvent.java similarity index 97% rename from src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEvent.java rename to src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentSectionEvent.java index 3c1096da2c75acacca5913a29fc6dfd0e2bf6fd1..9bce2c778fb1a1909942d28c9246d74149caf994 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEvent.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentSectionEvent.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.ims.qti21.ui.editor; +package org.olat.ims.qti21.ui.editor.events; import org.olat.core.gui.control.Event; diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEvent.java b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentTestEvent.java similarity index 96% rename from src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEvent.java rename to src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentTestEvent.java index 5efe507cbd40a89df5c847b97d11c51092d75410..f249b27173b0c2fd2f88be9cc7b7415ac8f56fca 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestEvent.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentTestEvent.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.ims.qti21.ui.editor; +package org.olat.ims.qti21.ui.editor.events; import org.olat.core.gui.control.Event; diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEvent.java b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentTestPartEvent.java similarity index 72% rename from src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEvent.java rename to src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentTestPartEvent.java index 1999143c62900a7cb6439c4b94effa2afd06a8e9..4c59cc579cd98ac2263ba15544fba2ffa8c032b9 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEvent.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentTestPartEvent.java @@ -17,23 +17,22 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.ims.qti21.ui.editor; +package org.olat.ims.qti21.ui.editor.events; import org.olat.core.gui.control.Event; /** * - * Initial date: 03.07.2015<br> + * Initial date: 10.12.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class AssessmentItemEvent extends Event { - - private static final long serialVersionUID = -1768118856227595311L; - - public static final AssessmentItemEvent ASSESSMENT_ITEM_CHANGED = new AssessmentItemEvent("changed"); +public class AssessmentTestPartEvent extends Event { - public AssessmentItemEvent(String cmd) { + private static final long serialVersionUID = 2930881002425927366L; + public static final AssessmentTestPartEvent ASSESSMENT_TEST_PART_CHANGED_EVENT = new AssessmentTestPartEvent("changed"); + + public AssessmentTestPartEvent(String cmd) { super(cmd); } diff --git a/src/test/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilderTest.java b/src/test/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e69c2fd85e945e062173bc258991f2a664a98eee --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilderTest.java @@ -0,0 +1,70 @@ +/** + * <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.model.xml; + +import java.util.List; + +import javax.xml.transform.stream.StreamResult; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; + +import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; +import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; +import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; + +/** + * Test the conversion from TinyMCE HTML code to the QTI Works object + * model. + * + * + * Initial date: 10.12.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AssessmentHtmlBuilderTest { + + private static final OLog log = Tracing.createLoggerFor(AssessmentHtmlBuilderTest.class); + + @Test + public void filter() { + String content = "<html><p>Test \u00EA<strong><span><img = src='img.jpg'></span></strong></p><p>Test 2</p></html>"; + + AssessmentItem item = new AssessmentItem(); + ItemBody helper = new ItemBody(item); + new AssessmentHtmlBuilder().appendHtml(helper, content); + + List<Block> paragraphs = helper.getBlocks(); + Assert.assertNotNull(paragraphs); + Assert.assertEquals(2, paragraphs.size()); + + // The serializer can throw some exceptions if it doens't like the model + // we want to serialize. + StringOutput sb = new StringOutput(); + QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); + qtiSerializer.serializeJqtiObject(helper, new StreamResult(sb)); + log.info(sb.toString()); + } +} diff --git a/src/test/java/org/olat/ims/qti21/model/xml/AssessmentTestPackageTest.java b/src/test/java/org/olat/ims/qti21/model/xml/AssessmentTestPackageTest.java index 6d7d353552382e71d5ead7891bb746498ba9796f..734e5c0890919276424b73d60d0628f22f6c3bac 100644 --- a/src/test/java/org/olat/ims/qti21/model/xml/AssessmentTestPackageTest.java +++ b/src/test/java/org/olat/ims/qti21/model/xml/AssessmentTestPackageTest.java @@ -32,7 +32,6 @@ import org.junit.Test; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; -import org.xml.sax.SAXParseException; import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.node.content.variable.RubricBlock; @@ -55,16 +54,12 @@ import uk.ac.ed.ph.jqtiplus.node.test.outcome.processing.SetOutcomeValue; import uk.ac.ed.ph.jqtiplus.notification.Notification; import uk.ac.ed.ph.jqtiplus.provision.BadResourceException; import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; -import uk.ac.ed.ph.jqtiplus.reading.QtiModelBuildingError; -import uk.ac.ed.ph.jqtiplus.reading.QtiXmlInterpretationException; -import uk.ac.ed.ph.jqtiplus.reading.QtiXmlInterpretationException.InterpretationFailureReason; import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; import uk.ac.ed.ph.jqtiplus.types.Identifier; import uk.ac.ed.ph.jqtiplus.validation.TestValidationResult; import uk.ac.ed.ph.jqtiplus.value.BaseType; import uk.ac.ed.ph.jqtiplus.value.Cardinality; -import uk.ac.ed.ph.jqtiplus.xmlutils.XmlParseResult; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; /** @@ -198,53 +193,10 @@ public class AssessmentTestPackageTest { } BadResourceException e = test.getResolvedAssessmentTest().getTestLookup().getBadResourceException(); - if(e instanceof QtiXmlInterpretationException) { - QtiXmlInterpretationException qe = (QtiXmlInterpretationException)e; - if(qe.getQtiModelBuildingErrors() != null) { - for(QtiModelBuildingError error :qe.getQtiModelBuildingErrors()) { - String localName = error.getElementLocalName(); - String msg = error.getException().getMessage(); - int lineNumber = error.getElementLocation().getLineNumber(); - System.out.println(lineNumber + " :: " + localName + " :: " + msg); - } - } - - if(qe.getInterpretationFailureReason() != null) { - InterpretationFailureReason reason = qe.getInterpretationFailureReason(); - System.out.println("Failure: " + reason); - } - - if(qe.getXmlParseResult() != null) { - XmlParseResult result = qe.getXmlParseResult(); - if(result.getWarnings() != null) { - for(SAXParseException saxex : result.getWarnings()) { - int lineNumber = saxex.getLineNumber(); - int columnNumber = saxex.getColumnNumber(); - String msg = saxex.getMessage(); - System.out.println("Error: " + lineNumber + ":" + columnNumber + " :: " + msg); - } - } - - if(result.getErrors() != null) { - for(SAXParseException saxex : result.getErrors()) { - int lineNumber = saxex.getLineNumber(); - int columnNumber = saxex.getColumnNumber(); - String msg = saxex.getMessage(); - System.out.println("Error: " + lineNumber + ":" + columnNumber + " :: " + msg); - } - } - - if(result.getFatalErrors() != null) { - for(SAXParseException saxex : result.getFatalErrors()) { - int lineNumber = saxex.getLineNumber(); - int columnNumber = saxex.getColumnNumber(); - String msg = saxex.getMessage(); - System.out.println("Fatal: " + lineNumber + ":" + columnNumber + " :: " + msg); - } - } - } - } - + StringBuilder out = new StringBuilder(); + AssessmentBuilderHelper.extractMessage(e, out); + log.info(out.toString()); + Assert.assertTrue(test.getModelValidationErrors().isEmpty()); } } \ No newline at end of file diff --git a/src/test/java/org/olat/ims/qti21/model/xml/ConvertHTMLTestTest.java b/src/test/java/org/olat/ims/qti21/model/xml/ConvertHTMLTestTest.java deleted file mode 100644 index 15138d0b51c7543e7756ba905f5e28eb4a8a2f6b..0000000000000000000000000000000000000000 --- a/src/test/java/org/olat/ims/qti21/model/xml/ConvertHTMLTestTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * <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.model.xml; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.cyberneko.html.parsers.DOMParser; -import org.jcodec.common.Assert; -import org.junit.Test; -import org.olat.core.util.filter.FilterFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; -import uk.ac.ed.ph.jqtiplus.exception.QtiModelException; -import uk.ac.ed.ph.jqtiplus.node.LoadingContext; -import uk.ac.ed.ph.jqtiplus.node.QtiNode; -import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; -import uk.ac.ed.ph.jqtiplus.node.content.xhtml.text.P; - -/** - * - * Initial date: 07.12.2015<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class ConvertHTMLTestTest { - - @Test - public void convert() { - String content = "<html><p>Test</p><p>Test 2</p></html>"; - Document partialDocument = getDoc(content); - Element rootElement = partialDocument.getDocumentElement(); - - - - MyLoadingContext context = new MyLoadingContext(); - - Element paragraphEl = (Element)rootElement.getFirstChild(); - String tagName = paragraphEl.getTagName(); - String localName = paragraphEl.getLocalName(); - - ItemBody itemBody = new ItemBody(null); - itemBody.load(rootElement, context); - - Assert.assertNotNull(localName); - Assert.assertEquals(2, itemBody.getBlocks().size()); - - - - } - - private Document getDoc(String content) { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(new ByteArrayInputStream(content.getBytes())); - return doc; - } catch (ParserConfigurationException | SAXException | IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - - private Document getDocument(String content) { - try { - DOMParser parser = new DOMParser(); - parser.setFeature("http://xml.org/sax/features/validation", false); - - parser.setFeature( "http://cyberneko.org/html/features/override-namespaces", true); - parser.setFeature ( "http://xml.org/sax/features/namespaces", true ); - parser.setProperty("http://cyberneko.org/html/properties/names/elems", "upper" ); // has no effect, cannot override xerces configuration - parser.setProperty( "http://cyberneko.org/html/properties/names/attrs", "upper" ); // has no effect, cannot override xerces configuration - parser.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment",true); - parser.parse(new InputSource(new StringReader(content))); - return parser.getDocument(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - - private List<P> getText(QtiNode choice, String htmlContent) { - String text = FilterFactory.getHtmlTagsFilter().filter(htmlContent); - P firstChoiceText = AssessmentItemFactory.getParagraph(choice, text); - List<P> blocks = new ArrayList<>(); - blocks.add(firstChoiceText); - return blocks; - } - - private static final class MyLoadingContext implements LoadingContext { - - @Override - public JqtiExtensionManager getJqtiExtensionManager() { - // - return null; - } - - @Override - public void modelBuildingError(QtiModelException exception, Node badNode) { - // - } - - } - -} diff --git a/src/test/java/org/olat/ims/qti21/model/xml/ManifestPackageTest.java b/src/test/java/org/olat/ims/qti21/model/xml/ManifestPackageTest.java index 60493fe43fddc97a23aaa180dea4b49198e4530d..fc846744221ff75e2df067d67373a4d77f51d028 100644 --- a/src/test/java/org/olat/ims/qti21/model/xml/ManifestPackageTest.java +++ b/src/test/java/org/olat/ims/qti21/model/xml/ManifestPackageTest.java @@ -55,8 +55,8 @@ public class ManifestPackageTest { tmpDir.mkdirs(); } - - FileOutputStream out = new FileOutputStream(new File(tmpDir, "imsmanifest.xml")); + File manifestFile = new File(tmpDir, "imsmanifest.xml"); + FileOutputStream out = new FileOutputStream(manifestFile); ManifestPackage.write(manifestType, out); out.flush(); out.close(); @@ -67,5 +67,9 @@ public class ManifestPackageTest { List<ContentPackageResource> tests = summary.getTestResources(); Assert.assertEquals(1, items.size()); Assert.assertEquals(1, tests.size()); + + ManifestType reloadManifestType = ManifestPackage.read(manifestFile); + Assert.assertNotNull(reloadManifestType); + } }